Browse Source

Merge branch 'feature/1219_opt' of http://git.dayaedu.com/yonge/cooleshow into test

zouxuan 5 months ago
parent
commit
af68ef5602
98 changed files with 3893 additions and 910 deletions
  1. 3 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/AdminFeignService.java
  2. 5 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java
  3. 62 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/AlbumCategoryController.java
  4. 19 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/CourseHomeworkController.java
  5. 81 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/DiscountCardRecordController.java
  6. 10 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  7. 30 45
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/UserTenantAlbumRecordController.java
  8. 39 7
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/VipCardRecordController.java
  9. 5 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/UserTenantAlbumRecordVo.java
  10. 30 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/task/TaskController.java
  11. 7 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/CourseHomeworkController.java
  12. 7 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java
  13. 38 18
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MusicAlbumController.java
  14. 12 36
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/TeacherController.java
  15. 11 10
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/task/TaskController.java
  16. 6 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/CourseHomeworkController.java
  17. 7 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java
  18. 36 18
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicAlbumController.java
  19. 4 3
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java
  20. 27 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/SubjectController.java
  21. 8 17
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/SysMusicCompareRecordController.java
  22. 68 28
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherHomeController.java
  23. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EDiscountType.java
  24. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ETenantAlbumCategoryType.java
  25. 25 0
      cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/UpdateUserVipStatusTask.java
  26. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/HomeDao.java
  27. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/StudentDao.java
  28. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/TeacherDao.java
  29. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/VipCardRecordDao.java
  30. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/MusicAlbumSheetDto.java
  31. 6 22
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/MusicAlbumSheetSortDto.java
  32. 19 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicAlbumDetailSearch.java
  33. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicSheetSearch.java
  34. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentSearch.java
  35. 66 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumCategory.java
  36. 8 61
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumMusicRelate.java
  37. 26 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/DiscountCardRecord.java
  38. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImGroup.java
  39. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/Student.java
  40. 2 89
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/StudentCourseHomework.java
  41. 33 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserTenantAlbumRecord.java
  42. 31 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/VipCardRecord.java
  43. 45 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EDeductionStatus.java
  44. 34 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EStudentEntitlements.java
  45. 20 5
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  46. 2 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/PeriodEnum.java
  47. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/SourceTypeEnum.java
  48. 24 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/AlbumCategoryMapper.java
  49. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/DiscountCardRecordMapper.java
  50. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantAlbumRecordMapper.java
  51. 42 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/AlbumCategoryService.java
  52. 21 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/DiscountCardRecordService.java
  53. 8 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/HomeService.java
  54. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java
  55. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/StudentService.java
  56. 12 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserTenantAlbumRecordService.java
  57. 18 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/VipCardRecordService.java
  58. 96 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/AlbumCategoryServiceImpl.java
  59. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/AlbumMusicRelateServiceImpl.java
  60. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java
  61. 386 56
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/DiscountCardRecordServiceImpl.java
  62. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ExposureRecordServiceImpl.java
  63. 121 50
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/HomeServiceImpl.java
  64. 19 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java
  65. 43 19
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicAlbumServiceImpl.java
  66. 25 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetServiceImpl.java
  67. 41 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  68. 15 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/SysMusicCompareRecordServiceImpl.java
  69. 2 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  70. 7 52
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantActivationCodeServiceImpl.java
  71. 17 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java
  72. 332 126
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantAlbumRecordServiceImpl.java
  73. 454 189
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardRecordServiceImpl.java
  74. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/AlbumDetailVo.java
  75. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetVo.java
  76. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetVoResult.java
  77. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/UserOrderVo.java
  78. 125 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/AlbumCategoryWrapper.java
  79. 255 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/DiscountCardRecordWrapper.java
  80. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/HomeworkWrapper.java
  81. 15 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/MusicSheetWrapper.java
  82. 15 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StudentWrapper.java
  83. 78 10
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TeacherIndexWrapper.java
  84. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserInfoWrapper.java
  85. 129 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserTenantAlbumRecordWrapper.java
  86. 158 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/VipCardRecordWrapper.java
  87. 39 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/AlbumCategoryMapper.xml
  88. 71 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/DiscountCardRecordMapper.xml
  89. 5 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ExposureRecordDao.xml
  90. 83 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/HomeMapper.xml
  91. 14 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetMapper.xml
  92. 21 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentMapper.xml
  93. 8 7
      cooleshow-user/user-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml
  94. 13 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherMapper.xml
  95. 23 10
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderDetailMapper.xml
  96. 91 3
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserTenantAlbumRecordMapper.xml
  97. 76 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/VipCardRecordMapper.xml
  98. 30 0
      toolset/utils/src/main/java/com/yonge/toolset/utils/date/DateUtil.java

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

@@ -206,6 +206,9 @@ public interface AdminFeignService {
     HttpResponseResult<Object> courseStartRemind();
 
 
+    //更新权益
+    @GetMapping("/task/updateUserVipStatus")
+    void updateUserVipStatus();
     /**
      * 账号注销校验
      */

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

@@ -206,6 +206,11 @@ public class AdminFeignServiceFallback implements AdminFeignService {
     }
 
     @Override
+    public void updateUserVipStatus() {
+
+    }
+
+    @Override
     public ImUserInfo register(String userId, String clientType, String username, String avatar) {
         return null;
     }

+ 62 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/AlbumCategoryController.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.admin.controller;
+
+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.service.AlbumCategoryService;
+import com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper;
+import com.yonge.toolset.base.exception.BizException;
+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.*;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.admin:}/albumCategory")
+@Api(tags = "机构专辑分类")
+public class AlbumCategoryController {
+
+    @Autowired
+    private AlbumCategoryService albumCategoryService;
+
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
+    
+    @ApiOperation(value = "查询分页", notes = "机构专辑分类- 传入 AlbumCategoryWrapper.AlbumCategoryQuery")
+    @PostMapping("/page")
+    public R<PageInfo<AlbumCategoryWrapper.AlbumCategory>> page(@RequestBody AlbumCategoryWrapper.AlbumCategoryQuery query) {
+        
+        IPage<AlbumCategoryWrapper.AlbumCategory> pages = albumCategoryService.selectPage(QueryInfo.getPage(query), query);
+        
+        return R.from(QueryInfo.pageInfo(pages));
+	}
+    
+    @ApiOperation(value = "新增", notes = "机构专辑分类- 传入 AlbumCategoryWrapper.AlbumCategory")
+	@PostMapping("/save")
+	public R<JSONObject> add( @RequestBody @Validated AlbumCategoryWrapper.AddAlbumCategory albumCategory) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            throw new BizException("用户信息获取失败");
+        }
+        albumCategory.setOperatorId(sysUser.getId());
+        // 新增数据
+        albumCategoryService.add(albumCategory);
+        
+        return R.defaultR();
+	}
+
+	@ApiOperation(value = "删除", notes = "机构专辑分类- 传入id")
+	@PostMapping("/remove")
+	public R<Boolean> remove(@RequestParam Long id) {
+    
+		return R.from(albumCategoryService.del(id));
+	}
+}

+ 19 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/CourseHomeworkController.java

@@ -1,11 +1,14 @@
 package com.yonge.cooleshow.admin.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.yonge.cooleshow.biz.dal.dto.search.HomeworkAdminSearch;
 import com.yonge.cooleshow.biz.dal.entity.StudentCourseHomework;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.service.CourseHomeworkService;
 import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
 import com.yonge.cooleshow.biz.dal.service.StudentCourseHomeworkService;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo;
 import com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper;
@@ -17,6 +20,7 @@ import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
@@ -24,6 +28,8 @@ import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("${app-config.url.admin:}/homework")
@@ -38,6 +44,8 @@ public class CourseHomeworkController extends BaseController {
 
 	@Resource
 	private StudentCourseHomeworkService studentCourseHomeworkService;
+	@Resource
+	private SysUserService sysUserService;
 
 	@ApiOperation(value = "课后作业-列表", httpMethod = "POST", consumes = "application/json", produces = "application/json")
 	@PostMapping(value = "/list", consumes = "application/json", produces = "application/json")
@@ -85,7 +93,16 @@ public class CourseHomeworkController extends BaseController {
 	@ApiOperation(value = "根据作业编号,获取学员作业列表")
 	@GetMapping(value = "/studentList")
 	@PreAuthorize("@pcs.hasPermissions('homework/studentList')")
-	public HttpResponseResult<List<StudentCourseHomework>> studentList(Long homeworkId) {
-		return succeed(studentCourseHomeworkService.lambdaQuery().eq(StudentCourseHomework::getCourseHomeworkId, homeworkId).list());
+	public HttpResponseResult<List<HomeworkWrapper.StudentCourseHomeworkDto>> studentList(Long homeworkId) {
+		List<StudentCourseHomework> list = studentCourseHomeworkService.lambdaQuery().eq(StudentCourseHomework::getCourseHomeworkId, homeworkId).list();
+		if (CollectionUtils.isNotEmpty(list)){
+			List<HomeworkWrapper.StudentCourseHomeworkDto> dtos = JSON.parseArray(JSON.toJSONString(list), HomeworkWrapper.StudentCourseHomeworkDto.class);
+			List<Long> studentIds = dtos.stream().map(StudentCourseHomework::getStudentId).collect(Collectors.toList());
+			List<SysUser> sysUsers = sysUserService.getDao().selectBatchIds(studentIds);
+			Map<Long, String> nameMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getUsername));
+			dtos.forEach(e -> e.setStudentName(nameMap.get(e.getStudentId())));
+			return succeed(dtos);
+		}
+		return succeed(new ArrayList<>());
 	}
 }

+ 81 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/DiscountCardRecordController.java

@@ -0,0 +1,81 @@
+package com.yonge.cooleshow.admin.controller;
+
+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.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.service.DiscountCardRecordService;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("${app-config.url.admin:}/discountCardRecord")
+@Api(value = "畅学卡记录", tags = "畅学卡记录")
+public class DiscountCardRecordController extends BaseController {
+
+    @Autowired
+    private DiscountCardRecordService discountCardRecordService;
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @PostMapping("/page")
+    @ApiOperation(value = "畅学卡记录列表")
+    public R<PageInfo<DiscountCardRecordWrapper.DiscountCardRecord>> page(@RequestBody DiscountCardRecordWrapper.DiscountCardRecordQuery query) {
+
+        // 查询数据
+        IPage<DiscountCardRecordWrapper.DiscountCardRecord> pages = discountCardRecordService.selectPage(QueryInfo.getPage(query), query);
+
+
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增畅学卡", notes = "传入vipPurchaseRecord")
+    @PostMapping("/add")
+    public R<JSONObject> add(@Validated @RequestBody DiscountCardRecordWrapper.AddDiscountCardRecord result) {
+        SysUser sysUser = sysUserService.getUser();
+        if (sysUser == null  || sysUser.getId() == null) {
+            throw new BizException( "用户信息获取失败");
+        }
+        result.setCreateBy(sysUser.getId());
+        discountCardRecordService.addStudentVip(result);
+        return R.defaultR();
+    }
+
+
+
+    @ApiOperation(value = "扣减畅学卡", notes = "传入vipPurchaseRecord")
+    @PostMapping("/deduction")
+    public R<JSONObject> deduction(@Validated @RequestBody DiscountCardRecordWrapper.DeductionDiscountCardRecord result) {
+        SysUser sysUser = sysUserService.getUser();
+        if (sysUser == null  || sysUser.getId() == null) {
+            throw new BizException( "用户信息获取失败");
+        }
+        result.setCreateBy(sysUser.getId());
+        discountCardRecordService.deduction(result);
+        return R.defaultR();
+    }
+
+
+
+
+
+    @ApiOperation(value = "畅学卡时长")
+    @PostMapping("/info")
+    public R<DiscountCardRecordWrapper.Info> info(@RequestBody DiscountCardRecordWrapper.InfoQuery infoQuery) {
+
+        return R.from(discountCardRecordService.info(infoQuery));
+    }
+}

+ 10 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -338,4 +338,14 @@ public class StudentController extends BaseController {
         studentService.save(student);
         return succeed();
     }
+
+
+
+    @GetMapping("/initEntitlements")
+    @ApiOperation(value = "初始化权益")
+    public HttpResponseResult<Boolean> syncEntitlements() {
+
+        studentService.initEntitlements();
+        return succeed();
+    }
 }

+ 30 - 45
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/UserTenantAlbumRecordController.java

@@ -1,45 +1,36 @@
 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.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.UserTenantAlbumRecordVo;
-import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.entity.UserTenantAlbumRecord;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.service.UserTenantAlbumRecordService;
-import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.page.PageInfo;
-import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.redisson.Redisson;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 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.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.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 @Slf4j
 @Validated
@@ -52,31 +43,23 @@ public class UserTenantAlbumRecordController extends BaseController {
     private UserTenantAlbumRecordService userTenantAlbumRecordService;
 
     @Resource
-    private SysUserFeignService sysUserFeignService;
+    private SysUserService sysUserService;
 
     @Autowired
     private RedissonClient redissonClient;
 
-    @ApiOperation(value = "详情", notes = "购买训练工具记录-根据详情ID查询单条, 传入id")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
-    })
-    @PreAuthorize("@pcs.hasPermissions('userTenantAlbumRecord/detail', {'BACKEND'})")
-//    @GetMapping("/detail/{id}")
-    public R<UserTenantAlbumRecordVo.UserTenantAlbumRecord> detail(@PathVariable("id") Long id) {
+    @PostMapping("/page")
+    @ApiOperation(value = "记录列表")
+    public R<PageInfo<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord>> page(@RequestBody UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query) {
 
-        UserTenantAlbumRecord wrapper = userTenantAlbumRecordService.detail(id);
+        // 查询数据
+        IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> pages = userTenantAlbumRecordService.selectAdminPage(QueryInfo.getPage(query), query);
 
-        return R.from(UserTenantAlbumRecordVo.UserTenantAlbumRecord.from(JSON.toJSONString(wrapper)));
-    }
 
-    @ApiOperation(value = "查询分页", notes = "购买训练工具记录- 传入 UserTenantAlbumRecordVo.UserTenantAlbumRecordQuery")
-    @PreAuthorize("@pcs.hasPermissions('userTenantAlbumRecord/page', {'BACKEND'})")
-    @PostMapping("/page")
-    public R<PageInfo<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord>> page(@RequestBody UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query) {
-        return R.from(PageUtil.pageInfo(userTenantAlbumRecordService.selectUserTenantAlbumRecordPage(QueryInfo.getPage(query), query)));
+        return R.from(QueryInfo.pageInfo(pages));
     }
 
+
     @ApiOperation(value = "新增", notes = "购买训练工具记录- 传入 UserTenantAlbumRecordVo.UserTenantAlbumRecord")
     @PreAuthorize("@pcs.hasPermissions('userTenantAlbumRecord/save', {'BACKEND'})")
     @PostMapping("/save")
@@ -93,19 +76,19 @@ public class UserTenantAlbumRecordController extends BaseController {
         userTenantAlbumRecord.setClientType(ClientEnum.STUDENT);
         userTenantAlbumRecord.setSourceType(SourceTypeEnum.BACKEND_GIVE);
 
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        SysUser sysUser = sysUserService.getUser();
         userTenantAlbumRecord.setCreateBy(sysUser.getId());
 
         RLock lock = redissonClient.getLock("UserTenantAlbumRecord_" + userTenantAlbumRecordVo.getUserId() + "_" + userTenantAlbumRecordVo.getTenantAlbumId());
         try {
             boolean b = lock.tryLock(60, 60, TimeUnit.SECONDS);
             if (b) {
-                userTenantAlbumRecordService.add(userTenantAlbumRecord);
+                userTenantAlbumRecordService.add(userTenantAlbumRecord,userTenantAlbumRecordVo.getSendMsg());
             } else {
                 throw new BizException("请勿重复点击");
             }
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            log.error("获取锁异常", e);
         } finally {
             if (lock.getHoldCount() > 0) {
                 lock.unlock();
@@ -114,25 +97,27 @@ public class UserTenantAlbumRecordController extends BaseController {
         return R.defaultR();
     }
 
-    @ApiOperation(value = "修改", notes = "购买训练工具记录- 传入 UserTenantAlbumRecordVo.UserTenantAlbumRecord")
-    @PreAuthorize("@pcs.hasPermissions('userTenantAlbumRecord/update', {'BACKEND'})")
-//    @PostMapping("/update")
-    public R<JSONObject> update(@Validated @RequestBody UserTenantAlbumRecordVo.UserTenantAlbumRecord userTenantAlbumRecordVo) {
-
-        // 更新数据
-        userTenantAlbumRecordService.updateById(JSON.parseObject(userTenantAlbumRecordVo.jsonString(), UserTenantAlbumRecord.class));
 
+    @ApiOperation(value = "扣减", notes = "传入vipPurchaseRecord")
+    @PostMapping("/deduction")
+    public R<JSONObject> deduction(@Validated @RequestBody UserTenantAlbumRecordWrapper.DeductionUserTenantAlbumRecord result) {
+        SysUser sysUser = sysUserService.getUser();
+        if (sysUser == null  || sysUser.getId() == null) {
+            throw new BizException( "用户信息获取失败");
+        }
+        result.setCreateBy(sysUser.getId());
+        userTenantAlbumRecordService.deduction(result);
         return R.defaultR();
     }
 
-    @ApiOperation(value = "删除", notes = "购买训练工具记录- 传入id")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
-    })
-    @PreAuthorize("@pcs.hasPermissions('userTenantAlbumRecord/remove', {'BACKEND'})")
-//    @PostMapping("/remove")
-    public R<Boolean> remove(@RequestParam Long id) {
 
-        return R.from(userTenantAlbumRecordService.removeById(id));
+
+
+
+    @ApiOperation(value = "时长")
+    @PostMapping("/info")
+    public R<List<UserTenantAlbumRecordWrapper.Info>> info(@RequestBody UserTenantAlbumRecordWrapper.InfoQuery infoQuery) {
+
+        return R.from(userTenantAlbumRecordService.info(infoQuery));
     }
 }

+ 39 - 7
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/VipCardRecordController.java

@@ -2,6 +2,9 @@ package com.yonge.cooleshow.admin.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.google.common.collect.Lists;
+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.dao.UserOrderDao;
@@ -13,12 +16,11 @@ import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
 import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.page.PageInfo;
-import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.checkerframework.checker.units.qual.A;
@@ -63,20 +65,41 @@ public class VipCardRecordController extends BaseController {
      */
     @PostMapping("/page")
     @ApiOperation(value = "查询分页", notes = "传入vipCardRecordSearch")
-    public HttpResponseResult<PageInfo<VipCardRecordVo>> page(@RequestBody VipCardRecordSearch query) {
-        IPage<VipCardRecordVo> pages = vipCardRecordService.selectPage(PageUtil.getPage(query), query);
-        return succeed(PageUtil.pageInfo(pages));
+    public HttpResponseResult<PageInfo<VipCardRecordWrapper.VipCardRecord>> page(@RequestBody VipCardRecordWrapper.VipQuery query) {
+        IPage<VipCardRecordWrapper.VipCardRecord> pages = vipCardRecordService.selectAdminPage(QueryInfo.getPage(query), query);
+        return succeed(QueryInfo.pageInfo(pages));
     }
 
+    @ApiOperation("扣减会员")
+    @PostMapping("/deduction")
+    @PreAuthorize("@pcs.hasPermissions('vipCardRecord/deduction')")
+    public HttpResponseResult<Void> deduction(@RequestBody @Validated VipCardRecordWrapper.DeductionVipCardRecord deductionVipCardRecord) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        deductionVipCardRecord.setCreateBy(sysUser.getId());
+
+        // 判断是否有待支付订单 如果有返回不可下单
+        OrderSearch search = new OrderSearch();
+        search.setOrderClient(deductionVipCardRecord.getClientType().name());
+        search.setGoodType(Lists.newArrayList(GoodTypeEnum.VIP, GoodTypeEnum.SVIP).stream().map(GoodTypeEnum::name).collect(Collectors.joining(",")));
+        search.setUserId(deductionVipCardRecord.getUserId());
+
+        UserOrderVo userOrderVo = userOrderDao.getPendingOrder(search);
+        if (null != userOrderVo) {
+            throw new BizException(997, "当前用户存在未支付订单,不可操作添加/扣减会员");
+        }
+        vipCardRecordService.deduction(deductionVipCardRecord);
+        return succeed();
+    }
 
-    @ApiOperation("添加/扣减会员")
+
+    @ApiOperation("添加会员")
     @PostMapping("/add")
     @PreAuthorize("@pcs.hasPermissions('vipCardRecord/add')")
     public HttpResponseResult<Void> add(@RequestBody @Validated VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         addVipCardRecord.setCreateBy(sysUser.getId());
         if (addVipCardRecord.getStatus().equals(EVipRecordStatus.ADD)) {
-            addVipCardRecord.setSourceType(SourceTypeEnum.PLATFORM);
+            addVipCardRecord.setSourceType(SourceTypeEnum.BACKEND_GIVE);
         } else if (addVipCardRecord.getStatus().equals(EVipRecordStatus.DEDUCTION)) {
             addVipCardRecord.setSourceType(SourceTypeEnum.PLATFORM_DEDUCT);
         }
@@ -94,4 +117,13 @@ public class VipCardRecordController extends BaseController {
         vipCardRecordService.add(addVipCardRecord);
         return succeed();
     }
+
+
+
+    @ApiOperation(value = "会员时长")
+    @PostMapping("/info")
+    public R<VipCardRecordWrapper.Info> info(@RequestBody VipCardRecordWrapper.InfoQuery infoQuery) {
+
+        return R.from(vipCardRecordService.info(infoQuery));
+    }
 }

+ 5 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/UserTenantAlbumRecordVo.java

@@ -101,7 +101,7 @@ public class UserTenantAlbumRecordVo {
 
         @ApiModelProperty(value = "时间类型 DAY:天 MONTH:月,YEAR:年", required = true)
         @NotNull
-        @Pattern(regexp = "^DAY|MONTH|YEAR$")
+        @Pattern(regexp = "^DAY|MONTH|YEAR|PERPETUAL$")
         private String type;
 
 
@@ -119,6 +119,10 @@ public class UserTenantAlbumRecordVo {
         private String reason;
 
 
+        @ApiModelProperty("是否发送推送,1:是,0:否")
+        @NotNull(message = "是否发送推送不能为空")
+        private Boolean sendMsg;
+
         public String jsonString() {
             return JSON.toJSONString(this);
         }

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

@@ -25,6 +25,7 @@ import springfox.documentation.annotations.ApiIgnore;
 import java.io.File;
 import java.net.URL;
 import java.util.Date;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -86,6 +87,12 @@ public class TaskController extends BaseController {
     @Autowired
     private UserMusicService userMusicService;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
+    @Autowired
+    private StudentService studentService;
+
     /***
      * 轮询用户订单
      * @author liweifan
@@ -374,4 +381,27 @@ public class TaskController extends BaseController {
             }
         }, 10L, TimeUnit.SECONDS);
     }
+
+
+
+    //更新权益
+    @GetMapping("/updateUserVipStatus")
+    public void updateUserVipStatus(){
+        DistributedLock.of(redissonClient).runIfLockCanGet("updateUserVipStatus", () -> {
+            try {
+
+                List<Long> userIds = vipCardRecordService.updateUserVipStatus();
+
+                userIds.parallelStream().forEach(userId -> {
+                    try {
+                        studentService.updateVipStatus(userId);
+                    }catch (Exception e){
+                        log.error("updateUserVipStatus error", e);
+                    }
+                });
+            }catch (Exception e){
+                log.error("updateUserVipStatus error", e);
+            }
+        }, 10L, TimeUnit.SECONDS);
+    }
 }

+ 7 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/CourseHomeworkController.java

@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -95,6 +96,12 @@ public class CourseHomeworkController extends BaseController {
         query.setStudentId(sysUserService.getUserId());
         query.setClientType("STUDENT");
         query.setCourseStatus(CourseScheduleEnum.COMPLETE);
+        List<CourseScheduleEnum> list = new ArrayList<>();
+        list.add(CourseScheduleEnum.PIANO_ROOM_CLASS);
+        list.add(CourseScheduleEnum.PRACTICE);
+        list.add(CourseScheduleEnum.VIP);
+        list.add(CourseScheduleEnum.GROUP);
+        query.setCourseType(list);
 
         IPage<CourseHomeworkVo> page = courseHomeworkService.selectPage(PageUtil.getPage(query), query);
         List<CourseHomeworkVo> records = page.getRecords();

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

@@ -156,5 +156,12 @@ public class ImGroupController extends BaseController {
 
         return succeed(userFriend);
     }
+
+    @ApiOperation("修改群简介")
+    @PostMapping(value = "/updateIntroduce")
+    public HttpResponseResult<Boolean> updateIntroduce(@Valid @RequestBody ImGroup imGroup) throws Exception {
+        return succeed(imGroupService.updateIntroduce(imGroup));
+    }
+
 }
 

+ 38 - 18
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MusicAlbumController.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumDetailSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumSearch;
+import com.yonge.cooleshow.biz.dal.dto.search.MusicSheetSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
@@ -12,9 +13,11 @@ import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.album.PurchaseRecordTypeEnum;
 import com.yonge.cooleshow.biz.dal.service.AppVersionInfoService;
 import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
+import com.yonge.cooleshow.biz.dal.service.MusicSheetService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.vo.AlbumDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
+import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -60,6 +63,9 @@ public class MusicAlbumController extends BaseController {
     @Autowired
     private AppVersionInfoService appVersionInfoService;
 
+    @Autowired
+    private MusicSheetService musicSheetService;
+
     @ApiOperation(value = "分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/list", consumes="application/json", produces="application/json")
     public HttpResponseResult<PageInfo<MusicAlbumVo>> list(@RequestBody MusicAlbumSearch query) {
@@ -97,6 +103,17 @@ public class MusicAlbumController extends BaseController {
     }
 
 
+    @ApiOperation(value = "分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
+    @PostMapping(value="/musicPage", consumes="application/json", produces="application/json")
+    public HttpResponseResult<PageInfo<MusicSheetVo>> musicPage(@RequestBody MusicAlbumDetailSearch query) {
+
+        query.setType(2);
+        query.setState(YesOrNoEnum.YES);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectAlbumDetailPage(PageUtil.getPage(query), query);
+        return succeed(PageUtil.pageInfo(musicSheetVoIPage));
+    }
+
+
     /**
      * 专辑详情
      */
@@ -113,25 +130,28 @@ public class MusicAlbumController extends BaseController {
         AlbumDetailVo albumDetailVo = musicAlbumService.detail(PageUtil.getPage(query), query,sysUser,ClientEnum.STUDENT);
         albumDetailVo.setFavorite(yesOrNoEnum);
 
-        // 相关专辑
-        MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
-        musicAlbumSearch.setAuditVersion(YesOrNoEnum.NO);
-        musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);
-        musicAlbumSearch.setAuditVersion(albumDetailVo.getAuditVersion());
-        musicAlbumSearch.setSortBy(1);
-        musicAlbumSearch.setPage(1);
-        musicAlbumSearch.setRows(query.getRelatedNum() +1);
-        musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
-        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.STUDENT);
-        List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
-                                                      .stream()
-                                                      .filter(musicAlbumVo -> !musicAlbumVo.getId()
-                                                                                           .equals(albumDetailVo.getId()))
-                                                      .collect(Collectors.toList());
-        if (musicAlbumVos1.size() > query.getRelatedNum()) {
-            musicAlbumVos1 = musicAlbumVos1.subList(0,query.getRelatedNum());
+
+        if (query.getQueryRelatedAlbum()) {
+            // 相关专辑
+            MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
+            musicAlbumSearch.setAuditVersion(YesOrNoEnum.NO);
+            musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);
+            musicAlbumSearch.setAuditVersion(albumDetailVo.getAuditVersion());
+            musicAlbumSearch.setSortBy(1);
+            musicAlbumSearch.setPage(1);
+            musicAlbumSearch.setRows(query.getRelatedNum() + 1);
+            musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
+            IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch), musicAlbumSearch, ClientEnum.STUDENT);
+            List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
+                    .stream()
+                    .filter(musicAlbumVo -> !musicAlbumVo.getId()
+                            .equals(albumDetailVo.getId()))
+                    .collect(Collectors.toList());
+            if (musicAlbumVos1.size() > query.getRelatedNum()) {
+                musicAlbumVos1 = musicAlbumVos1.subList(0, query.getRelatedNum());
+            }
+            albumDetailVo.setRelatedMusicAlbum(musicAlbumVos1);
         }
-        albumDetailVo.setRelatedMusicAlbum(musicAlbumVos1);
         return succeed(albumDetailVo);
     }
 

+ 12 - 36
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/TeacherController.java

@@ -6,10 +6,7 @@ import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.TeacherStyleSearch;
 import com.yonge.cooleshow.biz.dal.entity.TeacherStyleVideo;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
-import com.yonge.cooleshow.biz.dal.service.AppVersionInfoService;
-import com.yonge.cooleshow.biz.dal.service.StudentStarService;
-import com.yonge.cooleshow.biz.dal.service.TeacherService;
-import com.yonge.cooleshow.biz.dal.service.TeacherStyleVideoService;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.HotTeacherVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherHomeVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherStyleVideoVo;
@@ -31,6 +28,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 java.util.List;
 import java.util.stream.Collectors;
 
@@ -38,31 +36,27 @@ import java.util.stream.Collectors;
 @RequestMapping("${app-config.url.student:}/teacher")
 @Api(value = "教师表", tags = "教师表")
 public class TeacherController extends BaseController {
-    @Autowired
+    @Resource
     private TeacherStyleVideoService styleVideoService;
-    @Autowired
-    private SysUserFeignService sysUserFeignService;
-    @Autowired
+    @Resource
+    private SysUserService sysUserService;
+    @Resource
     private TeacherService teacherService;
-    @Autowired
+    @Resource
     private StudentStarService studentStarService;
-    @Autowired
+    @Resource
     private AppVersionInfoService appVersionInfoService;
 
     @ApiOperation(value = "老师风采-分页")
     @PostMapping("/stylePage")
     public HttpResponseResult<PageInfo<TeacherStyleVideoVo>> stylePage(@RequestBody TeacherStyleSearch query) {
-        SysUser user = sysUserFeignService.queryUserInfo();
-        if (user == null || null == user.getId()) {
-            return failed(HttpStatus.FORBIDDEN, "请登录");
-        }
         /*if(StringUtils.isBlank(query.getSubjectId())){
         	Student student = studentService.getById(user.getId());
         	query.setSubjectId(student.getSubjectId());
         }*/
         // 检查app版本
         query.setAuditVersion(appVersionInfoService.getAppAuditVersion(query.getPlatform(), query.getVersion()));
-        query.setStudentId(user.getId());
+        query.setStudentId(sysUserService.getUserId());
         IPage<TeacherStyleVideoVo> pages = styleVideoService.stylePage(PageUtil.getPage(query), query);
         return succeed(PageUtil.pageInfo(pages));
     }
@@ -73,11 +67,7 @@ public class TeacherController extends BaseController {
         if (null == userId) {
             return failed("缺少老师ID");
         }
-        SysUser user = sysUserFeignService.queryUserInfo();
-        if (user == null || null == user.getId()) {
-            return failed(HttpStatus.FORBIDDEN, "请登录");
-        }
-        HttpResponseResult<TeacherHomeVo> res = teacherService.queryTeacherHome(user.getId(), userId);
+        HttpResponseResult<TeacherHomeVo> res = teacherService.queryTeacherHome(sysUserService.getUserId(), userId);
         //学生端过滤只看审核通过的
         if (null != res.getData() && !CollectionUtils.isEmpty(res.getData().getStyleVideo())) {
             List<TeacherStyleVideo> styleVideo = res.getData().getStyleVideo();
@@ -98,11 +88,7 @@ public class TeacherController extends BaseController {
         if (null == starStatusEnum) {
             return failed("缺少关注状态");
         }
-        SysUser user = sysUserFeignService.queryUserInfo();
-        if (user == null || null == user.getId()) {
-            return failed(HttpStatus.FORBIDDEN, "请登录");
-        }
-        return studentStarService.starOrUnStar(user.getId(), userId, starStatusEnum);
+        return studentStarService.starOrUnStar(sysUserService.getUserId(), userId, starStatusEnum);
     }
 
     @ApiOperation(value = "增加视频浏览量")
@@ -126,20 +112,10 @@ public class TeacherController extends BaseController {
     @ApiOperation(value = "推荐老师列表")
     @GetMapping("/queryHotTeacherList")
     public HttpResponseResult<List<HotTeacherVo>> queryHotTeacherList() {
-        SysUser user = sysUserFeignService.queryUserInfo();
-        if (user == null || null == user.getId()) {
-            return failed(HttpStatus.FORBIDDEN, "请登录");
-        }
-        Long userId = null;
-        if (user != null && null != user.getId()) {
-            userId = user.getId();
-        }
-        List<HotTeacherVo> list = teacherService.queryHotTeacherList(userId);
-        
+        List<HotTeacherVo> list = teacherService.queryHotTeacherList(sysUserService.getUserId());
         for(HotTeacherVo vo : list){
         	vo.setGraduateSchool(null);
         }
-        
         return HttpResponseResult.succeed(list);
     }
 }

+ 11 - 10
cooleshow-app/src/main/java/com/yonge/cooleshow/student/task/TaskController.java

@@ -1,10 +1,7 @@
 package com.yonge.cooleshow.student.task;
 
 import com.yonge.cooleshow.biz.dal.entity.StudentTotal;
-import com.yonge.cooleshow.biz.dal.service.CourseRepliedService;
-import com.yonge.cooleshow.biz.dal.service.StudentTimeService;
-import com.yonge.cooleshow.biz.dal.service.StudentTotalService;
-import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.payment.util.DistributedLock;
@@ -16,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import springfox.documentation.annotations.ApiIgnore;
 
+import javax.annotation.Resource;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -28,13 +26,15 @@ import java.util.concurrent.TimeUnit;
 @ApiIgnore
 @Slf4j
 public class TaskController extends BaseController {
-    @Autowired
+    @Resource
     private StudentTotalService studentTotalService;
-    @Autowired
+    @Resource
     private StudentTimeService studentTimeService;
-    @Autowired
+    @Resource
     private VipCardRecordService vipCardRecordService;
-    @Autowired
+    @Resource
+    private DiscountCardRecordService discountCardRecordService;
+    @Resource
     private CourseRepliedService repliedService;
 
 
@@ -59,12 +59,13 @@ public class TaskController extends BaseController {
      */
     @GetMapping("/halfHourTask")
     public HttpResponseResult<Boolean> halfHourTask() {
-        //会员卡到期提醒
         // 并发执行锁
         DistributedLock.of(redissonClient).runIfLockCanGet("halfHourTask", () -> {
             try {
-
+                //会员卡到期提醒
                 vipCardRecordService.pollExpireMsg();
+                //畅学卡到期提醒
+                discountCardRecordService.pollExpireMsg();
             }catch (Exception e){
                 log.error("halfHourTask error", e);
             }

+ 6 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/CourseHomeworkController.java

@@ -142,6 +142,12 @@ public class CourseHomeworkController extends BaseController {
         query.setTeacherId(sysUserService.getUserId());
         query.setCourseStatus(CourseScheduleEnum.COMPLETE);
         query.setClientType("TEACHER");
+        List<CourseScheduleEnum> list = new ArrayList<>();
+        list.add(CourseScheduleEnum.PIANO_ROOM_CLASS);
+        list.add(CourseScheduleEnum.PRACTICE);
+        list.add(CourseScheduleEnum.VIP);
+        list.add(CourseScheduleEnum.GROUP);
+        query.setCourseType(list);
 
         IPage<CourseHomeworkVo> page = courseHomeworkService.selectPage(PageUtil.getPage(query), query);
         if (CollectionUtils.isNotEmpty(page.getRecords())) {

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

@@ -171,6 +171,13 @@ public class ImGroupController extends BaseController {
         return succeed(imGroupService.queryAll(imGroupSearchDto));
     }
 
+
+    @ApiOperation("修改群简介")
+    @PostMapping(value = "/updateIntroduce")
+    public HttpResponseResult<Boolean> updateIntroduce(@Valid @RequestBody ImGroup imGroup) throws Exception {
+        return succeed(imGroupService.updateIntroduce(imGroup));
+    }
+
     @ApiOperation("修改群信息")
     @PostMapping(value = "/update")
     public HttpResponseResult<Boolean> update(@Valid @RequestBody ImGroup imGroup) throws Exception {

+ 36 - 18
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicAlbumController.java

@@ -12,9 +12,11 @@ import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.album.PurchaseRecordTypeEnum;
 import com.yonge.cooleshow.biz.dal.service.AppVersionInfoService;
 import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
+import com.yonge.cooleshow.biz.dal.service.MusicSheetService;
 import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.biz.dal.vo.AlbumDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
+import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -63,6 +65,9 @@ public class MusicAlbumController extends BaseController {
     @Autowired
     private AppVersionInfoService appVersionInfoService;
 
+    @Autowired
+    private MusicSheetService musicSheetService;
+
     @ApiOperation(value = "分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/list", consumes="application/json", produces="application/json")
     public HttpResponseResult<PageInfo<MusicAlbumVo>> list(@RequestBody MusicAlbumSearch query) {
@@ -114,25 +119,27 @@ public class MusicAlbumController extends BaseController {
         AlbumDetailVo albumDetailVo = musicAlbumService.detail(PageUtil.getPage(query), query, sysUser,  ClientEnum.TEACHER);
         albumDetailVo.setFavorite(yesOrNoEnum);
 
-        // 相关专辑
-        MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
-        musicAlbumSearch.setAuditVersion(YesOrNoEnum.NO);
-        musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);
-        musicAlbumSearch.setAuditVersion(albumDetailVo.getAuditVersion());
-        musicAlbumSearch.setSortBy(1);
-        musicAlbumSearch.setPage(1);
-        musicAlbumSearch.setRows(query.getRelatedNum() +1);
-        musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
-        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.TEACHER);
-        List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
-                                                      .stream()
-                                                      .filter(musicAlbumVo -> !musicAlbumVo.getId()
-                                                                                           .equals(albumDetailVo.getId()))
-                                                      .collect(Collectors.toList());
-        if (musicAlbumVos1.size() > query.getRelatedNum()) {
-            musicAlbumVos1 = musicAlbumVos1.subList(0,query.getRelatedNum());
+        if (query.getQueryRelatedAlbum()) {
+            // 相关专辑
+            MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
+            musicAlbumSearch.setAuditVersion(YesOrNoEnum.NO);
+            musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);
+            musicAlbumSearch.setAuditVersion(albumDetailVo.getAuditVersion());
+            musicAlbumSearch.setSortBy(1);
+            musicAlbumSearch.setPage(1);
+            musicAlbumSearch.setRows(query.getRelatedNum() + 1);
+            musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
+            IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch), musicAlbumSearch, ClientEnum.TEACHER);
+            List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
+                    .stream()
+                    .filter(musicAlbumVo -> !musicAlbumVo.getId()
+                            .equals(albumDetailVo.getId()))
+                    .collect(Collectors.toList());
+            if (musicAlbumVos1.size() > query.getRelatedNum()) {
+                musicAlbumVos1 = musicAlbumVos1.subList(0, query.getRelatedNum());
+            }
+            albumDetailVo.setRelatedMusicAlbum(musicAlbumVos1);
         }
-        albumDetailVo.setRelatedMusicAlbum(musicAlbumVos1);
         return succeed(albumDetailVo);
     }
 
@@ -207,4 +214,15 @@ public class MusicAlbumController extends BaseController {
     }
 
 
+
+    @ApiOperation(value = "分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
+    @PostMapping(value="/musicPage", consumes="application/json", produces="application/json")
+    public HttpResponseResult<PageInfo<MusicSheetVo>> musicPage(@RequestBody MusicAlbumDetailSearch query) {
+
+        query.setType(2);
+        query.setState(YesOrNoEnum.YES);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectAlbumDetailPage(PageUtil.getPage(query), query);
+        return succeed(PageUtil.pageInfo(musicSheetVoIPage));
+    }
+
 }

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.teacher.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.AppMusicSheetVo;
 import com.yonge.cooleshow.biz.dal.dto.MusicSheetRenderDto;
@@ -24,7 +25,6 @@ import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.EStatus;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.page.PageInfo;
-import com.yonge.toolset.base.page.QueryInfo;
 import com.yonge.toolset.base.util.StringUtil;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
@@ -235,18 +235,19 @@ public class MusicSheetController extends BaseController {
      */
     @GetMapping("/favorite")
     @ApiOperation(value = "收藏单曲")
-    public HttpResponseResult<PageInfo<MusicSheetVo>> favoriteMusic(QueryInfo query) {
+    public HttpResponseResult<PageInfo<MusicSheetVo>> favoriteMusic(MusicSheetWrapper.MusicSheetFavoriteQuery query) {
         SysUser sysUser = sysUserService.getUser();
         StudentMusicSheetSearch search = new StudentMusicSheetSearch();
         Teacher teacher = teacherService.getById(sysUser.getId());
         if (teacher.getTenantId() !=null && teacher.getTenantId() >0) {
             search.setTenantId(teacher.getTenantId());
         }
+        search.setFavoriteProviderType(query.getProviderType());
         search.setStudentId(sysUser.getId());
         search.setState(YesOrNoEnum.YES);
         search.setAuditStatus(null);
         search.setProviderType(null);
-        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search, ClientEnum.TEACHER);
+        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(QueryInfo.getPage(query),search, ClientEnum.TEACHER);
         return succeed(PageUtil.pageInfo(sheetVoIPage));
     }
 

+ 27 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/SubjectController.java

@@ -13,11 +13,14 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @RequestMapping("${app-config.url.teacher:}/subject")
 @Api(tags = "声部服务")
@@ -66,4 +69,28 @@ public class SubjectController extends BaseController {
 		subjectService.convertSubSubject(subjectSelect);
         return succeed(subjectSelect);
     }
+
+	@ApiOperation(value = "获取子集声部")
+	@GetMapping("/subSubjectSelect")
+    public HttpResponseResult<List<Subject>> subSubjectSelect(String type){
+		String userExtSubjectIds = null;
+
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser != null && sysUser.getId() != null) {
+        	Teacher teacher = teacherService.getById(sysUser.getId());
+        	if(teacher != null && teacher.getDefaultSubject() != null){
+        		userExtSubjectIds = teacher.getDefaultSubject().toString();
+        	}
+        }
+        List<Subject> subjectSelect = subjectService.subjectSelect(type, userExtSubjectIds);
+		//获取子集声部
+		if(CollectionUtils.isNotEmpty(subjectSelect)){
+			List<Subject> result = new ArrayList<>();
+			subjectSelect.stream()
+					.filter(e->CollectionUtils.isNotEmpty(e.getSubjects()))
+					.forEach(e->result.addAll(e.getSubjects()));
+			return succeed(result);
+		}
+        return succeed(subjectSelect);
+    }
 }

+ 8 - 17
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/SysMusicCompareRecordController.java

@@ -6,6 +6,7 @@ import com.yonge.cooleshow.biz.dal.entity.SysMusicCompareRecord;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.queryInfo.SysMusicCompareRecordQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.SysMusicCompareRecordService;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.exception.BizException;
@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.Objects;
@@ -31,18 +33,15 @@ import java.util.Objects;
 @RestController
 public class SysMusicCompareRecordController extends BaseController {
 
-    @Autowired
-    private SysUserFeignService sysUserFeignService;
-    @Autowired
+    @Resource
+    private SysUserService sysUserService;
+    @Resource
     private SysMusicCompareRecordService sysMusicCompareRecordService;
 
     @ApiOperation(value = "添加记录")
     @PostMapping("add")
     public HttpResponseResult add(SysMusicCompareRecord record){
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if(sysUser == null){
-            throw new BizException("请登录");
-        }
+        SysUser sysUser = sysUserService.getUser();
         if(Objects.isNull(record.getFeature())){
             return failed("请设置功能点");
         }
@@ -55,21 +54,13 @@ public class SysMusicCompareRecordController extends BaseController {
     @ApiOperation(value = "用户最后一次评测数据")
     @GetMapping("getLastEvaluationMusicalNotesPlayStats")
     public HttpResponseResult getLastEvaluationMusicalNotesPlayStats(Long recordId){
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if(sysUser == null){
-            throw new BizException("请登录");
-        }
-        return succeed(sysMusicCompareRecordService.getLastEvaluationMusicalNotesPlayStats(sysUser.getId(), recordId));
+        return succeed(sysMusicCompareRecordService.getLastEvaluationMusicalNotesPlayStats(sysUserService.getUserId(), recordId));
     }
 
     @ApiOperation("老师训练数据统计")
     @GetMapping("studentTrainData")
     public HttpResponseResult studentTrainData(SysMusicCompareRecordQueryInfo.TeacherCompareRecordQueryInfo queryInfo){
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null) {
-            return failed("获取用户信息失败");
-        }
-        queryInfo.setUserId(sysUser.getId());
+        queryInfo.setUserId(sysUserService.getUserId());
         queryInfo.setClientId("teacher");
         if (StringUtils.isEmpty(queryInfo.getStartTime())) {
             return failed("时间不能为空");

+ 68 - 28
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherHomeController.java

@@ -1,6 +1,9 @@
 package com.yonge.cooleshow.teacher.controller;
 
-import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.middleware.oss.OssPluginContext;
+import com.microsvc.toolkit.middleware.oss.impl.TencentOssPlugin;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.PianoRoomTimeVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherHomeStatisticalVo;
@@ -8,12 +11,24 @@ import com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherHomeWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import com.yonge.toolset.utils.date.DateUtil;
+import com.yonge.toolset.utils.easyexcel.ExcelUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.Data;
+import org.apache.commons.io.FileUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.io.File;
 import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -37,9 +52,9 @@ public class TeacherHomeController extends BaseController {
     @Resource
     private UserAccountRecordService userAccountRecordService;
     @Resource
-    private SysMusicCompareRecordService sysMusicCompareRecordService;
-    @Resource
     private HomeService homeService;
+    @Resource
+    private OssPluginContext ossPluginContext;
 
     @ApiOperation(value = "首页统计数据")
     @GetMapping(value="/count")
@@ -96,12 +111,7 @@ public class TeacherHomeController extends BaseController {
     @ApiOperation(value = "课程统计")
     @PostMapping("/totalCourse")
     public HttpResponseResult<List<TeacherHomeWrapper.TeacherTotalCourse>> totalCourse(@RequestBody TeacherHomeWrapper.TeacherTotalCourseQuery query) {
-        SysUser sysUser = sysUserService.getUser();
-        if (sysUser == null  || sysUser.getId() == null) {
-
-            return failed("用户信息获取失败");
-        }
-        query.setTeacherId(sysUser.getId());
+        query.setTeacherId(sysUserService.getUserId());
 
         return succeed(homeService.teacherTotalCourse(query));
     }
@@ -110,39 +120,69 @@ public class TeacherHomeController extends BaseController {
     @ApiOperation(value = "我的乐谱统计")
     @GetMapping("/musicSheetTotal")
     public HttpResponseResult<TeacherHomeWrapper.MusicSheetTotal> musicSheetTotal() {
-        SysUser sysUser = sysUserService.getUser();
-        if (sysUser == null  || sysUser.getId() == null) {
-
-            return failed("用户信息获取失败");
-        }
-
-        return succeed(homeService.musicSheetTotal(sysUser.getId()));
+        return succeed(homeService.musicSheetTotal(sysUserService.getUserId()));
     }
 
     @ApiOperation(value = "我的乐谱分页")
     @PostMapping("/musicSheetPage")
     public HttpResponseResult<List<TeacherHomeWrapper.MusicSheetTotal>> musicSheetPage(@RequestBody TeacherHomeWrapper.MusicSheetQuery query) {
-        SysUser sysUser = sysUserService.getUser();
-        if (sysUser == null  || sysUser.getId() == null) {
-
-            return failed("用户信息获取失败");
-        }
-        query.setTeacherId(sysUser.getId());
-
+        query.setTeacherId(sysUserService.getUserId());
         return succeed(homeService.musicSheetPage(query));
     }
 
 
 
-    @ApiOperation(value = "课程曝光/购买")
+    @ApiOperation(value = "课程浏览/购买")
     @PostMapping("/courseExposure")
     public HttpResponseResult<Map<String, List<TeacherIndexWrapper.CourseExposureTotal>>> courseExposure(@RequestBody TeacherIndexWrapper.CourseExposureSearch query) {
-        //获取购买的统计数据
         query.setTeacherId(sysUserService.getUserId());
-        Map<String, List<TeacherIndexWrapper.CourseExposureTotal>> stringListMap = homeService.courseBuyTotal(query);
+        Map<String, List<TeacherIndexWrapper.CourseExposureTotal>> result = new HashMap<>(2);
+        //获取购买的统计数据
+        result.put("buy", homeService.courseBuyTotal(query));
         //获取曝光的统计数据
-        stringListMap.putAll(homeService.courseExposureTotal(query));
-        return succeed(stringListMap);
+        result.put("exposure", homeService.courseExposureTotal(query));
+        return succeed(result);
+    }
+
+    @ApiOperation(value = "老师首页预计收入列表")
+    @PostMapping("/teacherIncomeList")
+    public HttpResponseResult<PageInfo<TeacherIndexWrapper.TeacherIncome>> teacherIncomeList(@RequestBody TeacherIndexWrapper.CourseExposureSearch query) {
+        query.setTeacherId(sysUserService.getUserId());
+        PageInfo<TeacherIndexWrapper.TeacherIncome> teacherIncomePageInfo = homeService.teacherIncomeList(PageUtil.getPage(query), query);
+        teacherIncomePageInfo.setStatInfo(homeService.teacherIncomeSum(query));
+        return succeed(teacherIncomePageInfo);
+    }
+
+    @PostMapping("/exportStudentPractice")
+    @ApiOperation(value = "查询导出首页练习数据学员列表")
+    public HttpResponseResult<String> exportExcel(@RequestBody TeacherIndexWrapper.StudentSearch studentSearch) {
+        studentSearch.setTeacherId(sysUserService.getUserId());
+        studentSearch.setLimit(10000);
+        List<TeacherIndexWrapper.StudentPracticeSummaryDto> teacherHomeStudent = homeService.getTeacherHomeStudent(studentSearch);
+        List<TeacherIndexWrapper.StudentPracticeSummaryExportDto> list =
+                JSON.parseArray(JSON.toJSONString(teacherHomeStudent), TeacherIndexWrapper.StudentPracticeSummaryExportDto.class);
+        DateFormat dateFormat1 = new SimpleDateFormat("yyMMddHHmmss");
+        Date date = new Date();
+        StringBuffer sb = new StringBuffer("/tmp/klx/studentPractice/");
+        sb.append(dateFormat1.format(date)).append("/练习记录")
+                .append(studentSearch.getStartTime()).append("~")
+                .append(studentSearch.getEndTime())
+                .append(studentSearch.getTeacherId()).append("_")
+                .append(System.currentTimeMillis()).append(".xlsx");
+        String filePath = sb.toString();
+        File srcFile = new File(filePath);
+        File directory = new File(filePath).getParentFile();
+        if (!directory.exists()) {
+            directory.mkdirs(); // 创建目录
+        }
+        EasyExcel.write(filePath,TeacherIndexWrapper.StudentPracticeSummaryExportDto.class).sheet("学员练习统计").doWrite(list);
+        //上传到oss
+        DateFormat dateFormatOss = new SimpleDateFormat("yyyy/MM/dd");
+        String dateStrOss = dateFormatOss.format(date);
+        dateStrOss = "klx/studentPractice/" + dateStrOss + "/" + DateUtil.getHour(date);
+        String excelFilePath = ossPluginContext.getPluginService(TencentOssPlugin.PLUGIN_NAME).uploadFile(dateStrOss, srcFile);
+        FileUtils.deleteQuietly(srcFile);
+        return HttpResponseResult.succeed(excelFilePath);
     }
 
 }

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

@@ -5,6 +5,7 @@ import com.yonge.toolset.base.enums.BaseEnum;
 
 public enum EDiscountType implements BaseEnum<String, EDiscountType> {
 
+    // 优惠券 COUPON 活动 ACTIVATY 畅学卡 DISCOUNT
     COUPON("优惠券"),
     ACTIVATY("活动"),
     DISCOUNT("畅学卡"),

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

@@ -5,6 +5,7 @@ import com.yonge.toolset.base.enums.BaseEnum;
 
 public enum ETenantAlbumCategoryType implements BaseEnum<String, ETenantAlbumCategoryType> {
 
+    // 类型 CATEGORY_TYPE 级别 CATEGORY_LEVEL
     CATEGORY_TYPE("类型"),
     CATEGORY_LEVEL("级别"),
     ;

+ 25 - 0
cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/UpdateUserVipStatusTask.java

@@ -0,0 +1,25 @@
+package com.yonge.cooleshow.task.jobs;
+
+import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.api.feign.MallPortalFeignService;
+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;
+
+/**
+ * 订单轮询
+ * @Author: liweifan
+ * @Data: 2022/4/13 17:36
+ */
+@Service
+public class UpdateUserVipStatusTask extends BaseTask {
+
+    @Autowired
+    private AdminFeignService adminFeignService;
+
+    @Override
+    public void execute() throws TaskException {
+        adminFeignService.updateUserVipStatus();
+    }
+}

+ 7 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/HomeDao.java

@@ -8,9 +8,11 @@ import com.yonge.cooleshow.biz.dal.vo.TagTotalTeacher;
 import com.yonge.cooleshow.biz.dal.vo.res.HomeTotalStudent;
 import com.yonge.cooleshow.biz.dal.vo.res.HomeTotalTeacher;
 import com.yonge.cooleshow.biz.dal.vo.res.HomeUserToDoNum;
+import com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherHomeWrapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -74,4 +76,9 @@ public interface HomeDao {
      * @return TeacherHomeWrapper.TeacherTotalCourse
      */
     List<TeacherHomeWrapper.TeacherTotalCourse> teacherTotalCourse(@Param("param") TeacherHomeWrapper.TeacherTotalCourseQuery query);
+
+    IPage<TeacherIndexWrapper.TeacherIncome> teacherIncomeList(@Param("page") IPage<TeacherIndexWrapper.TeacherIncome> page,
+                                                              @Param("param") TeacherIndexWrapper.CourseExposureSearch query);
+
+    BigDecimal teacherIncomeSum(@Param("param") TeacherIndexWrapper.CourseExposureSearch query);
 }

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

@@ -5,6 +5,7 @@ import java.util.Map;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 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.Student;
@@ -83,4 +84,7 @@ public interface StudentDao extends BaseMapper<Student> {
 
     List<StudentWrapper.UserCount> countStudentByTenantGroupIds(@Param("tenantId") Long tenantId, @Param("groupIdList") List<Long> groupIdList);
 
+    List<String> selectEntitlements(@Param("userId") Long userId);
+
+    List<Long> selectInitEntitlements(@Param("page") IPage<Object> objectPage);
 }

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

@@ -134,5 +134,8 @@ public interface TeacherDao extends BaseMapper<Teacher> {
      */
     List<StatGroupWrapper> countCustomerServiceMemberNum();
 
-    List<Long> getStudentIds(@Param("teacherId") Long teacherId, @Param("subjectId") Long subjectId);
+    List<Long> getStudentIds(@Param("teacherId") Long teacherId,
+                             @Param("subjectId") Long subjectId,
+                             @Param("startTime") String startTime,
+                             @Param("endTime") String endTime);
 }

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

@@ -62,4 +62,9 @@ public interface VipCardRecordDao extends BaseMapper<VipCardRecord> {
     IPage<VipRecordVo> selectVipRecord(@Param("page") IPage<VipRecordVo> page, @Param("param") VipRecordSearch param);
 
     List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(@Param("userIdList") List<Long> userIdList ,@Param("clientType") String clientType);
+
+    void updateMsgStatus(@Param("ids") List<Long> ids, @Param("msgStatus") int msgStatus);
+
+    IPage<VipCardRecordWrapper.VipCardRecord> selectAdminPage(@Param("page") IPage<VipCardRecordWrapper.VipCardRecord> page,
+                                                              @Param("param") VipCardRecordWrapper.VipQuery query);
 }

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/MusicAlbumSheetDto.java

@@ -1,7 +1,9 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 import java.util.List;
 
@@ -48,6 +50,7 @@ public class MusicAlbumSheetDto {
         this.albumMusicList = albumMusicList;
     }
 
+    @Data
     public static class AlbumMusic{
         @ApiModelProperty("曲目id")
         private Long musicSheetId;
@@ -55,6 +58,12 @@ public class MusicAlbumSheetDto {
         @ApiModelProperty("排序")
         private Integer sortNumber;
 
+        @ApiModelProperty(value = "级别")
+        private Long alBumCategoryLevelId;
+
+        @ApiModelProperty(value = "类型")
+        private Long alBumCategoryTypeId;
+
         public Long getMusicSheetId() {
             return musicSheetId;
         }

+ 6 - 22
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/MusicAlbumSheetSortDto.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.dto;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 /**
  * Description
@@ -9,6 +10,7 @@ import io.swagger.annotations.ApiModelProperty;
  * @author liujunchi
  * @date 2022-08-08
  */
+@Data
 @ApiModel("设置专辑中曲目的排序值")
 public class MusicAlbumSheetSortDto {
 
@@ -21,28 +23,10 @@ public class MusicAlbumSheetSortDto {
     @ApiModelProperty("排序值")
     private Integer sortNumber;
 
+    @ApiModelProperty(value = "级别")
+    private Long alBumCategoryLevelId;
 
-    public Long getAlbumId() {
-        return albumId;
-    }
 
-    public void setAlbumId(Long albumId) {
-        this.albumId = albumId;
-    }
-
-    public Long getMusicSheetId() {
-        return musicSheetId;
-    }
-
-    public void setMusicSheetId(Long musicSheetId) {
-        this.musicSheetId = musicSheetId;
-    }
-
-    public Integer getSortNumber() {
-        return sortNumber;
-    }
-
-    public void setSortNumber(Integer sortNumber) {
-        this.sortNumber = sortNumber;
-    }
+    @ApiModelProperty(value = "类型")
+    private Long alBumCategoryTypeId;
 }

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

@@ -4,6 +4,7 @@ import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.MusicSheetTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 import javax.validation.constraints.NotNull;
 import java.util.List;
@@ -15,6 +16,7 @@ import java.util.Optional;
  * @author liujunchi
  * @date 2022-03-31
  */
+@Data
 @ApiModel(value = "MusicAlbumDetailSearch", description = "专辑详情查询")
 public class MusicAlbumDetailSearch extends MusicSheetSearch {
 
@@ -45,6 +47,23 @@ public class MusicAlbumDetailSearch extends MusicSheetSearch {
     @ApiModelProperty(value = "登录学生id",hidden = true)
     private Long studentId;
 
+
+    @ApiModelProperty("专辑分类级别ID")
+    private Long albumCategoryLevelId;
+
+    @ApiModelProperty("专辑分类类型ID")
+    private Long albumCategoryTypeId;
+
+    @ApiModelProperty("是否查询分类信息")
+    private Boolean queryCategory = false;
+
+
+    @ApiModelProperty("是否查询曲目信息")
+    private Boolean queryMusicSheet = true;
+
+    @ApiModelProperty("是否查询相关专辑信息")
+    private Boolean queryRelatedAlbum = true;
+
     public Long getStudentId() {
         return studentId;
     }

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

@@ -39,6 +39,9 @@ public class MusicSheetSearch  extends QueryInfo{
     @ApiModelProperty("曲目编号/名称")
     private String idAndName;
 
+    @ApiModelProperty("曲目名称")
+    private String musicSheetName;
+
     @ApiModelProperty("标签id(多个逗号隔开)")
     private String musicTagIds;
 
@@ -58,6 +61,8 @@ public class MusicSheetSearch  extends QueryInfo{
     @ApiModelProperty(value = "提供方 TENANT 机构 PLATFORM 平台")
     private SourceTypeEnum providerType = SourceTypeEnum.PLATFORM;
 
+    @ApiModelProperty("收藏来源  TENANT 机构 PLATFORM 平台")
+    private SourceTypeEnum favoriteProviderType;
 
     @ApiModelProperty("曲目状态(0:停用,1:启用))")
     private YesOrNoEnum state;

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

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
@@ -90,6 +91,10 @@ public class StudentSearch extends QueryInfo{
     @ApiModelProperty(value = "排序方式",hidden = true)
     private String orderBy;
 
+
+    @ApiModelProperty("权益 VIP,SVIP,DISCOUNT:畅学卡,TENANT_ALBUM:训练教程 ,NORMAL:普通用户")
+    private List<String> entitlementsList;
+
     public Date getVipStartTime() {
         return vipStartTime;
     }

+ 66 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumCategory.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 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;
+
+
+/**
+ * 机构专辑分类
+ * 2024-12-19 16:57:26
+ */
+@Data
+@ApiModel(" AlbumCategory-机构专辑分类")
+@TableName("album_category")
+public class AlbumCategory implements Serializable {
+
+    @ApiModelProperty("主键ID") 
+	    @TableId(value = "id_", type = IdType.AUTO)
+	    private Long id;
+
+    @ApiModelProperty("专辑ID") 
+	@TableField(value = "album_id_")
+    private Long albumId;
+
+    @ApiModelProperty("专辑分类类别 类型 CATEGORY_TYPE 级别 CATEGORY_LEVEL") 
+	@TableField(value = "category_type_")
+    private ETenantAlbumCategoryType categoryType;
+
+    @ApiModelProperty("专辑分类名称") 
+	@TableField(value = "name_")
+    private String name;
+
+    @ApiModelProperty("排序") 
+	@TableField(value = "sort_")
+    private Integer sort;
+
+    @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;
+
+}

+ 8 - 61
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumMusicRelate.java

@@ -6,8 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import java.util.Date;
+import lombok.Data;
 
 /**
  * 专辑曲谱关联表
@@ -15,6 +14,7 @@ import java.util.Date;
  * @date 2022-03-25 23:46:28
  * @version v1.0
  **/
+@Data
 @ApiModel(value = "album_music_relate-专辑曲谱关联表")
 public class AlbumMusicRelate extends BaseEntity {
 
@@ -42,65 +42,12 @@ public class AlbumMusicRelate extends BaseEntity {
     @ApiModelProperty(value = "添加人")
     private Long createBy;  //添加人
 
+	@TableField("album_category_level_id_")
+	@ApiModelProperty(value = "级别")
+	private Long albumCategoryLevelId;
 
-	public AlbumMusicRelate setId(Long id) {
-	    this.id = id;
-	    return this;
-	}
-
-	public Long getId() {
-	    return this.id;
-	}
-
-	public AlbumMusicRelate setAlbumId(Long albumId) {
-	    this.albumId = albumId;
-	    return this;
-	}
-
-	public Long getAlbumId() {
-	    return this.albumId;
-	}
-
-	public AlbumMusicRelate setMusicSheetId(Long musicSheetId) {
-	    this.musicSheetId = musicSheetId;
-	    return this;
-	}
-
-	public Long getMusicSheetId() {
-	    return this.musicSheetId;
-	}
-
-	public AlbumMusicRelate setSortNumber(Integer sortNumber) {
-	    this.sortNumber = sortNumber;
-	    return this;
-	}
-
-	public Integer getSortNumber() {
-	    return this.sortNumber;
-	}
-
-	public AlbumMusicRelate setCreateTime(java.util.Date createTime) {
-	    this.createTime = createTime;
-	    return this;
-	}
-
-	public java.util.Date getCreateTime() {
-	    return this.createTime;
-	}
-
-	public AlbumMusicRelate setCreateBy(Long createBy) {
-	    this.createBy = createBy;
-	    return this;
-	}
-
-	public Long getCreateBy() {
-	    return this.createBy;
-	}
-
-
-    @Override
-    public String toString() {
-        return ToStringBuilder.reflectionToString(this);
-    }
+	@TableField("album_category_type_id_")
+	@ApiModelProperty(value = "类型")
+	private Long albumCategoryTypeId;
 
 }

+ 26 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/DiscountCardRecord.java

@@ -51,6 +51,16 @@ public class DiscountCardRecord implements Serializable {
 	@TableField(value = "sub_order_no_")
     private String subOrderNo;
 
+
+    @ApiModelProperty("预计开始时间")
+    @TableField(value = "estimated_start_time_")
+    private Date estimatedStartTime;
+
+    @ApiModelProperty("预计结束时间")
+    @TableField(value = "estimated_end_time_")
+    private Date estimatedEndTime;
+
+
     @ApiModelProperty("会员卡开始时间") 
 	@TableField(value = "start_time_")
     private Date startTime;
@@ -111,4 +121,20 @@ public class DiscountCardRecord implements Serializable {
 	@TableField(value = "send_msg_")
     private Boolean sendMsg;
 
+    @ApiModelProperty("扣减状态")
+    @TableField(value = "deduction_status_")
+    private EDeductionStatus deductionStatus;
+
+    @ApiModelProperty("扣减时间")
+    @TableField(value = "deduction_time_")
+    private Date deductionTime;
+
+    @ApiModelProperty("扣减原因")
+    @TableField(value = "deduction_reason_")
+    private String deductionReason;
+
+    @ApiModelProperty("扣减操作人")
+    @TableField(value = "deduction_by_")
+    private Long deductionBy;
+
 }

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

@@ -26,7 +26,7 @@ public class ImGroup implements Serializable {
     @ApiModelProperty(value = "主键;")
     private String id;
 
-    @NotBlank(message = "群名称不能为空")
+//    @NotBlank(message = "群名称不能为空")
     @TableField("name_")
     @ApiModelProperty(value = "群名称")
     private String name;

+ 6 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/Student.java

@@ -120,4 +120,10 @@ public class Student implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
     private Date discountEndTime;
 
+
+    @ApiModelProperty("权益 VIP,SVIP,DISCOUNT:畅学卡,TENANT_ALBUM:训练教程 ,NORMAL:普通用户")
+    @TableField(value = "entitlements_")
+    private String entitlements;
+
+
 }

+ 2 - 89
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/StudentCourseHomework.java

@@ -10,12 +10,14 @@ import io.swagger.annotations.ApiModelProperty;
 import java.io.Serializable;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * 学生课程作业
  */
 @TableName("student_course_homework")
+@Data
 @ApiModel(value = "StudentCourseHomework对象", description = "学生课程作业")
 public class StudentCourseHomework implements Serializable {
 	private static final long serialVersionUID = 1L;
@@ -58,93 +60,4 @@ public class StudentCourseHomework implements Serializable {
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
     private Date updateTime;
-
-	public Long getId() {
-        return id;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-    
-	public Long getCourseHomeworkId() {
-        return courseHomeworkId;
-    }
-
-    public void setCourseHomeworkId(Long courseHomeworkId) {
-        this.courseHomeworkId = courseHomeworkId;
-    }
-    
-	public String getCourseGroupType() {
-        return courseGroupType;
-    }
-
-    public void setCourseGroupType(String courseGroupType) {
-        this.courseGroupType = courseGroupType;
-    }
-    
-	public Long getCourseGroupId() {
-        return courseGroupId;
-    }
-
-    public void setCourseGroupId(Long courseGroupId) {
-        this.courseGroupId = courseGroupId;
-    }
-    
-	public Long getCourseScheduleId() {
-        return courseScheduleId;
-    }
-
-    public void setCourseScheduleId(Long courseScheduleId) {
-        this.courseScheduleId = courseScheduleId;
-    }
-    
-	public Long getStudentId() {
-        return studentId;
-    }
-
-    public void setStudentId(Long studentId) {
-        this.studentId = studentId;
-    }
-    
-	public String getAttachments() {
-        return attachments;
-    }
-
-    public void setAttachments(String attachments) {
-        this.attachments = attachments;
-    }
-    
-	public String getTeacherReplied() {
-        return teacherReplied;
-    }
-
-    public void setTeacherReplied(String teacherReplied) {
-        this.teacherReplied = teacherReplied;
-    }
-    
-	public Date getSubmitTime() {
-        return submitTime;
-    }
-
-    public void setSubmitTime(Date submitTime) {
-        this.submitTime = submitTime;
-    }
-    
-	public Date getCreateTime() {
-        return createTime;
-    }
-
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
-    
-	public Date getUpdateTime() {
-        return updateTime;
-    }
-
-    public void setUpdateTime(Date updateTime) {
-        this.updateTime = updateTime;
-    }
-    
 }

+ 33 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserTenantAlbumRecord.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EDeductionStatus;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import lombok.Data;
 
@@ -33,8 +34,6 @@ public class UserTenantAlbumRecord implements Serializable {
 	@TableField(value = "user_id_")
     private Long userId;
 
-
-
     @ApiModelProperty("机构ID")
     @TableField(value = "tenant_id_")
     private Long tenantId;
@@ -59,6 +58,16 @@ public class UserTenantAlbumRecord implements Serializable {
 	@TableField(value = "sub_order_no_")
     private String subOrderNo;
 
+
+
+    @ApiModelProperty("预计开始时间")
+    @TableField(value = "estimated_start_time_")
+    private Date estimatedStartTime;
+
+    @ApiModelProperty("预计结束时间")
+    @TableField(value = "estimated_end_time_")
+    private Date estimatedEndTime;
+
     @ApiModelProperty("开始时间") 
 	@TableField(value = "start_time_")
     private Date startTime;
@@ -87,12 +96,32 @@ public class UserTenantAlbumRecord implements Serializable {
 	@TableField(value = "times_")
     private Integer times;
 
-    @ApiModelProperty("消息发送 0、未发送 1、已发送提前3天消息 2、已发送会员过期消息 暂时不用") 
+    @ApiModelProperty("消息发送 0、未发送 1、已发送提前3天消息 2、已发送会员过期消息")
 	@TableField(value = "msg_status_")
-    private Boolean msgStatus;
+    private Integer msgStatus;
 
     @ApiModelProperty("备注") 
 	@TableField(value = "reason_")
     private String reason;
 
+    @ApiModelProperty("是否有效 1:有效,0:失效")
+    @TableField(value = "efficient_flag_")
+    private Boolean efficientFlag;
+
+    @ApiModelProperty("扣减状态")
+    @TableField(value = "deduction_status_")
+    private EDeductionStatus deductionStatus;
+
+    @ApiModelProperty("扣减时间")
+    @TableField(value = "deduction_time_")
+    private Date deductionTime;
+
+    @ApiModelProperty("扣减原因")
+    @TableField(value = "deduction_reason_")
+    private String deductionReason;
+
+    @ApiModelProperty("扣减操作人")
+    @TableField(value = "deduction_by_")
+    private Long deductionBy;
+
 }

+ 31 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/VipCardRecord.java

@@ -54,6 +54,16 @@ public class VipCardRecord implements Serializable {
     @TableField(value = "source_type_")
     private SourceTypeEnum sourceType;
 
+
+
+    @ApiModelProperty("预计开始时间")
+    @TableField(value = "estimated_start_time_")
+    private Date estimatedStartTime;
+
+    @ApiModelProperty("预计结束时间")
+    @TableField(value = "estimated_end_time_")
+    private Date estimatedEndTime;
+
     @ApiModelProperty("会员卡开始时间 ")
 	@TableField(value = "start_time_")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -114,4 +124,25 @@ public class VipCardRecord implements Serializable {
     @TableField(value = "send_msg_")
     private Boolean sendMsg;
 
+    @ApiModelProperty("扣减状态")
+    @TableField(value = "deduction_status_")
+    private EDeductionStatus deductionStatus;
+
+    @ApiModelProperty("扣减时间")
+    @TableField(value = "deduction_time_")
+    private Date deductionTime;
+
+    @ApiModelProperty("扣减原因")
+    @TableField(value = "deduction_reason_")
+    private String deductionReason;
+
+    @ApiModelProperty("扣减操作人")
+    @TableField(value = "deduction_by_")
+    private Long deductionBy;
+
+
+    @ApiModelProperty("版本")
+    @TableField(value = "version_")
+    private Integer version;
+
 }

+ 45 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EDeductionStatus.java

@@ -0,0 +1,45 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ *
+ *
+ * @author: liujunchi
+ * @date: 2022-03-30
+ */
+public enum EDeductionStatus implements BaseEnum<String, EDeductionStatus> {
+
+    // 生效中:EFFECTIVE 过期 EXPIRED 扣减 DEDUCT
+    /**
+     *
+     * 生效中
+     */
+    EFFECTIVE("生效中"),
+    /**
+     * 过期
+     */
+    EXPIRED("过期"),
+    //  扣除
+    DEDUCT("扣除")
+
+;
+    @EnumValue
+    private String code;
+    private String msg;
+
+    EDeductionStatus(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    public String getMsg() {
+        return this.msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+}

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

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+
+public enum EStudentEntitlements implements BaseEnum<String, EStudentEntitlements> {
+
+    //权益 VIP,SVIP,DISCOUNT:畅学卡,TENANT_ALBUM:训练教程 ,NORMAL:普通用户
+    VIP("VIP"),
+    SVIP("SVIP"),
+    DISCOUNT("畅学卡"),
+    TENANT_ALBUM("训练教程"),
+    NORMAL("普通用户"),
+
+    ;
+    @EnumValue
+    private String code;
+    private String msg;
+
+    EStudentEntitlements(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return this.msg;
+    }
+}

+ 20 - 5
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java

@@ -82,10 +82,19 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     SMS_NEW_VIP_BUY_SUCCESS("会员购买成功(短信)"),
     SMS_TEACHER_NEW_VIP_BUY_SUCCESS("会员购买成功(短信)"),
 
-    VIP_EXPIRE_THIRTY_DAY("VIP会员到期前30天"),
-    SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前30天"),
-    SMS_VIP_EXPIRE_THIRTY_DAY("VIP会员到期前30天(短信)"),
-    SMS_SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前30天(短信)"),
+    DISCOUNT_EXPIRE_THIRTY_DAY("畅学卡到期前3天"),
+
+    TEACHER_VIP_EXPIRE_THIRTY_DAY("VIP会员到期前3天"),
+    TEACHER_SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前3天"),
+    VIP_EXPIRE_THIRTY_DAY("VIP会员到期前3天"),
+    SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前3天"),
+    SMS_VIP_EXPIRE_THIRTY_DAY("VIP会员到期前3天(短信)"),
+    SMS_SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前3天(短信)"),
+
+    DISCOUNT_EXPIRE("畅学卡到期"),
+
+    TEACHER_VIP_EXPIRE("VIP会员到期"),
+    TEACHER_SVIP_EXPIRE("SVIP会员到期"),
 
     VIP_EXPIRE("VIP会员到期"),
     SVIP_EXPIRE("SVIP会员到期"),
@@ -159,7 +168,8 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     TENANT_VIP_EXPIRE("平台会员到期"),
     TENANT_PLATFORM_ADD_VIP("后台添加平台会员"),
     TENANT_ALBUM_BUY("购买训练教程"),
-    TENANT_ALBUM_EXPIRE("训练教程到期"),
+    TENANT_ALBUM_EXPIRE("训练教程即将到期"),
+    TENANT_ALBUM_EXPIRE_THIRTY_DAY("训练教程3天后到期"),
     TENANT_SEND_CODE("发放激活码"),
     TENANT_CODE_SENDCANCEL("激活码被撤回"),
     TENANT_MUSIC_BUY("购买曲目"),
@@ -185,6 +195,11 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     GROUP_SUCCESS_TEACHER("小组课已成课"),
     GROUP_FAIL_STUDENT("小组课成课失败"),
     GROUP_FAIL_TEACHER("小组课成课失败"),
+    DEDUCTION_DISCOUNT_SMS("扣减畅学卡"),
+    ADD_DISCOUNT_SMS("添加畅学卡"),
+    PAY_DISCOUNT_JG("购买畅学卡"),
+    DEDUCTION_TENANT_ALBUM_JG("扣减畅学卡"),
+    ADD_TENANT_ALBUM_JG("添加畅学卡"),
     ;
 
     MessageTypeEnum(String msg) {

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

@@ -8,8 +8,8 @@ import com.yonge.toolset.base.enums.BaseEnum;
  */
 public enum PeriodEnum implements BaseEnum<String, PeriodEnum> {
     // DAY 日 MONTH 月 QUARTERLY 季度 YEAR_HALF 半年 YEAR 年
-	DAY(""),
-	MONTH("月"),
+	DAY(""),
+	MONTH("月"),
 	QUARTERLY("季度"),
 	YEAR_HALF("半年"),
 	YEAR("年"),

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

@@ -11,6 +11,8 @@ import com.yonge.toolset.base.enums.BaseEnum;
  */
 public enum SourceTypeEnum implements BaseEnum<String, AuditStatusEnum> {
 
+
+    // 后台扣减 PLATFORM_DEDUCT,活动 ACTIVITY ,订单 ORDER,后台赠送 BACKEND_GIVE
     TEACHER("老师"),
 
     // 机构,机构自己上传曲目 , 暂时没有

+ 24 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/AlbumCategoryMapper.java

@@ -0,0 +1,24 @@
+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.AlbumCategory;
+import com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper;
+
+/**
+ * 机构专辑分类
+ * 2024-12-19 16:57:26
+ */
+@Repository
+public interface AlbumCategoryMapper extends BaseMapper<AlbumCategory> {
+
+	/**
+	 * 分页查询
+	 */
+	List<AlbumCategoryWrapper.AlbumCategory> selectPage(@Param("page") IPage<AlbumCategoryWrapper.AlbumCategory> page, @Param("param") AlbumCategoryWrapper.AlbumCategoryQuery param);
+	
+}

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/DiscountCardRecordMapper.java

@@ -1,10 +1,12 @@
 package com.yonge.cooleshow.biz.dal.mapper;
 
+import java.util.Date;
 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.MemberPriceSettings;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 import com.yonge.cooleshow.biz.dal.entity.DiscountCardRecord;
@@ -17,4 +19,11 @@ import com.yonge.cooleshow.biz.dal.entity.DiscountCardRecord;
 public interface DiscountCardRecordMapper extends BaseMapper<DiscountCardRecord> {
 
     MemberPriceSettings detail(@Param("userId") Long userId, @Param("orderDetilId") Long orderDetilId);
+
+    IPage<DiscountCardRecordWrapper.DiscountCardRecord> selectPage(@Param("page") IPage<DiscountCardRecordWrapper.DiscountCardRecord> page,
+                                                                   @Param("param") DiscountCardRecordWrapper.DiscountCardRecordQuery query);
+
+    void updateUserDiscountTime(@Param("userId") Long userId, @Param("startTime") Date startTime, @Param("endTime") Date endTime);
+
+    void updateMsgStatus(@Param("ids") List<Long> ids, @Param("msgStatus") int msgStatus);
 }

+ 7 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantAlbumRecordMapper.java

@@ -40,5 +40,12 @@ public interface UserTenantAlbumRecordMapper extends BaseMapper<UserTenantAlbumR
 
     List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> selectTemporaryRecord();
 
+    List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> selectTemporaryRecord1();
+
     List<TenantGroupAlbumWrapper.TenantAlbumSort> getTenantAlbumMaxCreateTime(@Param("userId") Long userId, @Param("clientType") ClientEnum clientType, @Param("tenantAlbumIds") List<Long> tenantAlbumIds);
+
+    void updateMsgStatus(@Param("ids") List<Long> ids, @Param("msgStatus") int msgStatus);
+
+    List<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> selectAdminPage(@Param("page") IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> page,
+                                                                                  @Param("param") UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query);
 }

+ 42 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/AlbumCategoryService.java

@@ -0,0 +1,42 @@
+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.AlbumCategoryWrapper;
+import com.yonge.cooleshow.biz.dal.entity.AlbumCategory;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 机构专辑分类
+ * 2024-12-19 16:57:26
+ */
+public interface AlbumCategoryService extends IService<AlbumCategory>  {
+
+
+    /**
+     * 分页查询
+     * @param page IPage<AlbumCategory>
+     * @param query AlbumCategoryWrapper.AlbumCategoryQuery
+     * @return IPage<AlbumCategory>
+     */
+    IPage<AlbumCategoryWrapper.AlbumCategory> selectPage(IPage<AlbumCategoryWrapper.AlbumCategory> page, AlbumCategoryWrapper.AlbumCategoryQuery query);
+
+
+    /**
+     * 新增/修改
+     * @param albumCategory
+     */
+    void add(AlbumCategoryWrapper.AddAlbumCategory albumCategory);
+
+    /**
+     * 删除
+     *
+     * @param id
+     *
+     */
+    Boolean del(Long id);
+
+    Map<Long,AlbumCategory> getMapByIds(List<Long> albumCategoryIds);
+}

+ 21 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/DiscountCardRecordService.java

@@ -1,8 +1,10 @@
 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.DiscountCardRecord;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 
 /**
  * 购买会员卡记录表
@@ -12,4 +14,23 @@ public interface DiscountCardRecordService extends IService<DiscountCardRecord>
 
 
     void orderSuccess(UserOrderDetailVo userPaymentOrder);
+
+
+    void addStudentVip(DiscountCardRecordWrapper.AddDiscountCardRecord result);
+
+    IPage<DiscountCardRecordWrapper.DiscountCardRecord> selectPage(IPage<DiscountCardRecordWrapper.DiscountCardRecord> page, DiscountCardRecordWrapper.DiscountCardRecordQuery query);
+
+    /**
+     * 获取剩余时长
+     *
+     */
+    DiscountCardRecordWrapper.Info info(DiscountCardRecordWrapper.InfoQuery infoQuery);
+
+    /**
+     * 扣减畅学卡
+     *
+     */
+    void deduction(DiscountCardRecordWrapper.DeductionDiscountCardRecord result);
+
+    void pollExpireMsg();
 }

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

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.dto.SubjectHomeSearch;
 import com.yonge.cooleshow.biz.dal.dto.req.TotalReq;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeVo;
+import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.SubjectHomeVo;
 import com.yonge.cooleshow.biz.dal.vo.res.HomeTotalStudent;
 import com.yonge.cooleshow.biz.dal.vo.res.HomeTotalTeacher;
@@ -13,6 +14,7 @@ import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherHomeWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.page.PageInfo;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
@@ -87,7 +89,11 @@ public interface HomeService {
 
     List<TeacherIndexWrapper.StudentPracticeSummaryDto> getTeacherHomeStudent(TeacherIndexWrapper.StudentSearch studentSearch);
 
-    Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> courseExposureTotal(TeacherIndexWrapper.CourseExposureSearch query);
+    List<TeacherIndexWrapper.CourseExposureTotal> courseExposureTotal(TeacherIndexWrapper.CourseExposureSearch query);
 
-    Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> courseBuyTotal(TeacherIndexWrapper.CourseExposureSearch query);
+    List<TeacherIndexWrapper.CourseExposureTotal> courseBuyTotal(TeacherIndexWrapper.CourseExposureSearch query);
+
+    PageInfo<TeacherIndexWrapper.TeacherIncome> teacherIncomeList(IPage<TeacherIndexWrapper.TeacherIncome> page,TeacherIndexWrapper.CourseExposureSearch query);
+
+    BigDecimal teacherIncomeSum(TeacherIndexWrapper.CourseExposureSearch query);
 }

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

@@ -17,6 +17,7 @@ import com.yonge.cooleshow.biz.dal.enums.RoleEnum;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import io.rong.models.Result;
 
+import javax.validation.Valid;
 import java.io.File;
 import java.util.List;
 import java.util.Set;
@@ -221,5 +222,7 @@ public interface ImGroupService extends IService<ImGroup> {
     void groupAvatarUpdate();
 
     Boolean muteAll(ImGroupWrapper.Mute mute);
+
+    Boolean updateIntroduce( ImGroup imGroup);
 }
 

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

@@ -143,4 +143,8 @@ public interface StudentService extends IService<Student> {
     String updateUserCustomerService(SysUser user);
 
     StudentIndexWrapper.SummaryDto indexSummary(Long userId);
+
+    void updateVipStatus(Long userId);
+
+    void initEntitlements();
 }

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

@@ -2,8 +2,6 @@ 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.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;
@@ -39,7 +37,7 @@ public interface UserTenantAlbumRecordService extends IService<UserTenantAlbumRe
      * @param userTenantAlbumRecord UserTenantAlbumRecordWrapper.UserTenantAlbumRecord
      * @return Boolean
      */
-     Boolean add(UserTenantAlbumRecord userTenantAlbumRecord);
+     Boolean add(UserTenantAlbumRecord userTenantAlbumRecord,boolean sendMsg);
 
     /**
      * 更新
@@ -86,4 +84,15 @@ public interface UserTenantAlbumRecordService extends IService<UserTenantAlbumRe
     UserTenantAlbumRecord getNewestByTenantAlbumId(Long tenantAlbumId, Long userId, ClientEnum client);
 
     List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> list(UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query);
+
+    /**
+     * 扣除用户专辑记录
+     *
+     * @return
+     */
+    void deduction(UserTenantAlbumRecordWrapper.DeductionUserTenantAlbumRecord result);
+
+    IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> selectAdminPage(IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> page, UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query);
+
+    List<UserTenantAlbumRecordWrapper.Info> info(UserTenantAlbumRecordWrapper.InfoQuery infoQuery);
 }

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

@@ -119,4 +119,22 @@ public interface VipCardRecordService extends IService<VipCardRecord> {
     VipCardRecord addVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord);
 
     List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(List<Long> userIdList , String clientType);
+
+    /**
+     * 扣减会员
+     *
+     * @param deductionVipCardRecord
+     */
+    void deduction(VipCardRecordWrapper.DeductionVipCardRecord deductionVipCardRecord);
+
+    /**
+     *
+     *  获取会员信息
+     *
+     */
+    VipCardRecordWrapper.Info info(VipCardRecordWrapper.InfoQuery infoQuery);
+
+    IPage<VipCardRecordWrapper.VipCardRecord> selectAdminPage(IPage<VipCardRecordWrapper.VipCardRecord> page, VipCardRecordWrapper.VipQuery query);
+
+    List<Long> updateUserVipStatus();
 }

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

@@ -0,0 +1,96 @@
+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.yonge.cooleshow.biz.dal.entity.AlbumMusicRelate;
+import com.yonge.cooleshow.biz.dal.entity.MusicAlbum;
+import com.yonge.cooleshow.biz.dal.service.AlbumMusicRelateService;
+import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
+import com.yonge.toolset.base.exception.BizException;
+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.AlbumCategory;
+import com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper;
+import com.yonge.cooleshow.biz.dal.mapper.AlbumCategoryMapper;
+import com.yonge.cooleshow.biz.dal.service.AlbumCategoryService;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 机构专辑分类
+ * 2024-12-19 16:57:26
+ */
+@Slf4j
+@Service
+public class AlbumCategoryServiceImpl extends ServiceImpl<AlbumCategoryMapper, AlbumCategory> implements AlbumCategoryService {
+
+    @Autowired
+    private MusicAlbumService musicAlbumService;
+
+    @Autowired
+    private AlbumMusicRelateService albumMusicRelateService;
+    
+    /**
+     * 分页查询
+     * @param page IPage<AlbumCategory>
+     * @param query AlbumCategoryWrapper.AlbumCategoryQuery
+     * @return IPage<AlbumCategory>
+     */
+    @Override
+    public IPage<AlbumCategoryWrapper.AlbumCategory> selectPage(IPage<AlbumCategoryWrapper.AlbumCategory> page, AlbumCategoryWrapper.AlbumCategoryQuery query) {
+        
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void add(AlbumCategoryWrapper.AddAlbumCategory albumCategory) {
+        MusicAlbum musicAlbum = musicAlbumService.getById(albumCategory.getAlbumId());
+        if (musicAlbum == null) {
+            throw new BizException("专辑不存在");
+        }
+        AlbumCategory entity = JSON.parseObject(albumCategory.jsonString(), AlbumCategory.class);
+        entity.setUpdateBy(albumCategory.getOperatorId());
+        if (entity.getId() == null) {
+            entity.setCreateBy(albumCategory.getOperatorId());
+        }
+        this.saveOrUpdate(entity);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean del(Long id) {
+
+        // 判断是否被使用
+        Integer count = albumMusicRelateService.lambdaQuery()
+                .and(o -> o.eq(AlbumMusicRelate::getAlbumCategoryLevelId, id).or().eq(AlbumMusicRelate::getAlbumCategoryTypeId, id))
+                .count();
+        if (count > 0) {
+            throw new BizException("已被使用,不可删除");
+        }
+
+        return this.removeById(id);
+
+    }
+
+    @Override
+    public Map<Long, AlbumCategory> getMapByIds(List<Long> albumCategoryIds) {
+
+        if (CollectionUtils.isEmpty(albumCategoryIds)) {
+            return Collections.emptyMap();
+        }
+        Collection<AlbumCategory> albumCategories = listByIds(albumCategoryIds);
+        return albumCategories.stream().collect(Collectors.toMap(AlbumCategory::getId, albumCategory -> albumCategory));
+
+    }
+
+}

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

@@ -68,6 +68,8 @@ public class AlbumMusicRelateServiceImpl extends ServiceImpl<AlbumMusicRelateDao
             albumMusicRelate.setAlbumId(albumId);
             albumMusicRelate.setMusicSheetId(albumMusic.getMusicSheetId());
             albumMusicRelate.setSortNumber(albumMusic.getSortNumber());
+            albumMusicRelate.setAlbumCategoryLevelId(albumMusic.getAlBumCategoryLevelId());
+            albumMusicRelate.setAlbumCategoryTypeId(albumMusic.getAlBumCategoryTypeId());
             albumMusicRelate.setCreateTime(new Date());
             albumMusicRelate.setCreateBy(userId);
             return albumMusicRelate;

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

@@ -586,6 +586,10 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
 
     // 检查时间段是否满足课程时间,不满足则删除,满足 并且可多段的情况下,将时间段拆分
     private List<CourseTimeEntity> splitTime(List<CourseTimeEntity> courseTime, Integer courseMinutes,Integer freeMinutes) {
+
+        //过滤掉当前时间之前的时间段
+        courseTime = courseTime.stream().filter(time -> time.getStartTime().compareTo(new Date()) >= 0).collect(Collectors.toList());
+
         Integer mergeMinutes = courseMinutes + freeMinutes;
         List<CourseTimeEntity> result = new ArrayList<>();
         for (CourseTimeEntity courseTimeEntity : courseTime) {

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

@@ -1,31 +1,34 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import cn.hutool.core.thread.ThreadUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.yonge.cooleshow.biz.dal.entity.DiscountCardRecord;
-import com.yonge.cooleshow.biz.dal.entity.Student;
-import com.yonge.cooleshow.biz.dal.enums.EVipRecordStatus;
-import com.yonge.cooleshow.biz.dal.enums.EVipType;
-import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.mapper.DiscountCardRecordMapper;
-import com.yonge.cooleshow.biz.dal.service.DiscountCardRecordService;
-import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
-import com.yonge.cooleshow.biz.dal.service.StudentService;
-import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.MemberPriceSettingsVo;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
-import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
+import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.date.DateUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.time.LocalDate;
+import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
-import java.util.Date;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum.PAY_DISCOUNT_JG;
 
 /**
  * 购买会员卡记录表
@@ -35,11 +38,14 @@ import java.util.Date;
 @Service
 public class DiscountCardRecordServiceImpl extends ServiceImpl<DiscountCardRecordMapper, DiscountCardRecord> implements DiscountCardRecordService {
 
-    @Autowired
+    @Resource
     private MemberPriceSettingsService memberPriceSettingsService;
-
-    @Autowired
+    @Resource
     private StudentService studentService;
+    @Resource
+    private SysUserService sysUserService;
+    @Resource
+    private SysMessageService sysMessageService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -53,64 +59,388 @@ public class DiscountCardRecordServiceImpl extends ServiceImpl<DiscountCardRecor
             return;
         }
 
-
-        DiscountCardRecord discountCardRecord = new DiscountCardRecord();
+        DiscountCardRecordWrapper.DiscountCardRecordChange discountCardRecord = new DiscountCardRecordWrapper.DiscountCardRecordChange();
         discountCardRecord.setUserId(orderDetailVo.getUserId());
         discountCardRecord.setVipCardId(orderDetailVo.getBizId());
         discountCardRecord.setOrderNo(orderDetailVo.getOrderNo());
         discountCardRecord.setSourceType(SourceTypeEnum.ORDER);
         discountCardRecord.setClientType(orderDetailVo.getOrderClient());
         discountCardRecord.setSubOrderNo(orderDetailVo.getSubOrderNo());
-        discountCardRecord.setCreateBy(orderDetailVo.getUserId());
         discountCardRecord.setType(detail.getPeriod());
+        discountCardRecord.setCreateBy(orderDetailVo.getUserId());
         discountCardRecord.setTimes(orderDetailVo.getGoodNum());
-        discountCardRecord.setVipType(detail.getVipType());
+        discountCardRecord.setStatus(EVipRecordStatus.ADD);
+
+        addStudentDiscount(discountCardRecord);
+
+        // 购买成功推送
+        com.yonge.cooleshow.auth.api.entity.SysUser sysUser = sysUserService.getByUserId(discountCardRecord.getUserId());
+        if (sysUser == null) {
+            return;
+        }
+
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(sysUser.getId(), sysUser.getPhone());
+
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, PAY_DISCOUNT_JG,receivers,
+                    null,0,null,ClientEnum.STUDENT.name()
+                    ,discountCardRecord.getTimes());
+        } catch (Exception e) {
+            log.error("消息发送失败 ", e);
+        }
+    }
+
+
+    private List<DiscountCardRecord> usedDiscountCardRecordList(Long userId) {
+        return this.lambdaQuery()
+                .eq(DiscountCardRecord::getUserId, userId)
+                .eq(DiscountCardRecord::getEfficientFlag, 1)
+                .gt(DiscountCardRecord::getEndTime, new Date())
+                .list();
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void addStudentVip(DiscountCardRecordWrapper.AddDiscountCardRecord result) {
+        DiscountCardRecordWrapper.DiscountCardRecordChange discountCardRecordChange = JSON.parseObject(JSON.toJSONString(result), DiscountCardRecordWrapper.DiscountCardRecordChange.class);
+        discountCardRecordChange.setSourceType(SourceTypeEnum.BACKEND_GIVE);
+        addStudentDiscount(discountCardRecordChange);
+
+        if (Boolean.TRUE.equals(result.getSendMsg())) {
+            ThreadUtil.execute(() -> sendVipDeductionMessage(result.getUserId(),result.getTimes(),result.getType(),result.getReason()));
+        }
+    }
+
+    private void sendVipDeductionMessage(Long userId, Integer num,PeriodEnum period,String reason) {
+        // 添加VIP时长短信
+        com.yonge.cooleshow.auth.api.entity.SysUser sysUser = sysUserService.getByUserId(userId);
+        if (sysUser == null) {
+            return;
+        }
+
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(sysUser.getId(), sysUser.getPhone());
+
+
+        // 短信
+        MessageTypeEnum messageTypeEnum = MessageTypeEnum.ADD_DISCOUNT_SMS;
+        if (num < 0) {
+            messageTypeEnum = MessageTypeEnum.DEDUCTION_DISCOUNT_SMS;
+        }
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, messageTypeEnum,receivers,
+                    null,0,null,ClientEnum.STUDENT.name()
+                    ,Math.abs(num) + period.getMsg(),reason);
+        } catch (Exception e) {
+            log.error("消息发送失败 ", e);
+        }
+    }
+
+    public int deductionStudentDiscount(DiscountCardRecordWrapper.DeductionDiscountCardRecord result) {
+
+        // 查找被扣除的记录
+        DiscountCardRecord record = this.getById(result.getRecordId());
+        if (record == null) {
+            throw new BizException("记录不存在");
+        }
+        if (record.getDeductionTime() != null) {
+            throw new BizException("记录已扣除");
+        }
+        Date endTime = record.getEndTime();
+        if (endTime.before(new Date())) {
+            throw new BizException("记录已过期");
+        }
+
+        // 获取 剩余时长
+        int days =0;
+        if (record.getStartTime().before(new Date())) {
+            days = DateUtil.daysBetweenUp(new Date(), endTime);
+        } else {
+            days = DateUtil.daysBetweenUp(record.getStartTime(), endTime);
+        }
+        DiscountCardRecord deductionRecord = new DiscountCardRecord();
+        deductionRecord.setId(record.getId());
+        deductionRecord.setDeductionTime(new Date());
+        deductionRecord.setDeductionReason(result.getReason());
+        deductionRecord.setEndTime(addTime(record.getEndTime(), PeriodEnum.DAY, -days,1));
+        deductionRecord.setDeductionBy(result.getCreateBy());
+        deductionRecord.setDeductionStatus(EDeductionStatus.DEDUCT);
+        if (record.getStartTime().after(deductionRecord.getEndTime())) {
+            deductionRecord.setEfficientFlag(false);
+        }
+        this.updateById(deductionRecord);
+
+        // 对比剩余天数
+
+        // 获取其他有效的记录
+        List<DiscountCardRecord> list = this.lambdaQuery()
+                .eq(DiscountCardRecord::getUserId, record.getUserId())
+                .gt(DiscountCardRecord::getEndTime, endTime)
+                .eq(DiscountCardRecord::getEfficientFlag, 1)
+                .list();
+
+        if (CollectionUtils.isEmpty(list)) {
+            return days;
+        }
+        Date startTime = record.getStartTime();
+        if (startTime.after(new Date())) {
+            startTime = addTime(startTime, PeriodEnum.DAY, -1,1);
+        } else {
+            startTime = addTime(new Date(), PeriodEnum.DAY, -1,1);
+        }
+        List<DiscountCardRecord> updateList = new ArrayList<>();
+        for (DiscountCardRecord discountCardRecord : list) {
+            DiscountCardRecord cardRecord = new DiscountCardRecord();
+            cardRecord.setId(discountCardRecord.getId());
+            cardRecord.setStartTime(startTime);
+            cardRecord.setEndTime(addTime(cardRecord.getStartTime(), discountCardRecord.getType(), discountCardRecord.getTimes(), 1));
+            formatVipRecordTime(cardRecord);
+            updateList.add(cardRecord);
+            startTime = cardRecord.getEndTime();
+        }
+        this.updateBatchById(updateList);
+
+
+        return days;
+
+    }
+
+
+    private Long addStudentDiscount(DiscountCardRecordWrapper.DiscountCardRecordChange result) {
+
+
+        DiscountCardRecord discountCardRecord = new DiscountCardRecord();
+        discountCardRecord.setUserId(result.getUserId());
+        discountCardRecord.setVipCardId(result.getVipCardId());
+        discountCardRecord.setOrderNo(result.getOrderNo());
+        discountCardRecord.setSourceType(result.getSourceType());
+        discountCardRecord.setClientType(ClientEnum.STUDENT);
+        discountCardRecord.setSubOrderNo(result.getSubOrderNo());
+        discountCardRecord.setCreateBy(result.getCreateBy());
+        discountCardRecord.setType(result.getType());
+        discountCardRecord.setTimes(result.getTimes());
+        discountCardRecord.setReason(result.getReason());
+        discountCardRecord.setVipType(EVipType.DISCOUNT);
         discountCardRecord.setStatus(EVipRecordStatus.ADD);
         discountCardRecord.setDisplayFlag(true);
         discountCardRecord.setEfficientFlag(true);
-        discountCardRecord.setSendMsg(false);
-
-        // 设置时间
-        Student student = studentService.getById(orderDetailVo.getUserId());
-        LocalDate startTime = LocalDate.now();
-        if (student.getDiscountEndTime() != null && student.getDiscountEndTime().after(new Date())) {
-            startTime = student.getDiscountEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
-        }
-        LocalDate endTime = LocalDate.now();
-
-        switch (discountCardRecord.getType()) {
-            case DAY:
-                endTime = startTime.plusDays(discountCardRecord.getTimes());
-                break;
-            case MONTH:
-                endTime = startTime.plusMonths(discountCardRecord.getTimes());
-                break;
-            case QUARTERLY:
-                endTime = startTime.plusMonths(discountCardRecord.getTimes() * 3L);
-                break;
-            case YEAR_HALF:
-                endTime = startTime.plusMonths(discountCardRecord.getTimes() * 6L);
-                break;
-            case YEAR:
-                endTime = startTime.plusYears(discountCardRecord.getTimes());
-                break;
-            default:
-                log.error("时间类型错误{}", discountCardRecord.getType());
-        }
-        if (startTime.isAfter(LocalDate.now())) {
-            startTime = startTime.plusDays(1);
+
+        // 设置开始时间
+        List<DiscountCardRecord> discountCardRecords = usedDiscountCardRecordList(result.getUserId());
+        if (CollectionUtils.isNotEmpty(discountCardRecords)) {
+            discountCardRecord.setStartTime(discountCardRecords.stream().max(Comparator.comparing(DiscountCardRecord::getEndTime)).get().getEndTime());
+        } else {
+            discountCardRecord.setStartTime(new Date());
         }
-        discountCardRecord.setStartTime(DateUtil.localDateTimeToDate(startTime.atTime(LocalTime.MIN)));
-        discountCardRecord.setEndTime(DateUtil.localDateTimeToDate(endTime.atTime(23,59,59)));
 
+        discountCardRecord.setEndTime(addTime(discountCardRecord.getStartTime(), discountCardRecord.getType(), discountCardRecord.getTimes(),1));
+        formatVipRecordTime(discountCardRecord);
+        discountCardRecord.setEstimatedEndTime(discountCardRecord.getEndTime());
+        discountCardRecord.setEstimatedStartTime(discountCardRecord.getStartTime());
         this.save(discountCardRecord);
 
+        updateUserTime(discountCardRecord.getUserId(),discountCardRecord.getClientType());
+
+
+        return discountCardRecord.getId();
+    }
+
+    private void updateUserTime(Long userId, ClientEnum clientType) {
+
+        // 设置开始时间
+        List<DiscountCardRecord> discountCardRecords = usedDiscountCardRecordList(userId);
+        Date endTime = null;
+        Date startTime = null;
+        if (CollectionUtils.isNotEmpty(discountCardRecords)) {
+            endTime = discountCardRecords.stream().max(Comparator.comparing(DiscountCardRecord::getEndTime)).get().getEndTime();
+            startTime = discountCardRecords.stream().min(Comparator.comparing(DiscountCardRecord::getStartTime)).get().getStartTime();
+        }
+
         // 更新学生时长
-        studentService.lambdaUpdate()
-                .set(Student::getDiscountEndTime, discountCardRecord.getEndTime())
-                .set(student.getDiscountStartTime() == null,Student::getDiscountStartTime, discountCardRecord.getStartTime())
-                .eq(Student::getUserId, orderDetailVo.getUserId())
-                .update();
+        baseMapper.updateUserDiscountTime(userId, startTime, endTime);
+
+
+        studentService.updateVipStatus(userId);
+    }
+
+    @Override
+    public IPage<DiscountCardRecordWrapper.DiscountCardRecord> selectPage(IPage<DiscountCardRecordWrapper.DiscountCardRecord> page, DiscountCardRecordWrapper.DiscountCardRecordQuery query) {
+        IPage<DiscountCardRecordWrapper.DiscountCardRecord> discountCardRecordIPage = baseMapper.selectPage(page, query);
+        List<DiscountCardRecordWrapper.DiscountCardRecord> records = discountCardRecordIPage.getRecords();
+        if (CollectionUtils.isEmpty(records)) {
+            return discountCardRecordIPage;
+        }
+        // 创建人ID集合
+        List<Long> createByList = records.stream()
+                .map(DiscountCardRecordWrapper.DiscountCardRecord::getOperatorId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<Long, SysUser> userMap = sysUserService.getMapByIds(createByList);
+        records.forEach(discountCardRecord -> {
+
+
+            if (discountCardRecord.getStartTime().before(new Date())) {
+                discountCardRecord.setSurplusDay(DateUtil.daysBetweenUp(new Date(), discountCardRecord.getEndTime()));
+            } else {
+                discountCardRecord.setSurplusDay(DateUtil.daysBetweenUp(discountCardRecord.getStartTime(), discountCardRecord.getEndTime()));
+            }
+
+            SysUser sysUser = userMap.get(discountCardRecord.getOperatorId());
+            if (sysUser != null) {
+                discountCardRecord.setOperatorName(sysUser.getRealName());
+            }
+        });
+        return discountCardRecordIPage;
+    }
 
+
+    /**
+     * 获取剩余时长
+     *
+     */
+    @Override
+    public DiscountCardRecordWrapper.Info info(DiscountCardRecordWrapper.InfoQuery infoQuery) {
+        DiscountCardRecordWrapper.Info info = new DiscountCardRecordWrapper.Info();
+
+        List<DiscountCardRecord> discountCardRecords = usedDiscountCardRecordList(infoQuery.getUserId());
+        if (CollectionUtils.isEmpty(discountCardRecords)) {
+            return info;
+        }
+
+        // 最大时间
+        DiscountCardRecord discountCardRecord = discountCardRecords.stream().max(Comparator.comparing(DiscountCardRecord::getEndTime)).get();
+        info.setSurplusDay(DateUtil.daysBetweenUp(new Date(), discountCardRecord.getEndTime()));
+        return info;
     }
+
+
+    /**
+     * 扣减畅学卡
+     *
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deduction(DiscountCardRecordWrapper.DeductionDiscountCardRecord result) {
+        // 判断是否是生效中
+
+        DiscountCardRecord discountCardRecord = this.getById(result.getRecordId());
+        if (discountCardRecord == null) {
+            throw new BizException("畅学卡记录不存在");
+        }
+        if (discountCardRecord.getEndTime().before(new Date())) {
+            throw new BizException("畅学卡已过期");
+        }
+
+
+        int days = deductionStudentDiscount(result);
+        updateUserTime(result.getUserId(),ClientEnum.STUDENT);
+
+
+        if (Boolean.TRUE.equals(result.getSendMsg())) {
+            ThreadUtil.execute(() -> sendVipDeductionMessage(result.getUserId(),-days,PeriodEnum.DAY,result.getReason()));
+        }
+    }
+
+
+    private Date addTime(Date time, PeriodEnum period, Integer times, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(time);
+
+        if (PeriodEnum.DAY.equals(period)) {
+            cal.add(Calendar.DAY_OF_MONTH, times);
+        } else if (PeriodEnum.MONTH.equals(period)) {
+            cal.add(Calendar.MONTH, times);
+        } else if (PeriodEnum.YEAR.equals(period)) {
+            cal.add(Calendar.YEAR, times);
+        }
+        if (type ==0) {
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+        } else {
+            cal.set(Calendar.HOUR_OF_DAY, 23);
+            cal.set(Calendar.MINUTE, 59);
+            cal.set(Calendar.SECOND, 59);
+            cal.set(Calendar.MILLISECOND, 0);
+        }
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
+
+    public DiscountCardRecord formatVipRecordTime(DiscountCardRecord discountCardRecord) {
+        // 如果开始时间是23:59:59,开始时间改为第二天的00:00:00
+        LocalDateTime startTime = discountCardRecord.getStartTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (startTime.toLocalTime().equals(LocalTime.of(23, 59, 59))) {
+            startTime = startTime.plusDays(1);
+        }
+
+        startTime = startTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
+        // 如果结束时间是00:00:00,开始时间改为前一天的23:59:59
+        LocalDateTime endTime = discountCardRecord.getEndTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (endTime.toLocalTime().equals(LocalTime.of(0, 0, 0))) {
+            endTime = endTime.plusDays(-1);
+        }
+        endTime = endTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
+        discountCardRecord.setStartTime(Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()));
+        discountCardRecord.setEndTime(Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
+        if (discountCardRecord.getStartTime().after(discountCardRecord.getEndTime())) {
+            discountCardRecord.setEndTime(discountCardRecord.getStartTime());
+        }
+        return discountCardRecord;
+    }
+
+    @Override
+    public void pollExpireMsg() {
+        //会员提前三天提示
+        List<DiscountCardRecord> records = this.lambdaQuery()
+                .eq(DiscountCardRecord::getEfficientFlag, true)
+                .eq(DiscountCardRecord::getMsgStatus, 0)
+                .lt(DiscountCardRecord::getEndTime, DateUtil.localDateTimeToDate(LocalDateTime.now().plusDays(4)))
+                .list();
+        if(CollectionUtils.isNotEmpty(records)){
+            //获取用户编号
+            List<Long> userIds = records.stream().map(DiscountCardRecord::getUserId).collect(Collectors.toList());
+            Map<Long,String> receivers = sysUserService.getDao().selectBatchIds(userIds).stream().collect(Collectors.toMap(SysUser::getId, SysUser::getPhone));
+            temporary3DaysSend(receivers);
+            //更新状态
+            List<Long> ids = records.stream().map(DiscountCardRecord::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,1);
+        }
+
+        //会员到期提示
+        List<DiscountCardRecord> expireRecords = this.lambdaQuery()
+                .eq(DiscountCardRecord::getEfficientFlag, true)
+                .in(DiscountCardRecord::getMsgStatus, 0,1)
+                .lt(DiscountCardRecord::getEndTime, DateUtil.localDateTimeToDate(LocalDateTime.now().plusDays(1)))
+                .list();
+        if (CollectionUtils.isNotEmpty(expireRecords)) {
+            //获取用户编号
+            List<Long> userIds = expireRecords.stream().map(DiscountCardRecord::getUserId).collect(Collectors.toList());
+            Map<Long,String> receivers = sysUserService.getDao().selectBatchIds(userIds).stream().collect(Collectors.toMap(SysUser::getId, SysUser::getPhone));
+            expireSend(receivers);
+            //更新状态
+            List<Long> ids = expireRecords.stream().map(DiscountCardRecord::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,2);
+        }
+    }
+
+    private void temporary3DaysSend(Map<Long, String> receivers) {
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.DISCOUNT_EXPIRE_THIRTY_DAY
+                    , receivers, null, 0, null, ClientEnum.STUDENT.getCode());
+        } catch (Exception e) {
+            log.error("畅学卡到期3天极光消息推送异常");
+        }
+    }
+
+    private void expireSend(Map<Long, String> receivers) {
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.DISCOUNT_EXPIRE
+                    ,receivers, null, 0, null, ClientEnum.STUDENT.getCode());
+        } catch (Exception e) {
+            log.error("畅学卡到期极光消息推送异常");
+        }
+    }
+
 }

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

@@ -49,7 +49,7 @@ public class ExposureRecordServiceImpl extends ServiceImpl<ExposureRecordDao, Ex
             //按对象id分组,并获取集合数量
             Map<Long, Integer> exposureNumMap = saveExposureReportDtos.stream().collect(Collectors.groupingBy(ExposureRecordWrapper.SaveExposureRecordDto::getObjectId, Collectors.summingInt(e -> 1)));
             exposureNumMap.forEach((objectId,exposureNum)-> {
-                if ("LIVE".equals(k)) {
+                if ("LIVE".equals(k) || "VIP_COURSE".equals(k) || "PRACTICE".equals(k) || "GROUP".equals(k)) {
                     courseGroupService.getDao().updateExposureNum(objectId, exposureNum);
                 } else if ("VIDEO".equals(k)) {
                     videoLessonGroupService.getDao().updateExposureNum(objectId, exposureNum);

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

@@ -1,12 +1,13 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.dayaedu.cbs.openfeign.wrapper.music.CbsMusicSheetWrapper;
 import com.yonge.cooleshow.biz.dal.dao.CourseScheduleDao;
 import com.yonge.cooleshow.biz.dal.dao.HomeDao;
-import com.yonge.cooleshow.biz.dal.dao.MusicSheetDao;
 import com.yonge.cooleshow.biz.dal.dao.UserAccountRecordDao;
 import com.yonge.cooleshow.biz.dal.dto.SubjectHomeSearch;
 import com.yonge.cooleshow.biz.dal.dto.req.TotalReq;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.TeacherTagEnum;
@@ -23,6 +24,7 @@ import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherHomeWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
+import com.yonge.toolset.utils.collection.MapUtil;
 import com.yonge.toolset.utils.date.DateUtil;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -30,6 +32,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.temporal.TemporalAdjusters;
 import java.util.*;
@@ -47,7 +50,7 @@ public class HomeServiceImpl implements HomeService {
     @Resource
     private CourseScheduleService courseScheduleService;
     @Resource
-    private MusicSheetDao musicSheetDao;
+    private MusicSheetService musicSheetService;
     @Resource
     private UserAccountRecordDao userAccountRecordDao;
     @Resource
@@ -58,6 +61,10 @@ public class HomeServiceImpl implements HomeService {
     private SysMusicCompareRecordService sysMusicCompareRecordService;
     @Resource
     private UserOrderDetailService userOrderDetailService;
+    @Resource
+    private SysUserService sysUserService;
+    @Resource
+    private StudentService studentService;
 
     @Override
     public HomeUserToDoNum getUserToDoNum() {
@@ -363,7 +370,7 @@ public class HomeServiceImpl implements HomeService {
 
         收益:售卖曲目累计收益金额
          */
-        TeacherHomeWrapper.MusicSheetTotal musicSheetTotal = musicSheetDao.musicSheetTotal(teacherId);
+        TeacherHomeWrapper.MusicSheetTotal musicSheetTotal = musicSheetService.getDao().musicSheetTotal(teacherId);
         if (musicSheetTotal == null) {
             musicSheetTotal = new TeacherHomeWrapper.MusicSheetTotal();
         }
@@ -381,14 +388,14 @@ public class HomeServiceImpl implements HomeService {
 
     @Override
     public List<TeacherHomeWrapper.MusicSheetTotal> musicSheetPage(TeacherHomeWrapper.MusicSheetQuery query) {
-        return musicSheetDao.musicSheetPage(query);
+        return musicSheetService.getDao().musicSheetPage(query);
     }
 
     @Override
     public TeacherIndexWrapper.TeacherPracticeHome getTeacherPracticeHome(TeacherIndexWrapper.SummarySearch summarySearch) {
         TeacherIndexWrapper.TeacherPracticeHome teacherPracticeHome = new TeacherIndexWrapper.TeacherPracticeHome();
         //获取老师关联的学员
-        List<Long> studentIds = teacherService.getDao().getStudentIds(summarySearch.getTeacherId(),summarySearch.getSubjectId());
+        List<Long> studentIds = teacherService.getDao().getStudentIds(summarySearch.getTeacherId(), summarySearch.getSubjectId(), summarySearch.getStartTime(), summarySearch.getEndTime());
         if(CollectionUtils.isEmpty(studentIds)){
             return teacherPracticeHome;
         }
@@ -398,7 +405,10 @@ public class HomeServiceImpl implements HomeService {
         if(Objects.nonNull(practiceSummary)
                 && practiceSummary.getPracticeCount().compareTo(BigDecimal.ZERO) > 0
                 && practiceSummary.getTotalPracticeTime().compareTo(BigDecimal.ZERO) > 0){
-            practiceSummary.setAveragePracticeTime(practiceSummary.getTotalPracticeTime().divide(practiceSummary.getPracticeCount(), 0, BigDecimal.ROUND_HALF_UP));
+            //舍掉小数
+            practiceSummary.setTotalPracticeTime(practiceSummary.getTotalPracticeTime().setScale(0, RoundingMode.DOWN));
+            practiceSummary.setAveragePracticeTime(practiceSummary.getTotalPracticeTime()
+                    .divide(practiceSummary.getPracticeCount(), 0, RoundingMode.DOWN));
         }
         teacherPracticeHome.setPracticeSummary(practiceSummary);
 
@@ -453,30 +463,20 @@ public class HomeServiceImpl implements HomeService {
 
     //数据补全,按时间顺序
     private List<TeacherIndexWrapper.CourseExposureTotal> exposureFillData(List<TeacherIndexWrapper.CourseExposureTotal> exposureTotals,
-                                                                           List<String> dateList,
-                                                                           String[] typeArr) {
-        if(exposureTotals == null){
-            exposureTotals = new ArrayList<>();
-        }
-        //按类型分组
-        Map<String, List<TeacherIndexWrapper.CourseExposureTotal>> typeMap = exposureTotals.stream()
-                .collect(Collectors.groupingBy(TeacherIndexWrapper.CourseExposureTotal::getType));
+                                                                           List<String> dateList) {
         List<TeacherIndexWrapper.CourseExposureTotal> result = new ArrayList<>();
         //按时间段补全数据
         for (String s : dateList) {
-            for (String type : typeArr) {
-                List<TeacherIndexWrapper.CourseExposureTotal> dateMap = typeMap.get(type);
-                if(CollectionUtils.isEmpty(dateMap)){
-                    result.add(new TeacherIndexWrapper.CourseExposureTotal(s,type,0));
+            if(CollectionUtils.isEmpty(exposureTotals)){
+                result.add(new TeacherIndexWrapper.CourseExposureTotal(s,0));
+            }else {
+                Map<String, TeacherIndexWrapper.CourseExposureTotal> dateMapGroup = exposureTotals.stream()
+                        .collect(Collectors.toMap(TeacherIndexWrapper.CourseExposureTotal::getDate, o -> o));
+                TeacherIndexWrapper.CourseExposureTotal courseExposureTotal = dateMapGroup.get(s);
+                if(Objects.nonNull(courseExposureTotal)){
+                    result.add(courseExposureTotal);
                 }else {
-                    Map<String, TeacherIndexWrapper.CourseExposureTotal> dateMapGroup = dateMap.stream()
-                            .collect(Collectors.toMap(TeacherIndexWrapper.CourseExposureTotal::getDate, o -> o));
-                    TeacherIndexWrapper.CourseExposureTotal courseExposureTotal = dateMapGroup.get(s);
-                    if(Objects.nonNull(courseExposureTotal)){
-                        result.add(courseExposureTotal);
-                    }else {
-                        result.add(new TeacherIndexWrapper.CourseExposureTotal(s,type,0));
-                    }
+                    result.add(new TeacherIndexWrapper.CourseExposureTotal(s,0));
                 }
             }
         }
@@ -486,17 +486,36 @@ public class HomeServiceImpl implements HomeService {
     @Override
     public List<TeacherIndexWrapper.StudentPracticeSummaryDto> getTeacherHomeStudent(TeacherIndexWrapper.StudentSearch studentSearch) {
         //获取老师关联的学员
-        List<Long> studentIds = teacherService.getDao().getStudentIds(studentSearch.getTeacherId(),studentSearch.getSubjectId());
+        List<Long> studentIds = teacherService.getDao().getStudentIds(studentSearch.getTeacherId(),
+                studentSearch.getSubjectId(),
+                studentSearch.getStartTime(),
+                studentSearch.getEndTime());
         if(CollectionUtils.isEmpty(studentIds)){
             return Collections.emptyList();
         }
+        //获取间隔天数
+        int days = DateUtil.daysBetween(DateUtil.strToDate(studentSearch.getStartTime(), DateUtil.DEFAULT_PATTERN),
+                DateUtil.strToDate(studentSearch.getEndTime(), DateUtil.DEFAULT_PATTERN)) + 1;
+        studentSearch.setIntervalDays(days);
         //获取学员练习汇总
-        return sysMusicCompareRecordService.getDao().getStudentTrainOverViewList(studentIds,studentSearch);
+        List<TeacherIndexWrapper.StudentPracticeSummaryDto> result = sysMusicCompareRecordService.getDao().getStudentTrainOverViewList(studentIds, studentSearch);
+        if(Objects.nonNull(result)){
+            //格式化练习总时长,(将秒转换为时分秒)
+            for (TeacherIndexWrapper.StudentPracticeSummaryDto dto : result) {
+                if(dto.getTotalPracticeTime() > 0){
+                    dto.setTotalPracticeTimeStr(DateUtil.secondToTime(dto.getTotalPracticeTime()));
+                    if (dto.getAveragePracticeTime() > 0){
+                        dto.setAveragePracticeTimeStr(DateUtil.secondToTime(dto.getAveragePracticeTime()));
+                    }
+                }
+            }
+        }
+        return result;
     }
 
 
     @Override
-    public Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> courseExposureTotal(TeacherIndexWrapper.CourseExposureSearch search) {
+    public List<TeacherIndexWrapper.CourseExposureTotal> courseExposureTotal(TeacherIndexWrapper.CourseExposureSearch search) {
         String groupBy;
         List<String> dateList;
         Date startDate = DateUtil.strToDate(search.getStartTime(), DateUtil.DEFAULT_PATTERN);
@@ -511,19 +530,11 @@ public class HomeServiceImpl implements HomeService {
             groupBy = "%Y";
             dateList = DateUtil.getYearList(startDate,endDate);
         }
-        List<TeacherIndexWrapper.CourseExposureTotal> courseExposureTotals = exposureRecordService.getDao().courseExposureTotal(search, groupBy);
-        //按分类分组
-        Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> typeMap = courseExposureTotals.stream()
-                .collect(Collectors.groupingBy(TeacherIndexWrapper.CourseExposureTotal::getType));
-        Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> result = new HashMap<>();
-        result.put("EXPOSURE_LIVE",exposureFillData(typeMap.get(GoodTypeEnum.LIVE.getCode()),dateList,new String[]{GoodTypeEnum.LIVE.getCode()}));
-        result.put("EXPOSURE_VIDEO",exposureFillData(typeMap.get(GoodTypeEnum.VIDEO.getCode()),dateList,new String[]{GoodTypeEnum.VIDEO.getCode()}));
-        result.put("EXPOSURE_MUSIC",exposureFillData(typeMap.get(GoodTypeEnum.MUSIC.getCode()),dateList,new String[]{GoodTypeEnum.MUSIC.getCode()}));
-        return result;
+        return exposureFillData(exposureRecordService.getDao().courseExposureTotal(search, groupBy),dateList);
     }
 
     @Override
-    public Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> courseBuyTotal(TeacherIndexWrapper.CourseExposureSearch search) {
+    public List<TeacherIndexWrapper.CourseExposureTotal> courseBuyTotal(TeacherIndexWrapper.CourseExposureSearch search) {
         //获取学员练习时长
         //获取分组条件,如果所选时间段只有一天,则按小时分组,超过一个月按天分组,超过一年按月分组
         String groupBy;
@@ -541,21 +552,81 @@ public class HomeServiceImpl implements HomeService {
             dateList = DateUtil.getYearList(startDate,endDate);
         }
         Map<String,List<TeacherIndexWrapper.CourseExposureTotal>> result = new HashMap<>();
-        //直播
+        //课
         List<TeacherIndexWrapper.CourseExposureTotal> liveSummer = userOrderDetailService.getDao().liveBuyTotal(search,groupBy);
-        result.put(GoodTypeEnum.LIVE.getCode(),exposureFillData(liveSummer,dateList,new String[]{GoodTypeEnum.LIVE.getCode()}));
-        //视频课
-        List<TeacherIndexWrapper.CourseExposureTotal> videoSummer = userOrderDetailService.getDao().videoBuyTotal(search,groupBy);
-        result.put(GoodTypeEnum.VIDEO.getCode(),exposureFillData(videoSummer,dateList,new String[]{GoodTypeEnum.VIDEO.getCode()}));
-        //获取老师关联的学员
-        List<Long> studentIds = teacherService.getDao().getStudentIds(search.getTeacherId(),null);
-        if(CollectionUtils.isNotEmpty(studentIds)){
+        result.put("COURSE",exposureFillData(liveSummer,dateList));
+
+        if(StringUtils.isEmpty(search.getType()) || StringUtils.equals(search.getType(),GoodTypeEnum.MUSIC.getCode())){
             //曲谱
-            search.setStudentIds(studentIds);
             List<TeacherIndexWrapper.CourseExposureTotal> musicSheetSummer = userOrderDetailService.getDao().musicSheetBuyTotal(search,groupBy);
-            result.put(GoodTypeEnum.MUSIC.getCode(),exposureFillData(musicSheetSummer,dateList,new String[]{GoodTypeEnum.MUSIC.getCode()}));
+            result.put(GoodTypeEnum.MUSIC.getCode(),exposureFillData(musicSheetSummer,dateList));
         }
-        return result;
+        //将数据合并,map中所有的数据按时间,将list中的数据相加
+        List<TeacherIndexWrapper.CourseExposureTotal> finalResult = new ArrayList<>();
+        for (String s : dateList) {
+            TeacherIndexWrapper.CourseExposureTotal courseExposureTotal = new TeacherIndexWrapper.CourseExposureTotal();
+            courseExposureTotal.setDate(s);
+            courseExposureTotal.setExposureNum(0);
+            for (Map.Entry<String, List<TeacherIndexWrapper.CourseExposureTotal>> entry : result.entrySet()) {
+                List<TeacherIndexWrapper.CourseExposureTotal> value = entry.getValue();
+                Map<String, TeacherIndexWrapper.CourseExposureTotal> collect = value.stream()
+                        .collect(Collectors.toMap(TeacherIndexWrapper.CourseExposureTotal::getDate, o -> o));
+                TeacherIndexWrapper.CourseExposureTotal exposureTotal = collect.get(s);
+                if(Objects.nonNull(exposureTotal)){
+                    courseExposureTotal.setExposureNum(courseExposureTotal.getExposureNum() + exposureTotal.getExposureNum());
+                }
+            }
+            finalResult.add(courseExposureTotal);
+        }
+        return finalResult;
+    }
+
+    @Override
+    public PageInfo<TeacherIndexWrapper.TeacherIncome> teacherIncomeList(IPage<TeacherIndexWrapper.TeacherIncome> page,TeacherIndexWrapper.CourseExposureSearch query) {
+        IPage<TeacherIndexWrapper.TeacherIncome> record = baserMapper.teacherIncomeList(page,query);
+        List<TeacherIndexWrapper.TeacherIncome> records = record.getRecords();
+        if (CollectionUtils.isNotEmpty(records)) {
+            List<Long> userIds = records.stream().map(TeacherIndexWrapper.TeacherIncome::getUserId).collect(Collectors.toList());
+            Map<Long, CbsMusicSheetWrapper.MusicSheetApplication> sysMusicSheetMap = new HashMap<>();
+            Map<Long, String> studentSubjectMap = new HashMap<>();
+            if(StringUtils.equals(query.getType(),"MUSIC")){
+                //曲谱
+                List<Long> musicSheetIds = records.stream().map(TeacherIndexWrapper.TeacherIncome::getBizId).collect(Collectors.toList());
+                CbsMusicSheetWrapper.MusicSheetApplicationQuery applicationQuery = musicSheetService.getMusicSheetApplicationQuery();
+                applicationQuery.setMusicSheetIds(musicSheetIds);
+                applicationQuery.setRows(musicSheetIds.size());
+                List<CbsMusicSheetWrapper.MusicSheetApplication> applications = musicSheetService.queryCbsMusicSheetApplication(applicationQuery);
+                sysMusicSheetMap = applications.stream().collect(Collectors.toMap(CbsMusicSheetWrapper.MusicSheetApplication::getId, Function.identity()));
+            }else {
+                //获取用户声部信息
+                List<Map<Integer, String>> studentSubjectMapList = studentService.getDao().getStudentSubjectMapList(userIds);
+                studentSubjectMap = MapUtil.convertIntegerMap(studentSubjectMapList);
+            }
+            List<SysUser> sysUsers = sysUserService.getDao().selectBatchIds(userIds);
+            Map<Long, SysUser> sysUserMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, Function.identity()));
+            for (TeacherIndexWrapper.TeacherIncome teacherIncome : records) {
+                SysUser sysUser = sysUserMap.get(teacherIncome.getUserId());
+                if (sysUser != null) {
+                    teacherIncome.setUserName(sysUser.getUsername());
+                    teacherIncome.setUserAvatar(sysUser.getAvatar());
+                }
+                if(StringUtils.equals(query.getType(),"MUSIC")){
+                    CbsMusicSheetWrapper.MusicSheetApplication musicSheetApplication = sysMusicSheetMap.get(teacherIncome.getBizId());
+                    if(musicSheetApplication != null){
+                        teacherIncome.setBizName(musicSheetApplication.getName());
+                        teacherIncome.setBizCover(musicSheetApplication.getMusicCover());
+                    }
+                }else {
+                    teacherIncome.setSubjectName(studentSubjectMap.get(teacherIncome.getUserId()));
+                }
+            }
+        }
+        return PageUtil.pageInfo(record);
+    }
+
+    @Override
+    public BigDecimal teacherIncomeSum(TeacherIndexWrapper.CourseExposureSearch query) {
+        return baserMapper.teacherIncomeSum(query);
     }
 
 }

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

@@ -1375,6 +1375,7 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
     public Boolean updateImGroup(ImGroup imGroup) {
 
         this.updateById(imGroup);
+        imGroup= this.getById(imGroup.getId());
         try {
             imGroupCoreService.modifyGroupInfo(imGroup.getId(),imGroup.getName(),imGroup.getImg());
         } catch (Exception e) {
@@ -1465,6 +1466,24 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         return true;
     }
 
+    @Override
+    @Transactional
+    public Boolean updateIntroduce(ImGroup imGroup) {
+
+        if (StringUtils.isEmpty(imGroup.getId())) {
+            throw new BizException("群组ID不能为空");
+        }
+        if (StringUtils.isEmpty(imGroup.getIntroduce())) {
+            throw new BizException("群组介绍不能为空");
+        }
+
+        return this.lambdaUpdate()
+                .eq(ImGroup::getId, imGroup.getId())
+                .set(ImGroup::getIntroduce, imGroup.getIntroduce())
+                .update();
+
+    }
+
     private void groupAvatarUpdate(List<ImGroup> records) {
 
         for (ImGroup imGroup : records) {

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

@@ -5,6 +5,7 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicSheetOrderSearch;
@@ -13,9 +14,11 @@ import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.*;
 import com.yonge.cooleshow.biz.dal.enums.album.PurchaseRecordTypeEnum;
+import com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.enums.ActivityShareEnum;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
 import com.yonge.toolset.utils.obj.ObjectUtil;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -84,6 +87,8 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
     @Autowired
     private TenantStaffService tenantStaffService;
 
+    @Autowired
+    private AlbumCategoryService albumCategoryService;
 
     @Autowired
     private SysUserFeignService sysUserFeignService;
@@ -138,31 +143,49 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
             query.setSubjectIds(musicAlbum.getSubjectId());
         }
 
+        if (query.getQueryCategory() !=null && query.getQueryCategory()) {
+            // 查询专辑分类
+            AlbumCategoryWrapper.AlbumCategoryQuery albumCategoryQuery = new AlbumCategoryWrapper.AlbumCategoryQuery();
+            albumCategoryQuery.setAlbumId(query.getId());
+            IPage<AlbumCategoryWrapper.AlbumCategory> albumCategoryIPage = albumCategoryService.selectPage(new Page<>(1, -1), albumCategoryQuery);
+            List<AlbumCategoryWrapper.AlbumCategory> records = albumCategoryIPage.getRecords();
+            if (CollectionUtils.isNotEmpty(records)) {
+                albumDetailVo.setAlbumLevelList(records.stream().filter(o->o.getCategoryType().equals(ETenantAlbumCategoryType.CATEGORY_LEVEL.name())).collect(Collectors.toList()));
+                albumDetailVo.setAlbumTypeList(records.stream().filter(o->o.getCategoryType().equals(ETenantAlbumCategoryType.CATEGORY_TYPE.name())).collect(Collectors.toList()));
+            }
+        }
+
         if (sysUser != null) {
             query.setStudentId(sysUser.getId());
         }
         query.setClientType(client);
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectAlbumDetailPage(page,query);
 
-        List<MusicSheetVo> records = musicSheetVoIPage.getRecords();
-        if (CollectionUtils.isNotEmpty(records)) {
-            // 专辑曲目付费方式
-            List<String> paymentTypes = musicSheetVoIPage.getRecords().stream()
-                    .flatMap(x -> Arrays.stream(x.getPaymentType().split(","))).distinct().collect(Collectors.toList());
-            albumDetailVo.setMusicPaymentTypes(paymentTypes);
+        IPage<MusicSheetVo> musicSheetVoIPage = null;
+        if (query.getQueryMusicSheet() !=null && query.getQueryMusicSheet()) {
+            musicSheetVoIPage = musicSheetService.selectAlbumDetailPage(page, query);
 
-            // 更新曲目专辑数量
-            musicSheetService.updateMusicAlbumNumInfo(records);
-        }
-        //处理Long精度丢失问题
-        List<MusicSheetVoResult> musicSheetVoResults = new ArrayList<>();
-        for (MusicSheetVo row : records) {
-            MusicSheetVoResult musicSheetVoResult = JSON.parseObject(JSON.toJSONString(row), MusicSheetVoResult.class);
-            musicSheetVoResult.setCbsMusicSheetId(row.getCbsMusicSheetId().toString());
-            musicSheetVoResults.add(musicSheetVoResult);
-        }
-        albumDetailVo.setMusicSheetList(PageUtil.pageInfo(com.yonge.cooleshow.biz.dal.dto.PageUtil.transPageInfo(musicSheetVoIPage, musicSheetVoResults)));
+            List<MusicSheetVo> records = musicSheetVoIPage.getRecords();
+            if (CollectionUtils.isNotEmpty(records)) {
+                // 专辑曲目付费方式
+                List<String> paymentTypes = musicSheetVoIPage.getRecords().stream()
+                        .flatMap(x -> Arrays.stream(x.getPaymentType().split(","))).distinct().collect(Collectors.toList());
+                albumDetailVo.setMusicPaymentTypes(paymentTypes);
 
+                // 更新曲目专辑数量
+                musicSheetService.updateMusicAlbumNumInfo(records);
+            }
+            //处理Long精度丢失问题
+            List<MusicSheetVoResult> musicSheetVoResults = new ArrayList<>();
+            for (MusicSheetVo row : records) {
+                MusicSheetVoResult musicSheetVoResult = JSON.parseObject(JSON.toJSONString(row), MusicSheetVoResult.class);
+                musicSheetVoResult.setCbsMusicSheetId(row.getCbsMusicSheetId().toString());
+                musicSheetVoResults.add(musicSheetVoResult);
+            }
+            albumDetailVo.setMusicSheetList(PageUtil.pageInfo(com.yonge.cooleshow.biz.dal.dto.PageUtil.transPageInfo(musicSheetVoIPage, musicSheetVoResults)));
+
+        } else {
+            musicSheetVoIPage = musicSheetService.selectAlbumDetailPage(new Page<>(1,1), query);
+        }
 
         albumDetailVo.setMusicSheetCount((int) musicSheetVoIPage.getTotal());
 
@@ -384,9 +407,10 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
                 .eq(AlbumMusicRelate::getAlbumId,query.getAlbumId())
                 .eq(AlbumMusicRelate::getMusicSheetId,query.getMusicSheetId())
                 .set(AlbumMusicRelate::getSortNumber,query.getSortNumber())
+                .set(AlbumMusicRelate::getAlbumCategoryLevelId,query.getAlBumCategoryLevelId())
+                .set(AlbumMusicRelate::getAlbumCategoryTypeId,query.getAlBumCategoryTypeId())
                 .update();
 
-
     }
 
     @Override

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

@@ -153,6 +153,9 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
 
     @Autowired
     private SysUserService sysUserService;
+    
+    @Autowired
+    private AlbumCategoryService albumCategoryService;
 
     @Value("${openfeign-client.app-id:1745637981387108354}")
     public Long applicationId;
@@ -359,6 +362,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
             List<MusicFavorite> musicFavoriteList = musicFavoriteService.lambdaQuery()
                     .eq(MusicFavorite::getUserId, query.getStudentId())
                     .eq(MusicFavorite::getClientType, query.getClientType())
+                    .eq(MusicFavorite::getProviderType, SourceTypeEnum.PLATFORM.name())
                     .in(MusicFavorite::getMusicSheetId, musicIdList)
                     .list();
             if (CollectionUtils.isNotEmpty(musicFavoriteList)) {
@@ -370,6 +374,27 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 }
             }
         }
+        
+        // 设置专辑
+        List<Long> albumCategoryIds = records.stream().flatMap(o -> Lists.newArrayList(o.getAlbumCategoryTypeId(), o.getAlbumCategoryLevelId()).stream())
+                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<Long, AlbumCategory> albumCategoryMap = albumCategoryService.getMapByIds(albumCategoryIds);
+
+        for (MusicSheetVo record : records) {
+            if (record.getAlbumCategoryTypeId() != null) {
+                AlbumCategory albumCategory = albumCategoryMap.get(record.getAlbumCategoryTypeId());
+                if (albumCategory != null) {
+                    record.setAlbumCategoryTypeName(albumCategory.getName());
+                }
+            }
+            if (record.getAlbumCategoryLevelId() != null) {
+                AlbumCategory albumCategory = albumCategoryMap.get(record.getAlbumCategoryLevelId());
+                if (albumCategory != null) {
+                    record.setAlbumCategoryLevelName(albumCategory.getName());
+                }
+            }
+        }
+
 
         return musicSheetVoIPage;
     }

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

@@ -6,6 +6,7 @@ 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.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -1109,4 +1110,44 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         summaryDto.setTotalCourseCount(courseScheduleService.getDao().countStudentOverCourse(userId, monday, sunday,null));
         return summaryDto;
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateVipStatus(Long userId) {
+        // 查询有效的会员
+
+        // 查询有效的畅学卡
+
+        // 查询有效的机构专辑
+        List<String> strings = baseMapper.selectEntitlements(userId);
+
+        if (CollectionUtils.isEmpty(strings)) {
+            this.lambdaUpdate()
+                    .eq(Student::getUserId, userId)
+                    .set(Student::getEntitlements, EStudentEntitlements.NORMAL)
+                    .update();
+        } else {
+            String collect = strings.stream().filter(StringUtils::isNotBlank).collect(Collectors.joining(","));
+            this.lambdaUpdate()
+                    .eq(Student::getUserId, userId)
+                    .set(Student::getEntitlements, StringUtils.isBlank(collect)?"NORMAL":collect)
+                    .update();
+
+        }
+    }
+
+    @Override
+    public void initEntitlements() {
+        int page = 1;
+        List<Long> list = baseMapper.selectInitEntitlements(new Page<>(page, 100));
+        while (CollectionUtils.isNotEmpty(list)) {
+            try {
+                list.forEach(this::updateVipStatus);
+            }catch (Exception e){
+                log.error("初始化学生权益失败",e);
+            }
+            page++;
+            list = baseMapper.selectInitEntitlements(new Page<>(page, 100));
+        }
+    }
 }

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

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.biz.dal.service.impl;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 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.*;
@@ -13,6 +14,7 @@ import com.yonge.cooleshow.biz.dal.enums.IndexDataType;
 import com.yonge.cooleshow.biz.dal.queryInfo.SysMusicCompareRecordQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.music.MusicCompareWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
@@ -56,6 +58,8 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 	@Resource
 	private StudentService studentService;
 	@Resource
+	private SubjectService subjectService;
+	@Resource
 	private SysUserService sysUserService;
 	@Resource
 	private SysMusicCompareWeekDataService sysMusicCompareWeekDataService;
@@ -371,9 +375,20 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 
 		userTrainChartResult.add(new IndexBaseDto(IndexDataType.CLOUD_STUDY_TRAIN_TIME, trainTimeData));
 		userTrainChartResult.add(new IndexBaseDto(IndexDataType.CLOUD_STUDY_TRAIN_NUM, trainNumData));
+		//获取学员基本信息
+		SysUser sysUser = sysUserService.findUserById(queryInfo.getUserId());
+		StudentWrapper.BasicUserInfo basicUserInfo = new StudentWrapper.BasicUserInfo();
+		basicUserInfo.setUsername(sysUser.getUsername());
+		basicUserInfo.setAvatar(sysUser.getAvatar());
+		Student student = studentService.getById(queryInfo.getUserId());
+		if(Objects.nonNull(student) && StringUtils.isNotEmpty(student.getSubjectId())){
+			Subject subject = subjectService.get(Long.parseLong(student.getSubjectId()));
+			basicUserInfo.setSubjectName(subject.getName());
+		}
 
 		result.put("userTrainChartData", userTrainChartResult);
 		result.put("detail",pageInfo);
+		result.put("userInfo",basicUserInfo);
 		return result;
 	}
 

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

@@ -1252,12 +1252,12 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         List<Long> watchTeacherIdList = new ArrayList<Long>();
 
         List<StudentStar> studentStarList = studentStarDao.queryByStudentId(userId);
-        if (studentStarList != null && studentStarList.size() > 0) {
+        if (CollectionUtils.isNotEmpty(studentStarList)) {
             watchTeacherIdList = studentStarList.stream().map(StudentStar::getTeacherId).collect(Collectors.toList());
         }
 
         Student student = studentService.getById(userId);
-        Long subjectId = -1L;
+        long subjectId = -1L;
         if (student !=null && student.getSubjectId() != null) {
             subjectId = Long.parseLong(student.getSubjectId());
         }

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

@@ -68,6 +68,12 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
     @Autowired
     private TenantGroupAlbumService tenantGroupAlbumService;
 
+    @Autowired
+    private StudentService studentService;
+
+    @Autowired
+    private UserTenantAlbumRecordService userTenantAlbumRecordService;
+
 
     private static final String PHONE_REG = "^1\\d{10}$";
 
@@ -653,62 +659,11 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
             userTenantAlbumRecord.setType(purchase.getPurchaseType());
         }
 
-        List<UserTenantAlbumRecord> userTenantAlbumRecords = userTenantAlbumRecordMapper
-                .selectList(Wrappers.<UserTenantAlbumRecord>lambdaQuery()
-                        .eq(UserTenantAlbumRecord::getTenantId, userTenantAlbumRecord.getTenantId())
-                        .eq(UserTenantAlbumRecord::getUserId, studentId)
-                        .eq(UserTenantAlbumRecord::getTenantAlbumId, userTenantAlbumRecord.getTenantAlbumId())
-                        .eq(UserTenantAlbumRecord::getClientType, ClientEnum.STUDENT)
-                        .orderByDesc(UserTenantAlbumRecord::getEndTime));
 
         userTenantAlbumRecord.setUserId(studentId);
         userTenantAlbumRecord.setCreateBy(studentId);
 
+        userTenantAlbumRecordService.add(userTenantAlbumRecord,false);
 
-//        userTenantAlbumRecord.setType("MONTH");
-
-        Calendar instance = Calendar.getInstance();
-        if (userTenantAlbumRecords.isEmpty()) {
-            instance.setTime(DateTime.now().withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).toDate());
-        } else {
-            // 如果最后一次的时间的小于当前时间,则以当前时间为会员的开始时间
-            // 如果最后一次的时间的大于当前时间,则以最后一次的结束时间为记录的开始时间,相当会员续期
-            UserTenantAlbumRecord lastRecord = userTenantAlbumRecords.get(0);
-            Date lastEndTime = lastRecord.getEndTime();
-            if (lastEndTime.before(new Date())) {
-                instance.setTime(DateTime.now().withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).toDate());
-            } else {
-                instance.setTime(lastEndTime);
-            }
-        }
-        userTenantAlbumRecord.setStartTime(instance.getTime());
-        //DAY 日 MONTH 月 QUARTERLY 季度 YEAR_HALF 半年 YEAR 年
-        switch (userTenantAlbumRecord.getType()) {
-            case "DAY":
-                instance.add(Calendar.DAY_OF_MONTH, userTenantAlbumRecord.getTimes());
-                break;
-            case "MONTH":
-                instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes());
-                break;
-            case "QUARTERLY":
-                instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes() * 3);
-                break;
-            case "YEAR_HALF":
-                instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes() * 6);
-                break;
-            case "YEAR":
-                instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes() * 12);
-                break;
-            default:
-                instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes());
-                break;
-        }
-
-        instance.set(Calendar.HOUR_OF_DAY, 23);
-        instance.set(Calendar.MINUTE, 59);
-        instance.set(Calendar.SECOND, 59);
-        instance.set(Calendar.MILLISECOND, 0);
-        userTenantAlbumRecord.setEndTime(instance.getTime());
-        userTenantAlbumRecordMapper.insert(userTenantAlbumRecord);
     }
 }

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

@@ -239,6 +239,23 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                     userOrderVo.setTenantName(tenantInfo.getName());
                 }
             }
+            Map<String,BigDecimal> orderDiscount = new HashMap<>();
+            orderDetilListByOrderNo.forEach(o -> {
+                if (StringUtils.isNotBlank(o.getDiscountJson())) {
+                    JSONObject jsonObject = JSON.parseObject(o.getDiscountJson(), JSONObject.class);
+                    jsonObject.forEach((k,v) -> {
+                       if (orderDiscount.containsKey(k)) {
+                           orderDiscount.put(k,orderDiscount.get(k).add(new BigDecimal(v.toString())));
+                       } else {
+                           orderDiscount.put(k,new BigDecimal(v.toString()));
+                       }
+                   });
+                }
+            });
+            // 过滤 金额=0
+            Map<String,BigDecimal> orderDiscountMap = orderDiscount.entrySet().stream().filter(o -> o.getValue().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+            userOrderVo.setOrderDiscountMap(orderDiscountMap);
+
             for (UserOrderDetailVo userOrderDetailVo : orderDetilListByOrderNo) {
                 if (userOrderDetailVo.getGoodType().equals(GoodTypeEnum.TENANT_ALBUM)) {
                     TenantAlbum tenantAlbum = tenantAlbumService.getById(userOrderDetailVo.getBizId());

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

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import cn.hutool.core.thread.ThreadUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -11,37 +12,34 @@ import com.google.common.collect.Lists;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.StudentDao;
-import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicSheetSearch;
 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.PeriodEnum;
-import com.yonge.cooleshow.biz.dal.enums.SubjectTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.mapper.*;
 import com.yonge.cooleshow.biz.dal.service.*;
-import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupAlbumWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 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.date.DateUtil;
 import com.yonge.toolset.utils.obj.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.jetbrains.annotations.Nullable;
 import org.joda.time.DateTime;
 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.UserTenantAlbumRecordWrapper;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -63,12 +61,6 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
     private TenantInfoService tenantInfoService;
 
     @Autowired
-    private TenantAlbumMusicService tenantAlbumMusicService;
-
-    @Autowired
-    private MusicSheetService musicSheetService;
-
-    @Autowired
     private StudentService studentService;
 
     @Autowired
@@ -81,9 +73,6 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
     private StudentDao studentDao;
 
     @Autowired
-    private TenantAlbumPurchaseMapper tenantAlbumPurchaseMapper;
-
-    @Autowired
     private UserTenantAlbumRecordService userTenantAlbumRecordService;
 
 
@@ -100,9 +89,6 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
     private SysUserMapper sysUserMapper;
 
     @Autowired
-    private TenantInfoMapper tenantInfoMapper;
-
-    @Autowired
     private TenantGroupAlbumService tenantGroupAlbumService;
 
 
@@ -114,6 +100,10 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
 
     @Autowired
     private CoursewareFeignService coursewareFeignService;
+
+    @Autowired
+    private SysUserService sysUserService;
+
     /**
      * 查询详情
      *
@@ -168,50 +158,6 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
                     vo.setTenantName(tenantInfo.getName());
                     vo.setTenantImg(tenantInfo.getLogo());
                 }
-                //查询机构专辑曲目表
-//                List<TenantAlbumMusic> tenantAlbumMusics = tenantAlbumMusicService.lambdaQuery()
-//                        .eq(TenantAlbumMusic::getTenantAlbumId, i.getId())
-//                        .eq(TenantAlbumMusic::getDelFlag, false)
-//                        .list();
-//
-//                Map<SubjectTypeEnum, List<TenantAlbumMusic>> groupByType =
-//                        tenantAlbumMusics.stream().collect(Collectors.groupingBy(TenantAlbumMusic::getSubjectType));
-//
-//                List<Long> musicSheetIdlist = tenantAlbumMusics.stream().map(next -> next.getMusicSheetId()).distinct().collect(Collectors.toList());
-
-//                StudentMusicSheetSearch search = new StudentMusicSheetSearch();
-//                search.setMusicSheetIdlist(musicSheetIdlist);
-//                search.setPage(1);
-//                search.setRows(9999);
-//
-//                IPage<MusicSheetVo> records = musicSheetService.selectStudentPage(PageUtil.getPage(search), search, ClientEnum.TENANT_STUDENT);
-//
-//                Map<Long, MusicSheetVo> idMsMap = records.getRecords().stream()
-//                        .collect(Collectors.toMap(MusicSheet::getId, Function.identity()));
-//
-//                List<TenantAlbumWrapper.MusicSheetData> musicSheetData = vo.getMusicSheetData();
-//
-//                groupByType.forEach((key, value) -> {
-//                    value.sort(Comparator.comparing(TenantAlbumMusic::getSortNumber));
-//                    TenantAlbumWrapper.MusicSheetData sheetData = new TenantAlbumWrapper.MusicSheetData();
-//                    sheetData.setSubjectType(key);
-//                    List<TenantAlbumWrapper.TenantAlbumSheet> tenantAlbumSheets = value.stream().map(next -> {
-//
-//                        TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
-//                        BeanUtils.copyProperties(next, tenantAlbumSheet);
-//                        Long musicSheetId = tenantAlbumSheet.getMusicSheetId();
-//                        MusicSheetVo musicSheet = idMsMap.getOrDefault(musicSheetId, new MusicSheetVo());
-//                        tenantAlbumSheet.setMusicSheetName(musicSheet.getMusicSheetName());
-//                        tenantAlbumSheet.setMusicTag(musicSheet.getMusicTag());
-//                        tenantAlbumSheet.setComposer(musicSheet.getComposer());
-//                        return tenantAlbumSheet;
-//                    }).collect(Collectors.toList());
-//
-//
-//                    sheetData.setTenantAlbumSheetList(tenantAlbumSheets);
-//                    musicSheetData.add(sheetData);
-//                    vo.setMusicSheetData(musicSheetData);
-//                });
                 list.add(vo);
             });
         }
@@ -250,14 +196,16 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
      */
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public Boolean add(UserTenantAlbumRecord userTenantAlbumRecord) {
+    public Boolean add(UserTenantAlbumRecord userTenantAlbumRecord,boolean sendMsg) {
         Long tenantAlbumId = userTenantAlbumRecord.getTenantAlbumId();
         TenantAlbum tenantAlbum = tenantAlbumMapper.selectById(tenantAlbumId);
-        if (tenantAlbum == null || Boolean.TRUE.equals(tenantAlbum.getDelFlag())) {
-            throw new BizException("专辑不存在");
-        }
-        if (Boolean.FALSE.equals(tenantAlbum.getStatus())) {
-            throw new BizException("专辑已经停用");
+        if (userTenantAlbumRecord.getSourceType() == SourceTypeEnum.BACKEND_GIVE) {
+            if (tenantAlbum == null || Boolean.TRUE.equals(tenantAlbum.getDelFlag())) {
+                throw new BizException("专辑不存在");
+            }
+            if (Boolean.FALSE.equals(tenantAlbum.getStatus())) {
+                throw new BizException("专辑已经停用");
+            }
         }
 
         List<UserTenantAlbumRecord> userTenantAlbumRecords = this.getBaseMapper()
@@ -281,41 +229,20 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
         }
         userTenantAlbumRecord.setStartTime(instance.getTime());
 
-        String type = userTenantAlbumRecord.getType();
-        if ("DAY".equals(type)) {
-            instance.add(Calendar.DAY_OF_MONTH, userTenantAlbumRecord.getTimes());
-        } else if ("MONTH".equals(type)) {
-            instance.add(Calendar.MONTH, userTenantAlbumRecord.getTimes());
-        } else if ("YEAR".equals(type)) {
-            instance.add(Calendar.YEAR, userTenantAlbumRecord.getTimes());
-        } else {
-            throw new BizException("不支持的周期类型");
-        }
-
-        instance.set(Calendar.HOUR_OF_DAY, 23);
-        instance.set(Calendar.MINUTE, 59);
-        instance.set(Calendar.SECOND, 59);
-        instance.set(Calendar.MILLISECOND, 0);
-        userTenantAlbumRecord.setEndTime(instance.getTime());
+        userTenantAlbumRecord.setEndTime(addTime(userTenantAlbumRecord.getStartTime(), PeriodEnum.valueOf(userTenantAlbumRecord.getType()), userTenantAlbumRecord.getTimes(),1));
+        formatVipRecordTime(userTenantAlbumRecord);
         userTenantAlbumRecord.setCreateTime(new Date());
         userTenantAlbumRecord.setUpdateTime(new Date());
+        userTenantAlbumRecord.setEstimatedEndTime(userTenantAlbumRecord.getEndTime());
+        userTenantAlbumRecord.setEstimatedStartTime(userTenantAlbumRecord.getStartTime());
         this.save(userTenantAlbumRecord);
+        studentService.updateVipStatus(userTenantAlbumRecord.getUserId());
 
-        SysUser sysUser = sysUserMapper.getByUserId(userTenantAlbumRecord.getUserId());
-        sendMessage(userTenantAlbumRecord.getUserId(), sysUser.getPhone(), ClientEnum.STUDENT, userTenantAlbumRecord.getTimes(), PeriodEnum.valueOf(userTenantAlbumRecord.getType()),
-                tenantAlbum.getName(), userTenantAlbumRecord.getReason());
-        return true;
-    }
-
-    private void sendMessage(Long userId, String phone, ClientEnum client, Integer times, PeriodEnum type, String tenantAlbumName, String reason) {
-        try {
-            Map<Long, String> receivers = new HashMap<>();
-            receivers.put(userId, phone);
-            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.USER_TENANT_ALBUM_VIP,
-                    receivers, null, 0, null, client.getCode(), times, type.getMsg(), tenantAlbumName, reason);
-        } catch (Exception e) {
-            log.error("机构专辑会员赠送消息发送失败 : {}", e.getMessage());
+        if (sendMsg) {
+            sendVipDeductionMessage(userTenantAlbumRecord.getUserId(),userTenantAlbumRecord.getTimes(),
+                    PeriodEnum.valueOf(userTenantAlbumRecord.getType()),userTenantAlbumRecord.getReason(),tenantAlbum.getName());
         }
+        return true;
     }
 
     /**
@@ -665,25 +592,31 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
 
     @Override
     public void sendTenantAlbumMessage() {
+        //3天内到期的专辑
         List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> userTenantAlbumRecords = baseMapper.selectTemporaryRecord();
-        if (CollectionUtils.isEmpty(userTenantAlbumRecords)) {
-            return;
+        if (CollectionUtils.isNotEmpty(userTenantAlbumRecords)) {
+            //获取专辑名称
+            List<Long> tenantAlbumIds = userTenantAlbumRecords.stream().map(UserTenantAlbumRecordWrapper.UserTenantAlbumRecord::getTenantAlbumId).collect(Collectors.toList());
+            Map<Long, String> albumIdMap = tenantAlbumService.lambdaQuery()
+                    .in(TenantAlbum::getId, tenantAlbumIds)
+                    .list().stream().collect(Collectors.toMap(TenantAlbum::getId, TenantAlbum::getName));
+            //发送消息
+            userTenantAlbumRecords.forEach(record -> temporary3DaySend(record.getUserId(),record.getPhone(), albumIdMap.get(record.getTenantAlbumId())));
+            List<Long> ids = userTenantAlbumRecords.stream().map(UserTenantAlbumRecordWrapper.UserTenantAlbumRecord::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,1);
         }
-        //标识
-        Map<Long, Long> temporaryFlagMap = new HashMap<>();
-        for (UserTenantAlbumRecordWrapper.UserTenantAlbumRecord record : userTenantAlbumRecords) {
-            if (null != temporaryFlagMap.get(record.getUserId())) {
-                continue;
-            }
-            temporaryFlagMap.put(record.getUserId(), record.getUserId());
+        //即将到期的专辑
+        List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> userTenantAlbumRecords1 = baseMapper.selectTemporaryRecord1();
+        if (CollectionUtils.isNotEmpty(userTenantAlbumRecords1)) {
+            //获取专辑名称
+            List<Long> tenantAlbumIds = userTenantAlbumRecords1.stream().map(UserTenantAlbumRecordWrapper.UserTenantAlbumRecord::getTenantAlbumId).collect(Collectors.toList());
+            Map<Long, String> albumIdMap = tenantAlbumService.lambdaQuery()
+                    .in(TenantAlbum::getId, tenantAlbumIds)
+                    .list().stream().collect(Collectors.toMap(TenantAlbum::getId, TenantAlbum::getName));
             //发送消息
-            CompletableFuture.runAsync(() -> temporarySend(record.getUserId(), record.getTenantAlbumId()));
-            UserTenantAlbumRecord userTenantAlbumRecord = new UserTenantAlbumRecord();
-            userTenantAlbumRecord.setMsgStatus(true);
-            userTenantAlbumRecord.setUpdateTime(new Date());
-            userTenantAlbumRecord.setId(record.getId());
-
-            baseMapper.updateById(userTenantAlbumRecord);
+            userTenantAlbumRecords1.forEach(record -> temporarySend(record.getUserId(),record.getPhone(), albumIdMap.get(record.getTenantAlbumId())));
+            List<Long> ids = userTenantAlbumRecords1.stream().map(UserTenantAlbumRecordWrapper.UserTenantAlbumRecord::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,2);
         }
     }
 
@@ -747,24 +680,297 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
         return userTenantAlbumRecords;
     }
 
+    /**
+     * 扣除用户专辑记录
+     *
+     * @return
+     */
+    private int deductionRecord(UserTenantAlbumRecordWrapper.DeductionUserTenantAlbumRecord result) {
 
-    private void temporarySend(Long userId, Long tenantAlbumId) {
-        SysUser sysUser = sysUserFeignService.queryUserById(userId);
-        if (null == sysUser) {
-            return;
+        // 查找被扣除的记录
+        UserTenantAlbumRecord record = this.getById(result.getRecordId());
+        if (record == null) {
+            throw new BizException("记录不存在");
+        }
+        if (record.getDeductionTime() != null) {
+            throw new BizException("记录已扣除");
+        }
+        Date endTime = record.getEndTime();
+        if (endTime.before(new Date())) {
+            throw new BizException("记录已过期");
+        }
+
+        // 获取 剩余时长
+        int days =0;
+        if (record.getStartTime().before(new Date())) {
+            days = DateUtil.daysBetweenUp(new Date(), endTime);
+        } else {
+            days = DateUtil.daysBetweenUp(record.getStartTime(), endTime);
+        }
+        UserTenantAlbumRecord userTenantAlbumRecord = new UserTenantAlbumRecord();
+        userTenantAlbumRecord.setId(record.getId());
+        userTenantAlbumRecord.setDeductionTime(new Date());
+        userTenantAlbumRecord.setDeductionReason(result.getReason());
+        userTenantAlbumRecord.setEndTime(addTime(record.getEndTime(), PeriodEnum.DAY, -days,1));
+        userTenantAlbumRecord.setDeductionBy(result.getCreateBy());
+        userTenantAlbumRecord.setDeductionStatus(EDeductionStatus.DEDUCT);
+        if (record.getStartTime().after(userTenantAlbumRecord.getEndTime())) {
+            userTenantAlbumRecord.setEfficientFlag(false);
+        }
+        this.updateById(userTenantAlbumRecord);
+
+        // 对比剩余天数
+
+        // 获取其他有效的记录
+        List<UserTenantAlbumRecord> list = this.lambdaQuery()
+                .eq(UserTenantAlbumRecord::getUserId, record.getUserId())
+                .gt(UserTenantAlbumRecord::getEndTime, endTime)
+                .eq(UserTenantAlbumRecord::getEfficientFlag, 1)
+                .eq(UserTenantAlbumRecord::getTenantAlbumId, record.getTenantAlbumId())
+                .list();
+
+        if (CollectionUtils.isEmpty(list)) {
+            return days;
+        }
+        Date startTime = record.getStartTime();
+        if (startTime.after(new Date())) {
+            startTime = addTime(startTime, PeriodEnum.DAY, -1,1);
+        } else {
+            startTime = addTime(new Date(), PeriodEnum.DAY, -1,1);
+        }
+        List<UserTenantAlbumRecord> updateList = new ArrayList<>();
+        for (UserTenantAlbumRecord discountCardRecord : list) {
+            UserTenantAlbumRecord cardRecord = new UserTenantAlbumRecord();
+            cardRecord.setId(discountCardRecord.getId());
+            cardRecord.setStartTime(startTime);
+            cardRecord.setEndTime(addTime(cardRecord.getStartTime(), PeriodEnum.valueOf(discountCardRecord.getType()), discountCardRecord.getTimes(), 1));
+            formatVipRecordTime(cardRecord);
+            updateList.add(cardRecord);
+            startTime = cardRecord.getEndTime();
+        }
+        this.updateBatchById(updateList);
+
+
+        return days;
+
+    }
+
+    private Date addTime(Date time, PeriodEnum period, Integer times, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(time);
+
+        if (PeriodEnum.DAY.equals(period)) {
+            cal.add(Calendar.DAY_OF_MONTH, times);
+        } else if (PeriodEnum.MONTH.equals(period)) {
+            cal.add(Calendar.MONTH, times);
+        } else if (PeriodEnum.YEAR.equals(period)) {
+            cal.add(Calendar.YEAR, times);
+        } else if (PeriodEnum.PERPETUAL.equals(period)) {
+            cal.add(Calendar.YEAR, 100);
+        }
+        if (type ==0) {
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+        } else {
+            cal.set(Calendar.HOUR_OF_DAY, 23);
+            cal.set(Calendar.MINUTE, 59);
+            cal.set(Calendar.SECOND, 59);
+            cal.set(Calendar.MILLISECOND, 0);
+        }
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
+
+    private void temporary3DaySend(Long userId,String phone, String tenantAlbumName) {
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(userId, phone);
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_ALBUM_EXPIRE_THIRTY_DAY,
+                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(),tenantAlbumName);
+        } catch (Exception e) {
+            log.error("机构学生训练教材过期", e);
         }
-        TenantAlbum tenantAlbum = tenantAlbumService.getById(tenantAlbumId);
+    }
+
+
+    /**
+     * 扣减畅学卡
+     *
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deduction(UserTenantAlbumRecordWrapper.DeductionUserTenantAlbumRecord result) {
+        // 判断是否是生效中
+
+        UserTenantAlbumRecord discountCardRecord = this.getById(result.getRecordId());
+        if (discountCardRecord == null) {
+            throw new BizException("畅学卡记录不存在");
+        }
+        if (discountCardRecord.getEndTime().before(new Date())) {
+            throw new BizException("畅学卡已过期");
+        }
+
+
+        int days = deductionRecord(result);
+
+        studentService.updateVipStatus(result.getUserId());
+
+        TenantAlbum tenantAlbum = tenantAlbumMapper.selectById(discountCardRecord.getTenantAlbumId());
         if (tenantAlbum == null) {
             return;
         }
+
+        if (Boolean.TRUE.equals(result.getSendMsg())) {
+            ThreadUtil.execute(() -> sendVipDeductionMessage(result.getUserId(),-days
+                    ,discountCardRecord.getType().equals(PeriodEnum.PERPETUAL.name())?PeriodEnum.PERPETUAL:PeriodEnum.DAY,result.getReason(),tenantAlbum.getName()));
+        }
+    }
+
+    @Override
+    public IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> selectAdminPage(IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> page, UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query) {
+        List<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> records = baseMapper.selectAdminPage(page, query);
+        if (CollectionUtils.isEmpty(records)) {
+            return page;
+        }
+        List<Long> tenantAlbumIds = records.stream().map(UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord::getTenantAlbumId).distinct().collect(Collectors.toList());
+        Map<Long, TenantAlbum> albumIdMap = tenantAlbumService.getMapByIds(tenantAlbumIds);
+
+        // 创建人ID集合
+        List<Long> createByList = records.stream()
+                .map(UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord::getOperatorId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> userMap = sysUserService.getMapByIds(createByList);
+        records.forEach(userTenantAlbumRecord -> {
+
+            if (userTenantAlbumRecord.getStartTime().before(new Date())) {
+                userTenantAlbumRecord.setSurplusDay(DateUtil.daysBetweenUp(new Date(), userTenantAlbumRecord.getEndTime()));
+            } else {
+                userTenantAlbumRecord.setSurplusDay(DateUtil.daysBetweenUp(userTenantAlbumRecord.getStartTime(), userTenantAlbumRecord.getEndTime()));
+            }
+
+            com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = userMap.get(userTenantAlbumRecord.getOperatorId());
+            if (sysUser != null) {
+                userTenantAlbumRecord.setOperatorName(sysUser.getRealName());
+            }
+            TenantAlbum tenantAlbum = albumIdMap.get(userTenantAlbumRecord.getTenantAlbumId());
+            if (tenantAlbum != null) {
+                userTenantAlbumRecord.setTenantAlbumName(tenantAlbum.getName());
+            }
+        });
+        return page.setRecords(records);
+    }
+
+    @Override
+    public List<UserTenantAlbumRecordWrapper.Info> info(UserTenantAlbumRecordWrapper.InfoQuery infoQuery) {
+        List<UserTenantAlbumRecordWrapper.Info> infos = new ArrayList<>();
+
+        List<UserTenantAlbumRecord> list = this.lambdaQuery()
+                .eq(UserTenantAlbumRecord::getUserId, infoQuery.getUserId())
+                .eq(UserTenantAlbumRecord::getEfficientFlag, 1)
+                .gt(UserTenantAlbumRecord::getEndTime, new Date())
+                .list();
+        if (CollectionUtils.isEmpty(list)) {
+            return infos;
+        }
+        Map<Long, List<UserTenantAlbumRecord>> map = list.stream().collect(Collectors.groupingBy(UserTenantAlbumRecord::getTenantAlbumId));
+        List<Long> tenantAlbumIds = list.stream().map(UserTenantAlbumRecord::getTenantAlbumId).collect(Collectors.toList());
+        Map<Long, TenantAlbum> albumIdMap = tenantAlbumService.getMapByIds(tenantAlbumIds);
+        map.forEach((k, v) -> {
+            TenantAlbum tenantAlbum = albumIdMap.get(k);
+            if (tenantAlbum == null) {
+                return;
+            }
+            // 过滤出永久的
+            List<UserTenantAlbumRecord> collect = v.stream().filter(x -> x.getType().equals(PeriodEnum.PERPETUAL.name())).collect(Collectors.toList());
+            if (CollectionUtils.isNotEmpty(collect)) {
+                v.removeAll(collect);
+            }
+            UserTenantAlbumRecordWrapper.Info info = new UserTenantAlbumRecordWrapper.Info();
+            info.setTenantAlbumId(k);
+            info.setTenantAlbumName(tenantAlbum.getName());
+            info.setPerpetualFlag(CollectionUtils.isNotEmpty(collect));
+            int surplusDay = 0;
+            if (CollectionUtils.isNotEmpty(v)) {
+                Date endTime = v.get(0).getEndTime();
+                if (v.get(0).getStartTime().before(new Date())) {
+                    surplusDay += DateUtil.daysBetweenUp(new Date(), endTime);
+                } else {
+                    surplusDay += DateUtil.daysBetweenUp(v.get(0).getStartTime(), endTime);
+                }
+            }
+            info.setSurplusDay(surplusDay);
+            infos.add(info);
+        });
+        return infos;
+
+    }
+
+
+    private void sendVipDeductionMessage(Long userId, Integer num,PeriodEnum period,String reason,String tenantAlbumName) {
+        // 添加VIP时长短信
+        SysUser sysUser = sysUserService.getByUserId(userId);
+        if (sysUser == null) {
+            return;
+        }
+
         Map<Long, String> receivers = new HashMap<>();
-        receivers.put(userId, sysUser.getPhone());
+        receivers.put(sysUser.getId(), sysUser.getPhone());
+
+
+        // 短信
+        MessageTypeEnum messageTypeEnum = MessageTypeEnum.ADD_TENANT_ALBUM_JG;
+        if (num < 0) {
+            messageTypeEnum = MessageTypeEnum.DEDUCTION_TENANT_ALBUM_JG;
+        }
+        try {
+            String string = Math.abs(num) + period.getMsg();
+            if (period == PeriodEnum.PERPETUAL) {
+                string = "永久";
+            }
 
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, messageTypeEnum,receivers,
+                    null,0,null,ClientEnum.STUDENT.name()
+                    , string,tenantAlbumName,reason);
+        } catch (Exception e) {
+            log.error("消息发送失败 ", e);
+        }
+    }
+
+    private void temporarySend(Long userId,String phone, String tenantAlbumName) {
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(userId, phone);
         try {
             sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_ALBUM_EXPIRE,
-                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(), tenantAlbum.getName());
+                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(),tenantAlbumName);
         } catch (Exception e) {
             log.error("机构学生训练教材过期", e);
         }
+
+    }
+
+
+
+    public UserTenantAlbumRecord formatVipRecordTime(UserTenantAlbumRecord userTenantAlbumRecord) {
+        // 如果开始时间是23:59:59,开始时间改为第二天的00:00:00
+        LocalDateTime startTime = userTenantAlbumRecord.getStartTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (startTime.toLocalTime().equals(LocalTime.of(23, 59, 59))) {
+            startTime = startTime.plusDays(1);
+        }
+
+        startTime = startTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
+        // 如果结束时间是00:00:00,开始时间改为前一天的23:59:59
+        LocalDateTime endTime = userTenantAlbumRecord.getEndTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (endTime.toLocalTime().equals(LocalTime.of(0, 0, 0))) {
+            endTime = endTime.plusDays(-1);
+        }
+        endTime = endTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
+        userTenantAlbumRecord.setStartTime(Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()));
+        userTenantAlbumRecord.setEndTime(Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
+        if (userTenantAlbumRecord.getStartTime().after(userTenantAlbumRecord.getEndTime())) {
+            userTenantAlbumRecord.setEndTime(userTenantAlbumRecord.getStartTime());
+        }
+        return userTenantAlbumRecord;
     }
 }

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

@@ -9,9 +9,7 @@ import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.MemberPriceSettingsDao;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
-import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
-import com.yonge.cooleshow.biz.dal.entity.MemberPriceSettings;
-import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.*;
@@ -20,21 +18,21 @@ import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.date.DateUtil;
+import org.jetbrains.annotations.NotNull;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
 import com.yonge.cooleshow.biz.dal.dto.search.VipCardRecordSearch;
 import com.yonge.cooleshow.biz.dal.dao.VipCardRecordDao;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.ZoneId;
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 
 
@@ -61,6 +59,12 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     @Autowired
     private SysUserService sysUserService;
 
+    @Autowired
+    private DiscountCardRecordService discountCardRecordService;
+
+    @Autowired
+    private UserTenantAlbumRecordService userTenantAlbumRecordService;
+
 
     @Override
     public VipCardRecordVo detail(Long orderDetilId) {
@@ -204,51 +208,43 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
 
     @Override
     public void pollExpireMsg() {
-        //提前三天提示
+        //会员提前三天提示
         List<VipCardRecordVo> temporaryRecords = baseMapper.selectTemporaryRecord();
-        //标识
-        Set<String> sendFlag = new HashSet<>();
-        for (VipCardRecordVo record : temporaryRecords) {
-            String key = record.getUserId() + "_" + record.getVipType().getCode() + "_" + record.getClientType().getCode();
-            if (sendFlag.contains(key)) {
-                continue;
+        if(CollectionUtils.isNotEmpty(temporaryRecords)){
+            Map<ClientEnum,List<VipCardRecordVo>> map = temporaryRecords.stream().collect(Collectors.groupingBy(VipCardRecordVo::getClientType));
+            //区分老师学生
+            for (Map.Entry<ClientEnum, List<VipCardRecordVo>> entry : map.entrySet()) {
+                List<VipCardRecordVo> list = entry.getValue();
+                //区分会员类型
+                Map<EVipType,List<VipCardRecordVo>> map1 = list.stream().collect(Collectors.groupingBy(VipCardRecordVo::getVipType));
+                map1.forEach((k,v)->{
+                    Map<Long, String> receivers = v.stream().collect(Collectors.toMap(VipCardRecordVo::getUserId, VipCardRecordVo::getPhone));
+                    temporary3DaysSend(receivers, entry.getKey(), k);
+                });
             }
-            sendFlag.add(key);
-            //发送消息
-            CompletableFuture.runAsync(() -> {
-                temporary3DaysSend(record.getUserId(), record.getPhone(), record.getClientType(), record.getVipType());
-            });
-            record.setMsgStatus(1);
-            record.setUpdateTime(new Date());
-
-            VipCardRecord vipCardRecord = new VipCardRecord();
-            BeanUtils.copyProperties(record, vipCardRecord);
-            baseMapper.updateById(vipCardRecord);
+            //更新状态
+            List<Long> ids = temporaryRecords.stream().map(VipCardRecordVo::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,1);
         }
 
-        //到期提示
+        //会员到期提示
         List<VipCardRecordVo> expireRecords = baseMapper.selectExpireRecord();
-        //标识
-        Set<String> expireSendFlag = new HashSet<>();
-        for (VipCardRecordVo record : expireRecords) {
-            String key = record.getUserId() + "_" + record.getVipType().getCode() + "_" + record.getClientType().getCode();
-            if (expireSendFlag.contains(key)) {
-                continue;
+        if (CollectionUtils.isNotEmpty(expireRecords)){
+            Map<ClientEnum,List<VipCardRecordVo>> map = expireRecords.stream().collect(Collectors.groupingBy(VipCardRecordVo::getClientType));
+            //区分老师学生
+            for (Map.Entry<ClientEnum, List<VipCardRecordVo>> entry : map.entrySet()) {
+                List<VipCardRecordVo> list = entry.getValue();
+                //区分会员类型
+                Map<EVipType,List<VipCardRecordVo>> map1 = list.stream().collect(Collectors.groupingBy(VipCardRecordVo::getVipType));
+                map1.forEach((k,v)->{
+                    Map<Long, String> receivers = v.stream().collect(Collectors.toMap(VipCardRecordVo::getUserId, VipCardRecordVo::getPhone));
+                    expireSend(receivers, entry.getKey(), k);
+                });
             }
-            expireSendFlag.add(key);
-            //发送消息
-            //发送消息
-            CompletableFuture.runAsync(() -> {
-                expireSend(record.getUserId(),record.getPhone(), record.getClientType(), record.getVipType());
-            });
-            record.setMsgStatus(2);
-            record.setUpdateTime(new Date());
-
-            VipCardRecord vipCardRecord = new VipCardRecord();
-            BeanUtils.copyProperties(record, vipCardRecord);
-            baseMapper.updateById(vipCardRecord);
+            //更新状态
+            List<Long> ids = expireRecords.stream().map(VipCardRecordVo::getId).collect(Collectors.toList());
+            baseMapper.updateMsgStatus(ids,2);
         }
-
     }
 
     @Override
@@ -433,13 +429,39 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
             Integer vipDays = addVipCardRecord.getVipDays();
             // 存在转换,先扣除,再添加
             if (vipDays != null && vipDays > 0) {
-                VipCardRecordWrapper.AddVipCardRecord dedectRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecordWrapper.AddVipCardRecord.class);
-                dedectRecord.setStatus(EVipRecordStatus.DEDUCTION);
-                dedectRecord.setVipType(EVipType.VIP);
-                dedectRecord.setType(PeriodEnum.DAY);
-                dedectRecord.setTimes(vipDays);
-                dedectRecord.setReason("后台转换扣减");
-                deductVip(dedectRecord);
+
+                // 转换的 ,找到转换的记录,设置为失效,修改时间,添加一条转换后的记录 订单与添加转换订单一致
+                List<VipCardRecord> vipCardRecords = getVipCardRecords(addVipCardRecord.getUserId(), clientType, Lists.newArrayList(EVipType.VIP));
+                int vipDaysNum = vipDays;
+                if (CollectionUtils.isNotEmpty(vipCardRecords)) {
+                    // 根据结束时间正序
+                    vipCardRecords.sort(Comparator.comparing(VipCardRecord::getEndTime));
+                    List<VipCardRecord> vipCardRecordList = new ArrayList<>();
+                    for (VipCardRecord vipCardRecord : vipCardRecords) {
+                        int i = DateUtil.daysBetweenUp(vipCardRecord.getStartTime(), vipCardRecord.getEndTime());
+                        VipCardRecord record = new VipCardRecord();
+                        record.setId(vipCardRecord.getId());
+                        if (vipDaysNum == 0) {
+                            record.setStartTime(addTime(vipCardRecord.getStartTime(), PeriodEnum.DAY, -vipDaysNum,0));
+                            record.setEndTime(addTime(vipCardRecord.getEndTime(), PeriodEnum.DAY, -vipDaysNum,1));
+                        } else if (i > vipDaysNum) {
+                            record.setEndTime(addTime(vipCardRecord.getEndTime(), PeriodEnum.DAY, -vipDaysNum,1));
+                            record.setEfficientFlag(true);
+                            record.setDisplayFlag(true);
+                            record.setReason("后台转换扣减");
+                            record.setUpdateTime(new Date());
+                        } else {
+                            record.setEfficientFlag(false);
+                            record.setDeductionStatus(EDeductionStatus.EXPIRED);
+                            record.setUpdateTime(new Date());
+                            record.setReason("后台转换扣减");
+                            vipDaysNum = vipDaysNum - i;
+                        }
+                        vipCardRecordList.add(record);
+                    }
+                    this.updateBatchById(vipCardRecordList);
+                }
+
 
                 VipCardRecordWrapper.AddVipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecordWrapper.AddVipCardRecord.class);
                 addRecord.setStatus(EVipRecordStatus.ADD);
@@ -458,8 +480,11 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
             }
         }
 
+        studentService.updateVipStatus(addVipCardRecord.getUserId());
+
         if (Boolean.TRUE.equals(addVipCardRecord.getSendMsg())) {
-            sendAddVipMsg(addVipCardRecord);
+            sendAddVipMsg(addVipCardRecord.getUserId(),addVipCardRecord.getClientType(),addVipCardRecord.getStatus(),
+                    addVipCardRecord.getVipType(),addVipCardRecord.getType(),addVipCardRecord.getTimes(),addVipCardRecord.getReason());
         }
     }
 
@@ -488,38 +513,16 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     // 会员添加
     @Override
     public VipCardRecord addVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
-        List<VipCardRecord> vipCardRecordList = this.lambdaQuery()
-                .eq(VipCardRecord::getClientType, addVipCardRecord.getClientType())
-                .eq(VipCardRecord::getUserId, addVipCardRecord.getUserId())
-                .ge(VipCardRecord::getEndTime, new Date())
-                .eq(VipCardRecord::getEfficientFlag, true)
-                .list()
-                .stream()
-//                .filter(n -> n.getEndTime() == null || n.getEndTime().after(new Date()))
-                .sorted(Comparator.comparing(VipCardRecord::getStartTime))
-                .collect(Collectors.toList());
+        List<VipCardRecord> vipCardRecordList = getVipCardRecords(addVipCardRecord.getUserId(),addVipCardRecord.getClientType(), Lists.newArrayList(EVipType.VIP,EVipType.SVIP));
 
 
         EVipType addVipType = addVipCardRecord.getVipType();
-//        List<VipCardRecord> perpetualRecords = vipCardRecordList.stream()
-//                .filter(n -> n.getVipType().equals(addVipType) && PeriodEnum.PERPETUAL.equals(n.getType()))
-//                .collect(Collectors.toList());
-//        if (!perpetualRecords.isEmpty()) {
-//            throw new BizException("已经是永久会员");
-//        }
-
         Date now = new Date();
-        long startTimeMills = now.getTime();
+        Date startDate = now;
         // 没有会员信息
         if (vipCardRecordList.isEmpty()) {
             PeriodEnum period = addVipCardRecord.getType();
-            Calendar calendar = Calendar.getInstance();
-            calendar.setTime(now);
-            calendar.set(Calendar.HOUR_OF_DAY, 23);
-            calendar.set(Calendar.MINUTE, 59);
-            calendar.set(Calendar.SECOND, 59);
-            calendar.set(Calendar.MILLISECOND, 0);
-            Date endDate = plusDate(calendar.getTime(), period, Long.valueOf(addVipCardRecord.getTimes()));
+
 
             VipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
             addRecord.setSourceType(addVipCardRecord.getSourceType() !=null?addVipCardRecord.getSourceType():SourceTypeEnum.BACKEND_GIVE);
@@ -527,74 +530,94 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
             addRecord.setDisplayFlag(true);
             addRecord.setEfficientFlag(true);
             addRecord.setStartTime(now);
-            addRecord.setEndTime(endDate);
+            addRecord.setVersion(2);
+            addRecord.setEndTime(addTime(addRecord.getStartTime(), period, addRecord.getTimes(),1));
+            formatVipRecordTime(addRecord);
+
+            addRecord.setEstimatedEndTime(addRecord.getEndTime());
+            addRecord.setEstimatedStartTime(addRecord.getStartTime());
             return addRecord;
         }
 
-        // 找到插入数据的位置
-        int index = 0;
         if (addVipType.equals(EVipType.VIP)) { // vip 放到最后
-            index = vipCardRecordList.size();
-            startTimeMills = vipCardRecordList.stream().map(VipCardRecord::getEndTime).max(Date::compareTo).get().getTime() + 1000L;
-        }
-        if (addVipType.equals(EVipType.SVIP)) { //放到VIP的前面
-            index = (int) vipCardRecordList.stream().filter(n -> EVipType.SVIP.equals(n.getVipType()) && !PeriodEnum.PERPETUAL.equals(n.getType())).count();
-            if (index > 0) {
-                startTimeMills = vipCardRecordList.stream().filter(n -> EVipType.SVIP.equals(n.getVipType()) && !PeriodEnum.PERPETUAL.equals(n.getType()))
-                        .map(VipCardRecord::getEndTime).max(Date::compareTo).get().getTime() + 1000;
+            startDate = vipCardRecordList.stream().map(VipCardRecord::getEndTime).max(Date::compareTo).get();
+        } else if (addVipType.equals(EVipType.SVIP)) { //放到VIP的前面
+            Optional<VipCardRecord> max = vipCardRecordList.stream().filter(o -> o.getVipType().equals(EVipType.SVIP)).max(Comparator.comparing(VipCardRecord::getEndTime));
+            if (max.isPresent()) {
+                startDate = max.get().getEndTime();
             }
         }
 
         VipCardRecord newRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
         newRecord.setSourceType(addVipCardRecord.getSourceType() !=null?addVipCardRecord.getSourceType():SourceTypeEnum.BACKEND_GIVE);
         newRecord.setStatus(EVipRecordStatus.ADD);
-        newRecord.setStartTime(new Date(startTimeMills));
-        if (index == 0) { // 当天剩余时间属于赠送
-            Calendar calendar = Calendar.getInstance();
-            calendar.setTime(new Date(startTimeMills));
-            calendar.set(Calendar.HOUR_OF_DAY, 23);
-            calendar.set(Calendar.MINUTE, 59);
-            calendar.set(Calendar.SECOND, 59);
-            calendar.set(Calendar.MILLISECOND, 0);
-            Date endDate = plusDate(calendar.getTime(), addVipCardRecord.getType(), Long.valueOf(addVipCardRecord.getTimes()));
-            newRecord.setEndTime(new Date(endDate.getTime()));
-        } else {
-            Date endDate = plusDate(new Date(startTimeMills - 1000), addVipCardRecord.getType(), Long.valueOf(addVipCardRecord.getTimes()));
-            newRecord.setEndTime(endDate);
-        }
+        newRecord.setStartTime(startDate);
+        newRecord.setEndTime(addTime(newRecord.getStartTime(), addVipCardRecord.getType(), addVipCardRecord.getTimes(),1));
 
         newRecord.setDisplayFlag(true);
         newRecord.setEfficientFlag(true);
 
-        // 平移时间
-//        long plusMills = newRecord.getEndTime().getTime() - startTimeMills;
-        long beforeEndTime = newRecord.getEndTime().getTime();
-        for (int i = 0; i < vipCardRecordList.size(); i++) {
-            VipCardRecord vipCardRecord = vipCardRecordList.get(i);
-            if (i >= index) {
-                VipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
-                addRecord.setStatus(EVipRecordStatus.UPDATE);
-
-                addRecord.setStartTime(new Date(beforeEndTime + 1000));
-
-//                int days = (int) Math.ceil(plusMills * 1.0D / (24 * 60 * 60 * 1000));
-                Date endTime = plusDate(vipCardRecord.getEndTime(), addVipCardRecord.getType(), addVipCardRecord.getTimes());
-                addRecord.setEndTime(endTime);
-                addRecord.setDisplayFlag(false);
-                addRecord.setEfficientFlag(true);
-                save(addRecord);
-                Long refId = addRecord.getId();
+        // 如果是SVIP,平移VIP
+        List<VipCardRecord> vipList = vipCardRecordList.stream().filter(o -> o.getVipType() == EVipType.VIP).collect(Collectors.toList());
+        if (addVipType.equals(EVipType.SVIP) && CollectionUtils.isNotEmpty(vipList)) {
+            // 更新开始时间/结束时间
+            List<VipCardRecord> updateList = new ArrayList<>();
+            for (VipCardRecord vipCardRecord : vipList) {
+                formatVipRecordTime(vipCardRecord);
+
+                // 如果开始时间小于当前时间, 切分过去的时间为一段记录,并且不显示,剩余的时间为一段记录,标记为显示并且生效中
+                if (vipCardRecord.getStartTime().before(now)) {
+                    VipCardRecord record = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                    record.setStartTime(vipCardRecord.getStartTime());
+                    record.setEndTime(addTime(now,PeriodEnum.DAY,-1,1));
+                    record.setEfficientFlag(true);
+                    if (record.getStartTime().after(record.getEndTime())) {
+                        record.setEfficientFlag(false);
+                    }
+                    record.setDeductionStatus(EDeductionStatus.EXPIRED);
+                    record.setDisplayFlag(false);
+                    record.setVersion(2);
+                    save(record);
+                    if (newRecord.getStartTime().after(now)) {
+                        vipCardRecord.setStartTime(addTime(now,PeriodEnum.DAY,0,0));
+                    } else {
+                        vipCardRecord.setStartTime(addTime(now,PeriodEnum.DAY,1,0));
+                    }
+                    vipCardRecord.setStatus(EVipRecordStatus.UPDATE);
+                }
 
-                VipCardRecord updateRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
-                updateRecord.setEfficientFlag(false);
-                updateRecord.setRefId(refId);
-                updateById(updateRecord);
-                beforeEndTime = endTime.getTime();
+                VipCardRecord record = new VipCardRecord();
+                record.setStartTime(addTime(vipCardRecord.getStartTime(), addVipCardRecord.getType(), addVipCardRecord.getTimes(),0));
+                record.setEndTime(addTime(vipCardRecord.getEndTime(), addVipCardRecord.getType(), addVipCardRecord.getTimes(),1));
+                record.setStatus(vipCardRecord.getStatus());
+                record.setId(vipCardRecord.getId());
+                updateList.add(record);
             }
+            updateBatchById(updateList);
         }
+        newRecord.setDeductionStatus(EDeductionStatus.EFFECTIVE);
+        newRecord.setVersion(2);
+        formatVipRecordTime(newRecord);
+        newRecord.setEstimatedEndTime(newRecord.getEndTime());
+        newRecord.setEstimatedStartTime(newRecord.getStartTime());
         return newRecord;
     }
 
+    @NotNull
+    private List<VipCardRecord> getVipCardRecords(Long userId,ClientEnum client, List<EVipType> vipTypes) {
+        List<VipCardRecord> vipCardRecordList = this.lambdaQuery()
+                .eq(VipCardRecord::getClientType, client)
+                .eq(VipCardRecord::getUserId, userId)
+                .in(CollectionUtils.isNotEmpty(vipTypes),VipCardRecord::getVipType, vipTypes)
+                .ge(VipCardRecord::getEndTime, new Date())
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .list()
+                .stream()
+                .sorted(Comparator.comparing(VipCardRecord::getStartTime))
+                .collect(Collectors.toList());
+        return vipCardRecordList;
+    }
+
     @Override
     public List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(List<Long> userIdList, String clientType) {
         List<VipCardRecordWrapper.UserVipInfo> userVipInfos = baseMapper.queryUserVipInfo(userIdList, clientType);
@@ -611,19 +634,234 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     }
 
 
+    /**
+     * 扣减会员
+     *
+     * @param result
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deduction(VipCardRecordWrapper.DeductionVipCardRecord result) {
+
+        // 查找被扣除的记录
+        VipCardRecord record = this.getById(result.getRecordId());
+        if (record == null) {
+            throw new BizException("记录不存在");
+        }
+        if (record.getDeductionTime() != null) {
+            throw new BizException("记录已扣除");
+        }
+        Date endTime = record.getEndTime();
+        if (endTime.before(new Date())) {
+            throw new BizException("记录已过期");
+        }
+
+        // 获取 剩余时长
+        int days =0;
+        if (record.getStartTime().before(new Date())) {
+            days = DateUtil.daysBetweenUp(new Date(), endTime);
+        } else {
+            days = DateUtil.daysBetweenUp(record.getStartTime(), endTime);
+        }
+        VipCardRecord vipCardRecord = new VipCardRecord();
+        vipCardRecord.setId(record.getId());
+        vipCardRecord.setDeductionTime(new Date());
+        vipCardRecord.setDeductionReason(result.getReason());
+        vipCardRecord.setEndTime(addTime(record.getEndTime(), PeriodEnum.DAY, -days,1));
+        vipCardRecord.setDeductionBy(result.getCreateBy());
+        vipCardRecord.setDeductionStatus(EDeductionStatus.DEDUCT);
+        if (record.getStartTime().after(vipCardRecord.getEndTime())) {
+            vipCardRecord.setEfficientFlag(false);
+        }
+        this.updateById(vipCardRecord);
+
+        // 对比剩余天数
+
+        // 获取其他有效的记录
+        List<VipCardRecord> list = this.lambdaQuery()
+                .eq(VipCardRecord::getUserId, record.getUserId())
+                .gt(VipCardRecord::getEndTime, endTime)
+                .eq(VipCardRecord::getEfficientFlag, 1)
+                .list();
+
+        Date startTime = record.getStartTime();
+        if (startTime.after(new Date())) {
+            startTime = addTime(startTime, PeriodEnum.DAY, -1,1);
+        } else {
+            startTime = addTime(new Date(), PeriodEnum.DAY, -1,1);
+        }
+        if (CollectionUtils.isNotEmpty(list)) {
+            List<VipCardRecord> updateList = new ArrayList<>();
+            for (VipCardRecord vipCardRecord1 : list) {
+                VipCardRecord cardRecord = new VipCardRecord();
+                cardRecord.setId(vipCardRecord1.getId());
+                if (vipCardRecord1.getStatus() == EVipRecordStatus.UPDATE) {
+                    cardRecord.setStartTime(addTime(vipCardRecord1.getStartTime(), PeriodEnum.DAY, -days,0));
+                    cardRecord.setEndTime(addTime(vipCardRecord1.getEndTime(), PeriodEnum.DAY, -days,1));
+                } else {
+                    cardRecord.setStartTime(startTime);
+                    cardRecord.setEndTime(addTime(cardRecord.getStartTime(), vipCardRecord1.getType(), vipCardRecord1.getTimes(), 1));
+                }
+                formatVipRecordTime(cardRecord);
+                updateList.add(cardRecord);
+                startTime = cardRecord.getEndTime();
+            }
+            this.updateBatchById(updateList);
+        }
+
+
+        studentService.updateVipStatus(result.getUserId());
+        if (Boolean.TRUE.equals(result.getSendMsg())) {
+            sendAddVipMsg(record.getUserId(),record.getClientType(),EVipRecordStatus.DEDUCTION,
+                    record.getVipType(),record.getType(),record.getTimes(),result.getReason());
+        }
+    }
+
+
+    /**
+     *
+     *  获取会员信息
+     *
+     */
+    @Override
+    public VipCardRecordWrapper.Info info(VipCardRecordWrapper.InfoQuery infoQuery) {
+        VipCardRecordWrapper.Info info = new VipCardRecordWrapper.Info();
+
+        // 所有的会员重新生成
+        List<VipCardRecord> vipCardRecordList = getVipCardRecords(infoQuery.getUserId(),infoQuery.getClient(), Lists.newArrayList(EVipType.VIP,EVipType.SVIP));
+        if (CollectionUtils.isEmpty(vipCardRecordList)) {
+            return info;
+        }
+        // 过滤出会员
+        List<VipCardRecord> vipList = vipCardRecordList.stream().filter(o -> o.getVipType() == EVipType.VIP).collect(Collectors.toList());
+        // 计算天数
+        int vipDays = 0;
+        if (CollectionUtils.isNotEmpty(vipList)) {
+            vipDays = vipList.stream().mapToInt(o -> DateUtil.daysBetweenUp(o.getStartTime(), o.getEndTime())).sum();
+        }
+        info.setSurplusVipDay(vipDays);
+        // 过滤出SVIP
+        List<VipCardRecord> svipList = vipCardRecordList.stream().filter(o -> o.getVipType() == EVipType.SVIP && o.getType() !=PeriodEnum.PERPETUAL).collect(Collectors.toList());
+        // 计算天数
+        int svipDays = 0;
+        if (CollectionUtils.isNotEmpty(svipList)) {
+            svipDays = svipList.stream().mapToInt(o -> DateUtil.daysBetweenUp(o.getStartTime(), o.getEndTime())).sum();
+        }
+        info.setSurplusSvipDay(svipDays);
+        // 过滤出永久SVIP
+        List<VipCardRecord> svipPerpetualList = vipCardRecordList.stream().filter(o -> o.getVipType() == EVipType.SVIP && o.getType() ==PeriodEnum.PERPETUAL).collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(svipPerpetualList)) {
+            info.setPerpetualFlag(true);
+        }
+        return info;
+    }
+
+    @Override
+    public IPage<VipCardRecordWrapper.VipCardRecord> selectAdminPage(IPage<VipCardRecordWrapper.VipCardRecord> page, VipCardRecordWrapper.VipQuery query) {
+        IPage<VipCardRecordWrapper.VipCardRecord> vipCardRecordIPage = baseMapper.selectAdminPage(page, query);
+        List<VipCardRecordWrapper.VipCardRecord> records = vipCardRecordIPage.getRecords();
+        if (CollectionUtils.isEmpty(records)) {
+            return vipCardRecordIPage;
+        }
+        // 创建人ID集合
+        List<Long> createByList = records.stream()
+                .map(VipCardRecordWrapper.VipCardRecord::getOperatorId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> userMap = sysUserService.getMapByIds(createByList);
+        records.forEach(vipCardRecord -> {
+
+            if (vipCardRecord.getStartTime().before(new Date())) {
+                vipCardRecord.setSurplusDay(DateUtil.daysBetweenUp(new Date(), vipCardRecord.getEndTime()));
+            } else {
+                vipCardRecord.setSurplusDay(DateUtil.daysBetweenUp(vipCardRecord.getStartTime(), vipCardRecord.getEndTime()));
+            }
+
+            com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = userMap.get(vipCardRecord.getOperatorId());
+            if (sysUser != null) {
+                vipCardRecord.setOperatorName(sysUser.getRealName());
+            }
+        });
+        return vipCardRecordIPage;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public List<Long> updateUserVipStatus() {
+        // 更新会员状态
+        List<VipCardRecord> vipCardRecords = this.lambdaQuery()
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .eq(VipCardRecord::getDeductionStatus, EDeductionStatus.EFFECTIVE)
+                .lt(VipCardRecord::getEndTime, new Date())
+                .list();
+        if (CollectionUtils.isNotEmpty(vipCardRecords)) {
+            List<VipCardRecord> updateList = new ArrayList<>();
+            for (VipCardRecord vipCardRecord : vipCardRecords) {
+                VipCardRecord record = new VipCardRecord();
+                record.setId(vipCardRecord.getId());
+                record.setDeductionStatus(EDeductionStatus.EXPIRED);
+                updateList.add(record);
+            }
+            this.updateBatchById(updateList);
+        }
+        // 更新畅学卡状态
+        List<DiscountCardRecord> discountCardRecords = discountCardRecordService.lambdaQuery()
+                .eq(DiscountCardRecord::getEfficientFlag, true)
+                .lt(DiscountCardRecord::getEndTime, new Date())
+                .eq(DiscountCardRecord::getDeductionStatus, EDeductionStatus.EFFECTIVE)
+                .list();
+        if (CollectionUtils.isNotEmpty(discountCardRecords)) {
+            List<DiscountCardRecord> updateList = new ArrayList<>();
+            for (DiscountCardRecord discountCardRecord : discountCardRecords) {
+                DiscountCardRecord record = new DiscountCardRecord();
+                record.setId(discountCardRecord.getId());
+                record.setDeductionStatus(EDeductionStatus.EXPIRED);
+                updateList.add(record);
+            }
+            discountCardRecordService.updateBatchById(updateList);
+        }
+        // 更新机构专辑状态
+        List<UserTenantAlbumRecord> userTenantAlbumRecords = userTenantAlbumRecordService.lambdaQuery()
+                .eq(UserTenantAlbumRecord::getEfficientFlag, true)
+                .lt(UserTenantAlbumRecord::getEndTime, new Date())
+                .eq(UserTenantAlbumRecord::getDeductionStatus, EDeductionStatus.EFFECTIVE)
+                .list();
+        if (CollectionUtils.isNotEmpty(userTenantAlbumRecords)) {
+            List<UserTenantAlbumRecord> updateList = new ArrayList<>();
+            for (UserTenantAlbumRecord userTenantAlbumRecord : userTenantAlbumRecords) {
+                UserTenantAlbumRecord record = new UserTenantAlbumRecord();
+                record.setId(userTenantAlbumRecord.getId());
+                record.setDeductionStatus(EDeductionStatus.EXPIRED);
+                updateList.add(record);
+            }
+            userTenantAlbumRecordService.updateBatchById(updateList);
+        }
+
+        // 更新学生表 权益字段
+        List<Long> userIds = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(vipCardRecords)) {
+            userIds.addAll(vipCardRecords.stream()
+                    .filter(o->o.getClientType() == ClientEnum.STUDENT)
+                    .map(VipCardRecord::getUserId).distinct().collect(Collectors.toList()));
+        }
+        if (CollectionUtils.isNotEmpty(discountCardRecords)) {
+            userIds.addAll(discountCardRecords.stream()
+                    .map(DiscountCardRecord::getUserId).distinct().collect(Collectors.toList()));
+        }
+        if (CollectionUtils.isNotEmpty(userTenantAlbumRecords)) {
+            userIds.addAll(userTenantAlbumRecords.stream()
+                    .map(UserTenantAlbumRecord::getUserId).distinct().collect(Collectors.toList()));
+        }
+
+
+        return userIds;
+
+    }
+
+
     // 会员扣减
     private VipCardRecord deductVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
 
         // 所有的会员重新生成
-        List<VipCardRecord> vipCardRecordList = this.lambdaQuery()
-                .eq(VipCardRecord::getClientType, addVipCardRecord.getClientType())
-                .eq(VipCardRecord::getUserId, addVipCardRecord.getUserId())
-                .ge(VipCardRecord::getEndTime, new Date())
-                .eq(VipCardRecord::getEfficientFlag, true)
-                .list()
-                .stream()
-                .sorted(Comparator.comparing(VipCardRecord::getStartTime))
-                .collect(Collectors.toList());
+        List<VipCardRecord> vipCardRecordList = getVipCardRecords(addVipCardRecord.getUserId(),addVipCardRecord.getClientType(), Lists.newArrayList(EVipType.VIP,EVipType.SVIP));
 
         // 当前类型的VIP
         PeriodEnum period = addVipCardRecord.getType();
@@ -854,78 +1092,48 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     }
 
     // 发送会员到期3天消息推送
-    private void temporary3DaysSend(Long userId, String phone, ClientEnum clientType, EVipType vipType) {
-        Map<Long, String> receivers = new HashMap<>();
-        receivers.put(userId, phone);
-        // 判断是否是机构学生 机构学生推送走另一个
-        if (clientType.equals(ClientEnum.STUDENT)) {
-            Student student = studentService.getById(userId);
-            if (student == null || (student.getTenantId() != null && student.getTenantId() > 0 )) {
-                return;
-            }
-        }
-        try {
-            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
-                    EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.SVIP_EXPIRE_THIRTY_DAY
-                    , receivers, null, 0, null, clientType.getCode());
-        } catch (Exception e) {
-            log.error("会员到期3天极光消息推送异常,userId={}", userId);
-        }
-
+    private void temporary3DaysSend(Map<Long, String> receivers, ClientEnum clientType, EVipType vipType) {
         try {
-            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
-                    EVipType.VIP.equals(vipType) ? MessageTypeEnum.SMS_VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.SMS_SVIP_EXPIRE_THIRTY_DAY
+            MessageTypeEnum messageTypeEnum;
+            if(clientType.equals(ClientEnum.TEACHER)){
+                messageTypeEnum = EVipType.VIP.equals(vipType) ? MessageTypeEnum.TEACHER_VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.TEACHER_SVIP_EXPIRE_THIRTY_DAY;
+            }else {
+                messageTypeEnum = EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.SVIP_EXPIRE_THIRTY_DAY;
+            }
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,messageTypeEnum
                     , receivers, null, 0, null, clientType.getCode());
         } catch (Exception e) {
-            log.error("会员到期3天短信消息推送异常,userId={}", userId);
+            log.error("会员到期3天极光消息推送异常");
         }
     }
 
     // 发送会员到期消息推送
-    private void expireSend(Long userId,String phone,ClientEnum userType, EVipType vipType) {
-        Map<Long, String> receivers = new HashMap<>();
-        receivers.put(userId, phone);
-        Student student = studentService.getById(userId);
-        if (userType.equals(ClientEnum.STUDENT) && student != null  && student.getTenantId() != null && student.getTenantId() >0) {
-//            try {
-//                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_VIP_EXPIRE,
-//                        receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode());
-//            } catch (Exception e) {
-//                log.error("会员到期极光消息推送异常,userId={}", userId);
-//            }
-        } else {
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
-                        EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE : MessageTypeEnum.SVIP_EXPIRE
-                        ,receivers, null, 0, null, userType.getCode());
-            } catch (Exception e) {
-                log.error("会员到期3天极光消息推送异常,userId={}", userId);
-            }
-
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
-                        EVipType.VIP.equals(vipType) ? MessageTypeEnum.SMS_VIP_EXPIRE : MessageTypeEnum.SMS_SVIP_EXPIRE,
-                        receivers, null, 0, null, userType.getCode());
-            } catch (Exception e) {
-                log.error("会员到期3天短信消息推送异常,userId={}", userId);
+    private void expireSend(Map<Long, String> receivers,ClientEnum userType, EVipType vipType) {
+        try {
+            MessageTypeEnum messageTypeEnum;
+            if(userType.equals(ClientEnum.TEACHER)){
+                messageTypeEnum = EVipType.VIP.equals(vipType) ? MessageTypeEnum.TEACHER_VIP_EXPIRE : MessageTypeEnum.TEACHER_SVIP_EXPIRE;
+            }else {
+                messageTypeEnum = EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE : MessageTypeEnum.SVIP_EXPIRE;
             }
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,messageTypeEnum
+                    ,receivers, null, 0, null, userType.getCode());
+        } catch (Exception e) {
+            log.error("会员到期极光消息推送异常");
         }
     }
 
     // 添加、扣除会员发送推送
-    private void sendAddVipMsg(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
-        SysUser sysUser = sysUserService.getByUserId(addVipCardRecord.getUserId());
+    private void sendAddVipMsg(Long userId,ClientEnum client,EVipRecordStatus status,EVipType vipType,PeriodEnum period,Integer times,String reason) {
+        SysUser sysUser = sysUserService.getByUserId(userId);
         if (sysUser == null) {
             return;
         }
         MessageTypeEnum messageTypeEnum;
-        EVipRecordStatus status = addVipCardRecord.getStatus();
-        EVipType vipType = addVipCardRecord.getVipType();
         if (EVipRecordStatus.ADD.equals(status)) {
             if (EVipType.VIP.equals(vipType)) {
                 messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_VIP;
             }else {
-                PeriodEnum period = addVipCardRecord.getType();
                 if (PeriodEnum.PERPETUAL.equals(period)) {
                     messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_PER_SVIP;
                 } else {
@@ -936,7 +1144,6 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
             if (EVipType.VIP.equals(vipType)) {
                 messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_DUDECT_VIP;
             }else {
-                PeriodEnum period = addVipCardRecord.getType();
                 if (PeriodEnum.PERPETUAL.equals(period)) {
                     messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_DUDECT_PER_SVIP;
                 } else {
@@ -948,17 +1155,49 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         }
 
         Map<Long, String> receivers = new HashMap<>();
-        receivers.put(addVipCardRecord.getUserId(), sysUser.getPhone());
+        receivers.put(userId, sysUser.getPhone());
 
         try {
             sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, messageTypeEnum,
-                    receivers, null, 0, null, addVipCardRecord.getClientType().getCode(), String.valueOf(addVipCardRecord.getTimes()), addVipCardRecord.getType().getMsg(),
-                    addVipCardRecord.getReason());
+                    receivers, null, 0, null, client.getCode(), String.valueOf(times), period.getMsg(),
+                    reason);
         } catch (Exception e) {
             log.error("会员添加消息发送失败 : {}", e.getMessage());
         }
     }
 
+
+
+    private Date addTime(Date time, PeriodEnum period, Integer times, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(time);
+
+        if (PeriodEnum.DAY.equals(period)) {
+            cal.add(Calendar.DAY_OF_MONTH, times);
+        } else if (PeriodEnum.MONTH.equals(period)) {
+            cal.add(Calendar.MONTH, times);
+        } else if (PeriodEnum.YEAR.equals(period)) {
+            cal.add(Calendar.YEAR, times);
+        } else if (PeriodEnum.QUARTERLY.equals(period)) {
+            cal.add(Calendar.MONTH, times * 3);
+        } else if (PeriodEnum.YEAR_HALF.equals(period)) {
+            cal.add(Calendar.MONTH, times * 6);
+        } else if (PeriodEnum.PERPETUAL.equals(period)) {
+            cal.add(Calendar.YEAR, 100);
+        }
+        if (type ==0) {
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+        } else {
+            cal.set(Calendar.HOUR_OF_DAY, 23);
+            cal.set(Calendar.MINUTE, 59);
+            cal.set(Calendar.SECOND, 59);
+            cal.set(Calendar.MILLISECOND, 0);
+        }
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
     private Date formatEnd(Date date) {
         Calendar c1 = Calendar.getInstance();
         c1.setTime(date);
@@ -977,4 +1216,30 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         c1.set(Calendar.MILLISECOND, 0);
         return c1.getTime();
     }
+
+
+
+    public VipCardRecord formatVipRecordTime(VipCardRecord vipCardRecord) {
+        // 如果开始时间是23:59:59,开始时间改为第二天的00:00:00
+        LocalDateTime startTime = vipCardRecord.getStartTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (startTime.toLocalTime().equals(LocalTime.of(23, 59, 59))) {
+            startTime = startTime.plusDays(1);
+        }
+
+        startTime = startTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
+        // 如果结束时间是00:00:00,开始时间改为前一天的23:59:59
+        LocalDateTime endTime = vipCardRecord.getEndTime().toInstant()
+                .atZone(ZoneId.systemDefault()).toLocalDateTime();
+        if (endTime.toLocalTime().equals(LocalTime.of(0, 0, 0))) {
+            endTime = endTime.plusDays(-1);
+        }
+        endTime = endTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
+        vipCardRecord.setStartTime(Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()));
+        vipCardRecord.setEndTime(Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
+        if (vipCardRecord.getStartTime().after(vipCardRecord.getEndTime())) {
+            vipCardRecord.setEndTime(vipCardRecord.getStartTime());
+        }
+        return vipCardRecord;
+    }
 }

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/AlbumDetailVo.java

@@ -2,9 +2,11 @@ package com.yonge.cooleshow.biz.dal.vo;
 
 import com.yonge.cooleshow.biz.dal.enums.MusicSheetTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
+import com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 import java.util.List;
 
@@ -14,6 +16,7 @@ import java.util.List;
  * @author: liujunchi
  * @date: 2022-03-31
  */
+@Data
 public class AlbumDetailVo {
 
     @ApiModelProperty(value = "是否审核时可见 (0:否  1:是)")
@@ -80,6 +83,12 @@ public class AlbumDetailVo {
     @ApiModelProperty(value = "曲谱类型(SINGLE:单曲,CONCERT:合奏)")
     private MusicSheetTypeEnum albumType;
 
+    @ApiModelProperty("专辑级别")
+    private List<AlbumCategoryWrapper.AlbumCategory> albumLevelList;
+
+    @ApiModelProperty("专辑类型")
+    private List<AlbumCategoryWrapper.AlbumCategory> albumTypeList;
+
     public YesOrNoEnum getAuditVersion() {
         return auditVersion;
     }

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetVo.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.dayaedu.cbs.openfeign.wrapper.music.CbsMusicSheetWrapper;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -57,6 +58,17 @@ public class MusicSheetVo extends MusicSheet {
     @ApiModelProperty("收藏来源")
     private String favoriteProviderType;
 
+    @ApiModelProperty(value = "级别")
+    private Long albumCategoryLevelId;
+
+    @ApiModelProperty(value = "类型")
+    private Long albumCategoryTypeId;
+
+    @ApiModelProperty(value = "级别")
+    private String albumCategoryLevelName;
+
+    @ApiModelProperty(value = "类型")
+    private String albumCategoryTypeName;
 
     @Data
     @EqualsAndHashCode(callSuper = true)

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetVoResult.java

@@ -256,6 +256,18 @@ public class MusicSheetVoResult implements Serializable {
     @ApiModelProperty("分类")
     private String categoryName;
 
+    @ApiModelProperty(value = "级别")
+    private Long albumCategoryLevelId;
+
+    @ApiModelProperty(value = "类型")
+    private Long albumCategoryTypeId;
+
+    @ApiModelProperty(value = "级别")
+    private String albumCategoryLevelName;
+
+    @ApiModelProperty(value = "类型")
+    private String albumCategoryTypeName;
+
     public ChargeTypeEnum getChargeType() {
         if (Objects.isNull(this.chargeType) && StringUtils.isNotEmpty(getPaymentType())) {
 

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/UserOrderVo.java

@@ -14,6 +14,7 @@ import lombok.Data;
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Author: liweifan
@@ -58,4 +59,6 @@ public class UserOrderVo extends UserOrder {
 	@ApiModelProperty(value = "活动类型 EVALUATION 评测活动 STANDARD_GIFT 达标赠送 SHARE分享活动", required = true)
 	private ActivityTypeEnum activityType;
 
+	@ApiModelProperty("优惠金额详情")
+	private Map<String,BigDecimal> orderDiscountMap;
 }

+ 125 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/AlbumCategoryWrapper.java

@@ -0,0 +1,125 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.Optional;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 机构专辑分类
+ * 2024-12-19 16:57:26
+ */
+@ApiModel(value = "AlbumCategoryWrapper对象", description = "机构专辑分类查询对象")
+public class AlbumCategoryWrapper {
+
+    @Data
+	@Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" AlbumCategoryQuery-机构专辑分类")
+    public static class AlbumCategoryQuery implements QueryInfo {
+    
+    	@ApiModelProperty("当前页")
+        private Integer page;
+        
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+		private String keyword;
+
+        @ApiModelProperty("专辑ID")
+        private Long albumId;
+
+        @ApiModelProperty("专辑分类类别 类型 CATEGORY_TYPE 级别 CATEGORY_LEVEL")
+        private String categoryType;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+        
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static AlbumCategoryQuery from(String json) {
+            return JSON.parseObject(json, AlbumCategoryQuery.class);
+        }
+    }  
+
+    @Data
+	@ApiModel(" AlbumCategory-机构专辑分类")
+    public static class AlbumCategory {
+
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+        @ApiModelProperty("专辑ID")
+        private Long albumId;
+
+        @ApiModelProperty("专辑分类类别 类型 CATEGORY_TYPE 级别 CATEGORY_LEVEL")
+        private String categoryType;
+
+        @ApiModelProperty("专辑分类名称")
+        private String name;
+
+        @ApiModelProperty("排序")
+        private Integer sort;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static AlbumCategory from(String json) {
+            return JSON.parseObject(json, AlbumCategory.class);
+        }
+	}
+
+
+
+    @Data
+    @ApiModel(" AddAlbumCategory")
+    public static class AddAlbumCategory {
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+        @ApiModelProperty("专辑ID")
+        @NotNull(message = "专辑ID不能为空")
+        private Long albumId;
+
+        @ApiModelProperty("专辑分类类别 类型 CATEGORY_TYPE 级别 CATEGORY_LEVEL")
+        @NotNull(message = "专辑分类类别不能为空")
+        private ETenantAlbumCategoryType categoryType;
+
+        @ApiModelProperty("专辑分类名称")
+        @NotNull(message = "名称不能为空")
+        private String name;
+
+        @ApiModelProperty("排序")
+        @NotNull(message = "排序不能为空")
+        private Integer sort;
+
+
+        @ApiModelProperty(value = "创建人",hidden = true)
+        private Long operatorId;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+    }
+}

+ 255 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/DiscountCardRecordWrapper.java

@@ -0,0 +1,255 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.enums.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang.StringUtils;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.Optional;
+
+/**
+ * 购买会员卡记录表
+ * 2024-12-18 14:24:32
+ */
+@ApiModel(value = "DiscountCardRecordWrapper对象", description = "购买会员卡记录表查询对象")
+public class DiscountCardRecordWrapper {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" DiscountCardRecordQuery-购买会员卡记录表")
+    public static class DiscountCardRecordQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+
+        @ApiModelProperty("扣减状态 生效中:EFFECTIVE 过期 EXPIRED 扣减 DEDUCT")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("关键字匹配")
+        private String keyword;
+
+        @ApiModelProperty("用户id")
+        @NotNull(message = "用户id不能为空")
+        private Long userId;
+
+
+        @ApiModelProperty("来源类型 : ACTIVITY :活动 ,ORDER:订单")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("结束时间")
+        private Date endTime;
+
+
+        @ApiModelProperty("扣减开始时间")
+        private Date deductionStartTime;
+
+
+        @ApiModelProperty("扣减结束时间")
+        private Date deductionEndTime;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static DiscountCardRecordQuery from(String json) {
+            return JSON.parseObject(json, DiscountCardRecordQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" DiscountCardRecord-购买会员卡记录表")
+    public static class AddDiscountCardRecord {
+
+        @ApiModelProperty("用户id")
+        @NotNull(message = "用户id不能为空")
+        private Long userId;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("操作人ID")
+        private Long createBy;
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月,YEAR:年")
+        private PeriodEnum type;
+
+        @ApiModelProperty("添加时间数量")
+        private Integer times;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+        @ApiModelProperty("是否发送推送,1:是,0:否")
+        private Boolean sendMsg;
+
+    }
+
+
+    @Data
+    @ApiModel(" DeductionDiscountCardRecord")
+    public static class DeductionDiscountCardRecord {
+
+        @ApiModelProperty("用户id")
+        @NotNull(message = "用户id不能为空")
+        private Long userId;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("操作人ID")
+        private Long createBy;
+
+        @ApiModelProperty("记录ID")
+        @NotNull(message = "记录ID不能为空")
+        private Long recordId;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+        @ApiModelProperty("是否发送推送,1:是,0:否")
+        private Boolean sendMsg;
+
+    }
+
+
+    @Data
+    @ApiModel(" DiscountCardRecordChange")
+    public static class DiscountCardRecordChange {
+
+        @ApiModelProperty("用户id")
+        private Long userId;
+
+        @ApiModelProperty("会员卡id")
+        private Long vipCardId;
+
+        @ApiModelProperty("订单号 ,活动id")
+        private String orderNo;
+
+        @ApiModelProperty("订单详情号")
+        private String subOrderNo;
+
+        @ApiModelProperty("来源类型 : ACTIVITY :活动 ,ORDER:订单")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("操作人ID")
+        private Long createBy;
+
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月,YEAR:年")
+        private PeriodEnum type;
+
+        @ApiModelProperty("添加时间数量")
+        private Integer times;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+        @ApiModelProperty("状态 ADD:新增,DEDUCTION:扣减")
+        private EVipRecordStatus status;
+
+    }
+
+
+    @Data
+    public static class DiscountCardRecord {
+
+        @ApiModelProperty("会员记录id")
+        private String id;
+
+        @ApiModelProperty("用户id")
+        private Long userId;
+
+        @ApiModelProperty("订单号 ,活动id")
+        private String orderNo;
+
+        @ApiModelProperty("来源类型 : 后台扣减 PLATFORM_DEDUCT,活动 ACTIVITY ,订单 ORDER,后台赠送 BACKEND_GIVE")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("会员卡开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("会员卡结束时间")
+        private Date endTime;
+
+
+        @ApiModelProperty("创建时间")
+        private Date createTime;
+
+        @ApiModelProperty("操作人")
+        private Long operatorId;
+
+
+        @ApiModelProperty("操作人")
+        private String operatorName;
+
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月,YEAR:年")
+        private PeriodEnum type;
+
+        @ApiModelProperty("添加时间数量")
+        private Integer times;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+
+        @ApiModelProperty("扣减状态 生效中:EFFECTIVE 过期 EXPIRED 扣减 DEDUCT")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("扣减时间")
+        private Date deductionTime;
+
+
+        @ApiModelProperty("剩余天数")
+        private Integer surplusDay = 0;
+
+
+    }
+
+    @Data
+    public static class InfoQuery {
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+        @ApiModelProperty("类型")
+        private ClientEnum client;
+    }
+
+    @Data
+    public static class Info {
+
+        @ApiModelProperty("剩余天数")
+        private Integer surplusDay = 0;
+    }
+}

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/HomeworkWrapper.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.wrapper;
 
 import com.alibaba.excel.annotation.ExcelProperty;
+import com.yonge.cooleshow.biz.dal.entity.StudentCourseHomework;
 import com.yonge.cooleshow.biz.dal.entity.SysUser;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -61,4 +62,15 @@ public class HomeworkWrapper {
         @ApiModelProperty("课程组编号")
         private Long courseGroupId;
     }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("学员作业列表")
+    public static class StudentCourseHomeworkDto extends StudentCourseHomework {
+
+        @ApiModelProperty("学员姓名")
+        private String studentName;
+    }
 }

+ 15 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/MusicSheetWrapper.java

@@ -1174,4 +1174,19 @@ public class MusicSheetWrapper {
 
 
     }
+
+
+    @Data
+    public static class MusicSheetFavoriteQuery implements QueryInfo {
+
+        @ApiModelProperty(value = "提供方 TENANT 机构 PLATFORM 平台")
+        private SourceTypeEnum providerType = SourceTypeEnum.PLATFORM;
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+    }
 }

+ 15 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StudentWrapper.java

@@ -230,4 +230,19 @@ public class StudentWrapper {
         private Long tenantGroupId;
         private Integer count;
     }
+
+    //用户基本信息
+    @Data
+    @ApiModel("用户基本信息")
+    public static class BasicUserInfo implements Serializable {
+
+        @ApiModelProperty("用户名")
+        private String username;
+
+        @ApiModelProperty("用户头像")
+        private String avatar;
+
+        @ApiModelProperty("声部")
+        private String subjectName;
+    }
 }

+ 78 - 10
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TeacherIndexWrapper.java

@@ -1,5 +1,7 @@
 package com.yonge.cooleshow.biz.dal.wrapper;
 
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -52,6 +54,12 @@ public class TeacherIndexWrapper {
 
         @ApiModelProperty("排序方式 ,ASC升序,DESC降序")
         private String sortType;
+
+        @ApiModelProperty("查询条数")
+        private Integer limit = 10;
+
+        @ApiModelProperty("间隔天数")
+        private Integer intervalDays;
     }
 
     @Data
@@ -68,9 +76,6 @@ public class TeacherIndexWrapper {
 
         @ApiModelProperty("练习人数")
         private List<PracticeTimeDto> practiceCounts;
-
-        @ApiModelProperty("学员练习统计")
-        private List<StudentPracticeSummaryDto> studentPracticeSummary;
     }
 
     @Data
@@ -107,26 +112,59 @@ public class TeacherIndexWrapper {
     @AllArgsConstructor
     public static class StudentPracticeSummaryDto{
 
+        @ApiModelProperty("学员编号")
+        private Long userId;
+
         @ApiModelProperty("学员姓名")
         private String studentName;
 
+        @ApiModelProperty("学员头像")
+        private String avatar;
+
         @ApiModelProperty("乐器")
         private String subjectName;
 
         @ApiModelProperty("练习总时长")
         private Long totalPracticeTime;
 
+        @ApiModelProperty("练习总时长(格式化)")
+        private String totalPracticeTimeStr;
+
         @ApiModelProperty("练习天数")
         private Integer practiceDays;
 
         @ApiModelProperty("平均练习时长")
         private Long averagePracticeTime;
+
+        @ApiModelProperty("平均练习时长(格式化)")
+        private String averagePracticeTimeStr;
     }
 
     @Data
     @Builder
     @NoArgsConstructor
     @AllArgsConstructor
+    public static class StudentPracticeSummaryExportDto{
+
+        @ExcelProperty(value = "学员姓名",index = 0)
+        private String studentName;
+
+        @ExcelProperty(value = "乐器",index = 1)
+        private String subjectName;
+
+        @ExcelProperty(value = "练习总时长",index = 2)
+        private String totalPracticeTimeStr;
+
+        @ExcelProperty(value = "练习天数",index = 3)
+        private Integer practiceDays;
+
+        @ExcelProperty(value = "平均练习时长",index = 4)
+        private String averagePracticeTimeStr;
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
     public static class CourseExposureTotal{
 
         @ApiModelProperty("日期")
@@ -135,21 +173,51 @@ public class TeacherIndexWrapper {
         @ApiModelProperty("曝光数")
         private Integer exposureNum;
 
-        @ApiModelProperty("类型")
-        private String type;
-
-        public CourseExposureTotal(String date, String type, Integer exposureNum) {
+        public CourseExposureTotal(String date, Integer exposureNum) {
             this.date = date;
-            this.type = type;
             this.exposureNum = exposureNum;
         }
     }
 
     @Data
+    public static class TeacherIncome{
+
+        @ApiModelProperty("下单时间")
+        private Date orderTime;
+
+        @ApiModelProperty("学员姓名")
+        private String userName;
+
+        @ApiModelProperty("学员头像")
+        private String userAvatar;
+
+        @ApiModelProperty("学员编号")
+        private Long userId;
+
+        @ApiModelProperty("声部")
+        private String subjectName;
+
+        @ApiModelProperty("数量")
+        private Integer bizQuantity;
+
+        @ApiModelProperty("业务id")
+        private Long bizId;
+
+        @ApiModelProperty("业务名称")
+        private String bizName;
+
+        @ApiModelProperty("业务图片")
+        private String bizCover;
+
+        @ApiModelProperty("金额")
+        private BigDecimal amount;
+    }
+
+    @Data
     @Builder
     @NoArgsConstructor
     @AllArgsConstructor
-    public static class CourseExposureSearch{
+    public static class CourseExposureSearch extends QueryInfo {
 
         @ApiModelProperty("开始时间")
         private String startTime;
@@ -157,7 +225,7 @@ public class TeacherIndexWrapper {
         @ApiModelProperty("结束时间")
         private String endTime;
 
-        @ApiModelProperty("类型MUSIC:乐谱,LIVE:直播课,VIDEO:视频课")
+        @ApiModelProperty("类型MUSIC:乐谱,LIVE:直播课,VIDEO:视频课,VIP_COURSE vip课,GROUP 小组课,PRACTICE 趣纠课")
         private String type;
 
         @ApiModelProperty("老师id")

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

@@ -32,4 +32,5 @@ public class UserInfoWrapper {
         private ClientEnum client;
 
     }
+
 }

+ 129 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserTenantAlbumRecordWrapper.java

@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.microsvc.toolkit.common.response.paging.QueryInfo;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EDeductionStatus;
+import com.yonge.cooleshow.biz.dal.enums.PeriodEnum;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -19,6 +21,8 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
 
+import javax.validation.constraints.NotNull;
+
 /**
  * 购买训练工具记录
  * 2023-07-24 13:32:24
@@ -32,13 +36,13 @@ public class UserTenantAlbumRecordWrapper {
     @AllArgsConstructor
     @ApiModel(" UserTenantAlbumRecordQuery-购买训练工具记录")
     public static class UserTenantAlbumRecordQuery implements QueryInfo {
-    
+
     	@ApiModelProperty("当前页")
         private Integer page;
-        
+
         @ApiModelProperty("分页行数")
         private Integer rows;
-        
+
         @ApiModelProperty("关键字匹配")
 		private String keyword;
 
@@ -60,6 +64,15 @@ public class UserTenantAlbumRecordWrapper {
         @ApiModelProperty("小组ID")
         private Long tenantGroupId;
 
+        @ApiModelProperty("扣减状态 生效中:EFFECTIVE 过期 EXPIRED 扣减 DEDUCT")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("扣减开始时间")
+        private Date deductionStartTime;
+
+
+        @ApiModelProperty("扣减结束时间")
+        private Date deductionEndTime;
         
         public String getKeyword() {
             return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
@@ -153,4 +166,117 @@ public class UserTenantAlbumRecordWrapper {
         }
 	}
 
+    @Data
+    public static class AdminUserTenantAlbumRecord {
+
+
+        @ApiModelProperty("记录id")
+        private String id;
+
+        @ApiModelProperty("用户id")
+        private Long userId;
+
+        @ApiModelProperty("机构专辑ID")
+        private Long tenantAlbumId;
+
+        @ApiModelProperty("机构专辑名称")
+        private String tenantAlbumName;
+
+        @ApiModelProperty("订单号")
+        private String orderNo;
+
+        @ApiModelProperty("ORDER:订单")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+
+        @ApiModelProperty("开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("结束时间")
+        private Date endTime;
+
+        @ApiModelProperty("创建时间")
+        private Date createTime;
+
+        @ApiModelProperty("操作人")
+        private Long operatorId;
+
+        @ApiModelProperty("操作人")
+        private String operatorName;
+
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月,YEAR:年")
+        private PeriodEnum type;
+
+        @ApiModelProperty("添加时间数量")
+        private Integer times;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+
+        @ApiModelProperty("剩余天数")
+        private Integer surplusDay = 0;
+
+        @ApiModelProperty("扣减状态")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("扣减时间")
+        private Date deductionTime;
+
+    }
+
+
+    @Data
+    public static class InfoQuery {
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+        @ApiModelProperty("类型")
+        private ClientEnum client;
+    }
+
+    @Data
+    public static class Info {
+
+        @ApiModelProperty("剩余天数")
+        private Integer surplusDay = 0;
+
+        @ApiModelProperty("是否永久")
+        private Boolean perpetualFlag = false;
+
+        @ApiModelProperty("机专辑ID")
+        private Long tenantAlbumId;
+
+        @ApiModelProperty("机专辑名称")
+        private String tenantAlbumName;
+
+    }
+
+    @Data
+    public static class DeductionUserTenantAlbumRecord {
+
+
+        @ApiModelProperty("用户id")
+        @NotNull(message = "用户id不能为空")
+        private Long userId;
+
+        @ApiModelProperty("操作人ID")
+        private Long createBy;
+
+        @ApiModelProperty("记录ID")
+        @NotNull(message = "记录ID不能为空")
+        private Long recordId;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+        @ApiModelProperty("是否发送推送,1:是,0:否")
+        private Boolean sendMsg;
+    }
+
 }

+ 158 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/VipCardRecordWrapper.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.wrapper;
 
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
 import com.yonge.cooleshow.biz.dal.enums.*;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -59,7 +60,7 @@ public class VipCardRecordWrapper {
         @NotNull(message = "用户类型不能为空")
         private ClientEnum clientType;
 
-        @ApiModelProperty("状态 ADD:新增,DEDUCTION:扣减,UPDATE:变更")
+        @ApiModelProperty("状态 ADD:新增")
         @NotNull
         private EVipRecordStatus status;
 
@@ -136,4 +137,160 @@ public class VipCardRecordWrapper {
             }
         }
     }
+
+    @Data
+    public static class DeductionVipCardRecord {
+
+        @ApiModelProperty("用户id")
+        @NotNull(message = "用户id不能为空")
+        private Long userId;
+
+        @ApiModelProperty("人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        @NotNull(message = "人员类型不能为空")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("操作人ID")
+        private Long createBy;
+
+        @ApiModelProperty("记录ID")
+        @NotNull(message = "记录ID不能为空")
+        private Long recordId;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+        @ApiModelProperty("是否发送推送,1:是,0:否")
+        private Boolean sendMsg;
+    }
+
+
+
+    @Data
+    public static class InfoQuery {
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+        @ApiModelProperty("类型")
+        private ClientEnum client;
+    }
+
+    @Data
+    public static class Info {
+
+        @ApiModelProperty("剩余vip天数")
+        private Integer surplusVipDay = 0;
+
+        @ApiModelProperty("剩余svip天数")
+        private Integer surplusSvipDay = 0;
+
+        @ApiModelProperty("是否永久")
+        private Boolean perpetualFlag = false;
+
+    }
+
+    @Data
+    public static class VipQuery  implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+        private String keyword;
+
+        @ApiModelProperty("用户Id")
+        private Long userId;
+
+
+        @ApiModelProperty("用户类型 学生:STUDENT 老师 :TEACHER")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("结束时间")
+        private Date endTime;
+
+        @ApiModelProperty("会员类型 VIP,SVIP")
+        private EVipType vipType;
+
+        @ApiModelProperty("ORDER:激活码激活,TENANT:自行购买,BACKEND_GIVE:后台添加")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("扣减状态 生效中:EFFECTIVE 过期 EXPIRED 扣减 DEDUCT")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("扣减开始时间")
+        private Date deductionStartTime;
+
+
+        @ApiModelProperty("扣减结束时间")
+        private Date deductionEndTime;
+    }
+
+    @Data
+    public static class VipCardRecord {
+
+        @ApiModelProperty("记录id")
+        private String id;
+
+        @ApiModelProperty("用户id")
+        private Long userId;
+
+
+        @ApiModelProperty("会员类型 VIP,SVIP")
+        private EVipType vipType;
+
+        @ApiModelProperty("版本")
+        private Integer version;
+
+        @ApiModelProperty("订单号")
+        private String orderNo;
+
+        @ApiModelProperty("ORDER:订单")
+        private SourceTypeEnum sourceType;
+
+        @ApiModelProperty("购买人员类型 TEACHRE :老师端 STUDNET : 学生端")
+        private ClientEnum clientType;
+
+
+        @ApiModelProperty("开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("结束时间")
+        private Date endTime;
+
+        @ApiModelProperty("创建时间")
+        private Date createTime;
+
+        @ApiModelProperty("操作人")
+        private Long operatorId;
+
+        @ApiModelProperty("操作人")
+        private String operatorName;
+
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月,YEAR:年")
+        private PeriodEnum type;
+
+        @ApiModelProperty("添加时间数量")
+        private Integer times;
+
+        @ApiModelProperty("备注")
+        private String reason;
+
+
+        @ApiModelProperty("剩余天数")
+        private Integer surplusDay = 0;
+
+        @ApiModelProperty("扣减状态")
+        private EDeductionStatus deductionStatus;
+
+        @ApiModelProperty("扣减时间")
+        private Date deductionTime;
+
+    }
 }

+ 39 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/AlbumCategoryMapper.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.biz.dal.mapper.AlbumCategoryMapper">
+
+	 
+    
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+         t.id_ AS id
+        , t.album_id_ AS albumId
+        , t.category_type_ AS categoryType
+        , t.name_ AS name
+        , t.sort_ AS sort
+        , t.del_flag_ AS delFlag
+        , t.create_by_ AS createBy
+        , t.create_time_ AS createTime
+        , t.update_by_ AS updateBy
+        , t.update_time_ AS updateTime
+        </sql> 
+    
+    <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.wrapper.AlbumCategoryWrapper$AlbumCategory">
+		SELECT         
+        	<include refid="baseColumns" />
+		FROM album_category t
+        <where>
+            <if test="param.albumId != null">
+                and t.album_id_ = #{param.albumId}
+            </if>
+            <if test="param.categoryType != null and param.categoryType != ''">
+                and t.category_type_ = #{param.categoryType}
+            </if>
+            <if test="param.keyword != null and param.keyword != ''">
+                and t.name_ like concat('%',#{param.keyword},'%')
+            </if>
+        </where>
+        order by t.sort_ ,t.id_ desc
+	</select>
+    
+</mapper>

+ 71 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/DiscountCardRecordMapper.xml

@@ -29,6 +29,14 @@
         , t.efficient_flag_ AS efficientFlag
         , t.send_msg_ AS sendMsg
         </sql>
+    <update id="updateMsgStatus">
+        update discount_card_record
+        set msg_status_ = #{msgStatus},update_time_ = now()
+        where id_ IN
+        <foreach collection="ids" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </update>
 
     <select id="detail" resultType="com.yonge.cooleshow.biz.dal.entity.MemberPriceSettings">
         SELECT
@@ -41,4 +49,67 @@
             and t.user_id_ = #{userId}
         </if>
     </select>
+
+    <select id="selectPage"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper$DiscountCardRecord">
+        select t.id_,
+               t.user_id_,
+               t.order_no_,
+               t.source_type_,
+               t.client_type_,
+               t.create_time_,
+                if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) as operatorId,
+               t.type_,
+                t.start_time_,
+        t.end_time_,
+               t.times_,
+                if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) as reason,
+               t.deduction_time_,
+               t.deduction_status_
+        from discount_card_record t
+
+        <if test="param.keyword != null and param.keyword != ''">
+            left join sys_user t1
+                      on if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) = t1.id_
+        </if>
+        <where>
+            t.display_flag_ = 1
+            <if test="param.userId != null">
+                and t.user_id_ = #{param.userId}
+                and t.client_type_ = 'STUDENT'
+            </if>
+            <if test="param.sourceType != null">
+                and t.source_type_ = #{param.sourceType}
+            </if>
+            <if test="param.deductionStatus != null">
+                and t.deduction_status_ = #{param.deductionStatus}
+            </if>
+            <if test="param.keyword != null and param.keyword != ''">
+                and (t1.username_ like CONCAT('%', #{param.keyword}, '%')
+                    or
+                     if(t.source_type_ = 'ORDER' and t.order_no_ is not null, t.order_no_, '') like
+                     CONCAT('%', #{param.keyword}, '%')
+                    or if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) like
+                       CONCAT('%', #{param.keyword}, '%')
+                    )
+            </if>
+            <if test="param.startTime != null">
+                and t.create_time_ &gt;= #{param.startTime}
+            </if>
+            <if test="param.endTime != null">
+                and t.create_time_ &lt;= #{param.endTime}
+            </if>
+            <if test="param.deductionStartTime != null">
+                and t.deduction_time_ &gt;= #{param.deductionStartTime}
+            </if>
+            <if test="param.deductionEndTime != null">
+                and t.deduction_time_ &lt;= #{param.deductionEndTime}
+            </if>
+        </where>
+        order by t.id_ desc
+    </select>
+
+    <update id="updateUserDiscountTime">
+        update student t set t.discount_end_time_ = #{endTime},t.discount_start_time_ = ifnull(t.discount_start_time_,#{startTime}) where t.user_id_ = #{userId}
+    </update>
 </mapper>

+ 5 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/ExposureRecordDao.xml

@@ -17,7 +17,10 @@
 		select DATE_FORMAT(er.exposure_time_, #{groupBy}) 'date',er.object_type_ as type,
 		       SUM(er.exposure_num_) exposureNum from exposure_record er
 		where er.exposure_time_ BETWEEN #{param.startTime} AND #{param.endTime}
-		group by er.object_type_,DATE_FORMAT(er.exposure_time_, #{groupBy})
-		ORDER BY type,'date'
+		<if test="param.type != null and param.type != ''">
+			and er.object_type_ = #{param.type}
+		</if>
+		group by DATE_FORMAT(er.exposure_time_, #{groupBy})
+		ORDER BY 'date'
 	</select>
 </mapper>

+ 83 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/HomeMapper.xml

@@ -526,4 +526,87 @@
 		</where>
 		group by t.good_type_
 	</select>
+	<select id="teacherIncomeList"
+			resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$TeacherIncome">
+		select uo.user_id_ userId,
+		<if test="param.type != 'MUSIC' and param.type != 'VIDEO'">
+			cg.course_num_ bizQuantity,
+		</if>
+		<if test="param.type == 'VIDEO'">
+			1 bizQuantity,
+		</if>
+		<if test="param.type == 'MUSIC'">
+			1 bizQuantity,
+		</if>
+		ttar.trans_amount_ amount,uo.create_time_ orderTime,
+		<if test="param.type != 'MUSIC' and param.type != 'VIDEO'">
+			cg.id_ bizId,cg.name_ bizName,cg.background_pic_ bizCover
+		</if>
+		<if test="param.type == 'VIDEO'">
+			cg.id_ bizId,cg.lesson_name_ bizName,cg.lesson_cover_url_ bizCover
+		</if>
+		<if test="param.type == 'MUSIC'">
+			cg.cbs_music_sheet_id_ bizId,'' bizName,'' bizCover
+		</if>
+		from tenant_teacher_account_record ttar
+		left join user_order uo ON uo.order_no_ = ttar.order_no_
+		<if test="param.type != 'MUSIC' and param.type != 'VIDEO'">
+			left join course_group cg ON cg.id_ = ttar.biz_id_
+		</if>
+		<if test="param.type == 'VIDEO'">
+			left join video_lesson_group cg ON cg.id_ = ttar.biz_id_
+		</if>
+		<if test="param.type == 'MUSIC'">
+			left join music_sheet cg ON cg.id_ = ttar.biz_id_
+		</if>
+		where uo.status_ = 'PAID' AND ttar.in_or_out_ = 'IN'
+		AND DATE_FORMAT(uo.create_time_,'%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime} AND ttar.teacher_id_ = #{param.teacherId}
+		AND ttar.biz_type_ = #{param.type}
+		UNION ALL
+		select uo.user_id_ userId,COUNT(ucar.id_) bizQuantity,SUM(ucar.trans_amount_) amount,
+		       uo.create_time_ orderTime,
+		<if test="param.type != 'MUSIC' and param.type != 'VIDEO'">
+			cg.id_ bizId,cg.name_ bizName,cg.background_pic_ bizCover
+		</if>
+		<if test="param.type == 'VIDEO'">
+			cg.id_ bizId,cg.lesson_name_ bizName,cg.lesson_cover_url_ bizCover
+		</if>
+		<if test="param.type == 'MUSIC'">
+			cg.cbs_music_sheet_id_ bizId,'' bizName,'' bizCover
+		</if>
+		from user_cash_account_record ucar
+		left join user_order uo ON uo.order_no_ = ucar.order_no_
+		<if test="param.type != 'MUSIC' and param.type != 'VIDEO'">
+			left join course_schedule cs ON cs.id_ = ucar.biz_id_
+			left join course_group cg ON cg.id_ = cs.course_group_id_
+		</if>
+		<if test="param.type == 'VIDEO'">
+			left join video_lesson_group cg ON cg.id_ = ucar.biz_id_
+		</if>
+		<if test="param.type == 'MUSIC'">
+			left join music_sheet cg ON cg.id_ = ucar.biz_id_
+		</if>
+		where uo.status_ = 'PAID' AND ucar.in_or_out_ = 'IN'
+		AND DATE_FORMAT(uo.create_time_,'%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime} AND ucar.account_id_ = #{param.teacherId}
+		AND ucar.biz_type_ = #{param.type}
+		group by ucar.order_no_
+		order by orderTime desc
+	</select>
+	<select id="teacherIncomeSum" resultType="java.math.BigDecimal">
+		select sum(a.amount) from (
+			select SUM(ttar.trans_amount_) amount
+			from tenant_teacher_account_record ttar
+			left join user_order uo ON uo.order_no_ = ttar.order_no_
+			where uo.status_ = 'PAID' AND ttar.in_or_out_ = 'IN'
+			  AND DATE_FORMAT(uo.create_time_,'%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime} AND ttar.teacher_id_ = #{param.teacherId}
+			  AND ttar.biz_type_ = #{param.type}
+			UNION ALL
+			select SUM(ucar.trans_amount_) amount
+			from user_cash_account_record ucar
+			left join user_order uo ON uo.order_no_ = ucar.order_no_
+			where uo.status_ = 'PAID' AND ucar.in_or_out_ = 'IN'
+			  AND DATE_FORMAT(uo.create_time_,'%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime} AND ucar.account_id_ = #{param.teacherId}
+			  AND ucar.biz_type_ = #{param.type}
+			) a
+	</select>
 </mapper>

+ 14 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetMapper.xml

@@ -327,6 +327,8 @@
         ,(select group_concat(s.name_) from subject s
             where find_in_set(s.id_,t.music_subject_) and s.del_flag_ = 0 ) as subjectNames
         ,amr.sort_number_ as albumSortNumber
+        ,amr.album_category_level_id_ as albumCategoryLevelId
+        ,amr.album_category_type_id_ as albumCategoryTypeId
         from music_sheet t
         left join album_music_relate amr on t.id_ = amr.music_sheet_id_
         left join sys_user su on t.create_by_ = su.id_
@@ -342,6 +344,15 @@
                 and (t.id_ like concat('%',#{param.idAndName},'%') or
                 t.music_sheet_name_ like concat('%',#{param.idAndName},'%'))
             </if>
+            <if test="param.musicSheetName != null and param.musicSheetName != ''">
+                and t.music_sheet_name_ like concat('%',#{param.musicSheetName},'%')
+            </if>
+            <if test="param.albumCategoryLevelId != null">
+                and amr.album_category_level_id_ = #{param.albumCategoryLevelId}
+            </if>
+            <if test="param2.albumCategoryTypeId != null">
+                and amr.album_category_type_id_ = #{param2.albumCategoryTypeId}
+            </if>
             <if test="param.search != null and param.search != ''">
                 and (t.cbs_music_sheet_id_ like concat('%',#{param.search},'%') or
                 t.music_sheet_name_ like concat('%',#{param.search},'%'))
@@ -622,6 +633,9 @@
                     </if>
                 )
             </if>
+            <if test="param.favoriteProviderType != null">
+                and mf.provider_type_ = #{param.favoriteProviderType}
+            </if>
 
             <if test="param.studentId != null">
                 and mf.user_id_ = #{param.studentId}

+ 21 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentMapper.xml

@@ -40,6 +40,7 @@
         , t.im_customer_id_ AS imCustomerId
         , t.discount_start_time_ as discountStartTime
         , t.discount_end_time_ as discountEndTime
+        , t.entitlements_ as entitlements
         </sql>
     <update id="setSubject">
         update student set subject_id_ = #{subjectIds},update_time_ = now() where user_id_ = #{id}
@@ -133,6 +134,13 @@
                     u.phone_ LIKE CONCAT('%', #{param.search}, '%')
                 )
             </if>
+            <if test="param.entitlementsList != null and param.entitlementsList.size() > 0">
+                and
+                <foreach collection="param.entitlementsList" item="item" separator=" and " open="(" close=")">
+                    t.entitlements_ like concat('%',#{item},'%')
+                </foreach>
+
+            </if>
             <if test="null != param.gender">
                 and u.gender_ = #{param.gender}
             </if>
@@ -407,4 +415,17 @@
         </where>
         group by tenant_group_id_
     </select>
+
+    <select id="selectEntitlements" resultType="java.lang.String">
+        select  distinct vip_type_ from vip_card_record where user_id_ = #{userId} and efficient_flag_ = 1 and client_type_ = 'STUDENT' and end_time_ > now() and deduction_status_ = 'EFFECTIVE'
+        union
+        select if(count(1)>0,'DISCOUNT','') from discount_card_record where user_id_ = #{userId} and efficient_flag_ = 1 and client_type_ = 'STUDENT' and end_time_ > now() and deduction_status_ = 'EFFECTIVE'
+        union
+        select if(count(1)>0,'TENANT_ALBUM','') from user_tenant_album_record where user_id_ = #{userId} and efficient_flag_ = 1  and end_time_ > now() and deduction_status_ = 'EFFECTIVE'
+
+    </select>
+
+    <select id="selectInitEntitlements" resultType="java.lang.Long">
+        select user_id_ from student
+    </select>
 </mapper>

+ 8 - 7
cooleshow-user/user-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml

@@ -604,7 +604,7 @@
 			#{studentId}
 		</foreach>
 		<if test="param.startTime != null and param.startTime != ''">
-			AND mcr.create_time_ BETWEEN #{param.startTime} AND #{param.endTime}
+			AND DATE_FORMAT(mcr.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
 		</if>
 	</select>
 	<select id="getStudentTrainTime"
@@ -615,7 +615,7 @@
 			#{studentId}
 		</foreach>
 		<if test="param.startTime != null and param.startTime != ''">
-			AND mcr.create_time_ BETWEEN #{param.startTime} AND #{param.endTime}
+			AND DATE_FORMAT(mcr.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
 		</if>
 		GROUP BY DATE_FORMAT(mcr.create_time_, #{groupBy})
 		ORDER BY 'date'
@@ -628,16 +628,16 @@
 			#{studentId}
 		</foreach>
 		<if test="param.startTime != null and param.startTime != ''">
-			AND mcr.create_time_ BETWEEN #{param.startTime} AND #{param.endTime}
+			AND DATE_FORMAT(mcr.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
 		</if>
 		GROUP BY DATE_FORMAT(mcr.create_time_, #{groupBy})
 		ORDER BY 'date'
 	</select>
 	<select id="getStudentTrainOverViewList"
 			resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$StudentPracticeSummaryDto">
-		select su.username_ studentName,sb.name_ subjectName,SUM(smcr.play_time_) totalPracticeTime,
+		select smcr.user_id_ userId,su.username_ studentName,su.avatar_ avatar,sb.name_ subjectName,SUM(smcr.play_time_) totalPracticeTime,
 		       COUNT(DISTINCT DATE_FORMAT(smcr.create_time_, '%Y-%m-%d')) practiceDays,
-		       SUM(smcr.play_time_) / COUNT(DISTINCT DATE_FORMAT(smcr.create_time_, '%Y-%m-%d')) averagePracticeTime
+		       SUM(smcr.play_time_) / ${param.intervalDays} averagePracticeTime
 		from sys_music_compare_record smcr
 				 left join sys_user su ON su.id_ = smcr.user_id_
 				 left join student st ON st.user_id_ = su.id_
@@ -647,7 +647,7 @@
 			#{studentId}
 		</foreach>
 		<if test="param.startTime != null and param.startTime != ''">
-			AND smcr.create_time_ BETWEEN #{param.startTime} AND #{param.endTime}
+			AND DATE_FORMAT(smcr.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
 		</if>
 		GROUP BY smcr.user_id_
 		<if test="param.sortField != null and param.sortField != ''">
@@ -656,7 +656,8 @@
 		<if test="param.sortField == null or param.sortField == ''">
 			ORDER BY totalPracticeTime DESC
 		</if>
-		LIMIT 10
+			,smcr.user_id_
+		LIMIT ${param.limit}
 	</select>
 	<!--曲目练习统计-->
 

+ 13 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherMapper.xml

@@ -406,10 +406,15 @@
                             from live_room lr
                             WHERE live_state_ = 1 and type_ = 'temp'
                             group by lr.speaker_id_) a on a.speaker_id_ = t.user_id_
+                 left join (select tft.teacher_id_,COUNT(DISTINCT tsp.course_type_) num from teacher_free_time tft
+                                                                                                 left join teacher_subject_price tsp ON tsp.teacher_id_ = tft.teacher_id_
+                            group by tft.teacher_id_) tft ON tft.teacher_id_ = t.user_id_
+                 left join (select create_by_,COUNT(DISTINCT create_by_) num from music_sheet where del_flag_ = 0 AND state_ = 1 AND source_type_ = 'TEACHER'
+                            GROUP BY create_by_) ms ON ms.create_by_ = t.user_id_
         where t.entry_flag_ = 1
           and t.is_test_user_ = 0 AND t.lock_flag_ = 0
           and find_in_set(#{subjectId}, t.subject_id_)
-        order by tt.fans_num_ desc
+        order by tft.num desc ,ms.num DESC ,tt.fans_num_ desc,t.user_id_
         limit 10
     </select>
 
@@ -512,10 +517,16 @@
     <select id="getStudentIds" resultType="java.lang.Long">
         select distinct cssp.user_id_ from course_group cg
         left join course_schedule_student_payment cssp ON cssp.course_group_id_ = cg.id_
+        <if test="startTime != null and startTime != ''">
+            left join course_schedule cs ON cssp.course_id_ = cs.id_
+        </if>
         <if test="subjectId != null">
             left join student st ON st.user_id_ = cssp.user_id_
         </if>
-        where cg.status_ = 'ING' AND cg.teacher_id_ = #{teacherId}
+        where cg.teacher_id_ = #{teacherId}
+        <if test="startTime != null and startTime != ''">
+            AND cs.class_date_ BETWEEN #{startTime} AND #{endTime} AND cs.lock_ = 0
+        </if>
         <if test="subjectId != null">
             and find_in_set(#{subjectId},st.subject_id_)
         </if>

+ 23 - 10
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderDetailMapper.xml

@@ -152,13 +152,29 @@
     </select>
     <select id="liveBuyTotal"
             resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$CourseExposureTotal">
+        select c.type,SUM(c.exposureNum) exposureNum,c.date from (
         select uod.good_type_ type,COUNT(distinct uod.order_no_) exposureNum,
                DATE_FORMAT(uod.create_time_,#{groupBy}) 'date' from user_order_detail uod
         left join user_order uo ON uo.order_no_ = uod.order_no_
         left join course_group cg On cg.id_ = uod.biz_id_
-        where uod.good_type_ = 'LIVE' AND cg.teacher_id_ = #{param.teacherId} AND uo.status_ = 'PAID'
+        where cg.teacher_id_ = #{param.teacherId} AND uo.status_ = 'PAID'
         AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
-        group by 'date' order by 'date'
+        <if test="param.type != null and param.type != ''">
+            and uod.good_type_ = #{param.type}
+        </if>
+        group by DATE_FORMAT(uod.create_time_,#{groupBy})
+        UNION ALL
+        select uod.good_type_ type,COUNT(distinct uod.order_no_) exposureNum,
+        DATE_FORMAT(uod.create_time_,#{groupBy}) 'date' from user_order_detail uod
+        left join user_order uo ON uo.order_no_ = uod.order_no_
+        left join video_lesson_group cg On cg.id_ = uod.biz_id_
+        where cg.teacher_id_ = #{param.teacherId} AND uo.status_ = 'PAID'
+        AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
+        <if test="param.type != null and param.type != ''">
+            and uod.good_type_ = #{param.type}
+        </if>
+        group by DATE_FORMAT(uod.create_time_,#{groupBy})) c
+        group by c.date ORDER BY c.date
     </select>
     <select id="videoBuyTotal"
             resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$CourseExposureTotal">
@@ -168,20 +184,17 @@
         left join video_lesson_group cg On cg.id_ = uod.biz_id_
         where uod.good_type_ = 'VIDEO' AND cg.teacher_id_ = #{param.teacherId} AND uo.status_ = 'PAID'
           AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
-        group by 'date' order by 'date'
+        group by DATE_FORMAT(uod.create_time_,#{groupBy}) order by 'date'
     </select>
     <select id="musicSheetBuyTotal"
             resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$CourseExposureTotal">
         select uod.good_type_ type,COUNT(distinct uod.order_no_) exposureNum,
                DATE_FORMAT(uod.create_time_,#{groupBy}) 'date' from user_order_detail uod
         left join user_order uo ON uo.order_no_ = uod.order_no_
-        where uod.good_type_ = 'MUSIC' AND uo.status_ = 'PAID'
-          AND uo.user_id_ IN
-          <foreach collection="param.studentIds" item="userId" open="(" close=")" separator=",">
-              #{userId}
-            </foreach>
-          AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
-        group by 'date' order by 'date'
+        left join music_sheet ms ON ms.id_ = uod.biz_id_
+        where uod.good_type_ = 'MUSIC' AND uo.status_ = 'PAID' AND ms.source_type_ = 'TEACHER' AND ms.create_by_ = #{param.teacherId}
+        AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
+        group by DATE_FORMAT(uod.create_time_,#{groupBy}) order by 'date'
     </select>
 
 	<select id="getPayingCourseGroupOrder" resultType="java.lang.String">

+ 91 - 3
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserTenantAlbumRecordMapper.xml

@@ -23,8 +23,16 @@
         , t.times_ AS times
         , t.msg_status_ AS msgStatus
         , t.reason_ AS reason
-        </sql> 
-    
+        </sql>
+    <update id="updateMsgStatus">
+        update user_tenant_album_record
+        set msg_status_ = #{msgStatus},update_time_ = now()
+        where id_ IN
+        <foreach collection="ids" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </update>
+
     <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper$TenantAlbum">
 		SELECT         
         	<include refid="baseColumns" />
@@ -87,11 +95,25 @@
         ) a
         left join user_tenant_album_record t on a.id_ = t.id_
         left join sys_user u on t.user_id_ = u.id_
-        where t.end_time_ &lt;= now()
+        where DATE_ADD(now(), INTERVAL 4 DAY) > t.end_time_
         and (msg_status_ = 0 or msg_status_ is null)
         order by end_time_ desc
     </select>
 
+    <select id="selectTemporaryRecord1" resultType="com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper$UserTenantAlbumRecord">
+        select
+        <include refid="baseColumns"/>,
+        u.phone_ as phone
+        from (
+        select max(id_) as id_ from user_tenant_album_record group by user_id_
+        ) a
+        left join user_tenant_album_record t on a.id_ = t.id_
+        left join sys_user u on t.user_id_ = u.id_
+        where DATE_ADD(now(), INTERVAL 1 DAY) > t.end_time_
+        and (msg_status_ IN (0,1) or msg_status_ is null)
+        order by end_time_ desc
+    </select>
+
     <select id="selectUserTenantAlbumRecordPage" resultType="com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper$UserTenantAlbumRecord">
         SELECT
         <include refid="baseColumns" />
@@ -137,4 +159,70 @@
         group by t.tenant_album_id_
 
     </select>
+
+    <select id="selectAdminPage"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper$AdminUserTenantAlbumRecord">
+        SELECT t.id_,
+               t.user_id_,
+               t.tenant_album_id_,
+               t.order_no_,
+               t.source_type_,
+               t.client_type_,
+               t.start_time_,
+               t.end_time_,
+               t.create_time_,
+                if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) as operatorId,
+               t.type_,
+               t.times_,
+                if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) as reason,
+               t.deduction_time_,
+               t.deduction_status_
+        from user_tenant_album_record t
+
+        <if test="param.keyword != null and param.keyword != ''">
+            left join sys_user t1
+                      on if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) = t1.id_
+            left join tenant_album t2 on t.tenant_album_id_ = t2.id_
+        </if>
+        <where>
+            <if test="param.keyword != null and param.keyword != ''">
+                and (
+                if(t.source_type_ = 'ORDER' and t.order_no_ is not null, t.order_no_, '') like
+                CONCAT('%', #{param.keyword}, '%')
+                    or if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) like
+                       CONCAT('%', #{param.keyword}, '%')
+                    or t1.username_ like CONCAT('%', #{param.keyword}, '%')
+                    or t2.name_ like CONCAT('%', #{param.keyword}, '%')
+                )
+            </if>
+            <if test="param.userId != null">
+                AND t.user_id_ = #{param.userId}
+            </if>
+            <if test="param.startTime != null">
+                AND t.create_time_ >= #{param.startTime}
+            </if>
+            <if test="param.endTime != null">
+                AND t.create_time_ &lt; #{param.endTime}
+            </if>
+            <if test="param.sourceType != null">
+                AND t.source_type_ = #{param.sourceType}
+            </if>
+            <if test="param.tenantId != null">
+                AND t.tenant_id_ = #{param.tenantId}
+            </if>
+            <if test="param.tenantGroupId != null">
+                AND t.tenant_album_id_ = #{param.tenantGroupId}
+            </if>
+            <if test="param.deductionStatus != null">
+                AND t.deduction_status_ = #{param.deductionStatus}
+            </if>
+            <if test="param.deductionStartTime != null">
+                AND t.deduction_time_ >= #{param.deductionStartTime}
+            </if>
+            <if test="param.deductionEndTime != null">
+                AND t.deduction_time_ &lt; #{param.deductionEndTime}
+            </if>
+        </where>
+        order by id_ desc
+    </select>
 </mapper>

+ 76 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/VipCardRecordMapper.xml

@@ -48,6 +48,14 @@
         ,t.ref_id_ as refId
         ,t.efficient_flag_ as efficientFlag
         </sql>
+    <update id="updateMsgStatus">
+        update vip_card_record
+        set msg_status_ = #{msgStatus},update_time_ = now()
+        where id_ IN
+        <foreach collection="ids" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </update>
 
     <select id="detail" resultType="com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo">
         SELECT
@@ -92,7 +100,7 @@
         having 1
         order by end_time_ desc) t
         group by t.user_id_, t.client_type_, t.vip_type_
-        having (DATE_ADD(now(), INTERVAL 3 DAY) > vipEndTime or DATE_ADD(now(), INTERVAL 3 DAY) > svipEndTime)
+        having (DATE_ADD(now(), INTERVAL 4 DAY) > vipEndTime or DATE_ADD(now(), INTERVAL 4 DAY) > svipEndTime)
         ) a
         left join vip_card_record t on a.id_ = t.id_
         left join sys_user u on t.user_id_ = u.id_
@@ -117,7 +125,7 @@
             having 1
             order by end_time_ desc) t
             group by t.user_id_, t.client_type_, t.vip_type_
-            having ( now() > vipEndTime or now()> svipEndTime)
+            having (DATE_ADD(now(), INTERVAL 1 DAY) > vipEndTime or DATE_ADD(now(), INTERVAL 1 DAY) > svipEndTime)
         ) a
         left join vip_card_record t on a.id_ = t.id_
         left join sys_user u on t.user_id_ = u.id_
@@ -177,4 +185,70 @@
         left join vip_card_record vcr on m.userId = vcr.user_id_ and vcr.end_time_ > now() and now() >= vcr.start_time_ and efficient_flag_ = 1 and vcr.client_type_ = #{clientType}
         order by vcr.end_time_ desc
     </select>
+
+	<select id="selectAdminPage"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper$VipCardRecord">
+        select t.id_,
+        t.user_id_,
+        t.order_no_,
+        t.version_,
+        t.source_type_,
+        t.client_type_,
+        t.vip_type_,
+        t.create_time_,
+        if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) as operatorId,
+        t.type_,
+        t.start_time_,
+        t.end_time_,
+        t.times_,
+        if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) as reason,
+        t.deduction_time_,
+        t.deduction_status_
+        from vip_card_record t
+
+        <if test="param.keyword != null and param.keyword != ''">
+            left join sys_user t1
+            on if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) = t1.id_
+        </if>
+        <where>
+            t.display_flag_ = 1
+            <if test="param.userId != null">
+                and t.user_id_ = #{param.userId}
+            </if>
+            <if test="param.clientType != null">
+                and t.client_type_ = #{param.clientType}
+            </if>
+            <if test="param.sourceType != null">
+                and t.source_type_ = #{param.sourceType}
+            </if>
+            <if test="param.vipType != null">
+                and t.vip_type_ = #{param.vipType}
+            </if>
+            <if test="param.deductionStatus != null">
+                and t.deduction_status_ = #{param.deductionStatus} and t.version_ = 2
+            </if>
+            <if test="param.keyword != null and param.keyword != ''">
+                and (t1.username_ like CONCAT('%', #{param.keyword}, '%')
+                or
+                if(t.source_type_ = 'ORDER' and t.order_no_ is not null, t.order_no_, '') like
+                CONCAT('%', #{param.keyword}, '%')
+                or if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) like
+                CONCAT('%', #{param.keyword}, '%')
+                )
+            </if>
+            <if test="param.startTime != null">
+                and t.create_time_ &gt;= #{param.startTime}
+            </if>
+            <if test="param.endTime != null">
+                and t.create_time_ &lt;= #{param.endTime}
+            </if>
+            <if test="param.deductionStartTime != null">
+                and t.deduction_time_ &gt;= #{param.deductionStartTime}
+            </if>
+            <if test="param.deductionEndTime != null">
+                and t.deduction_time_ &lt;= #{param.deductionEndTime}
+            </if>
+        </where>
+        order by t.id_ desc
+    </select>
 </mapper>

+ 30 - 0
toolset/utils/src/main/java/com/yonge/toolset/utils/date/DateUtil.java

@@ -1317,6 +1317,23 @@ public class DateUtil {
 		return yearList;
 	}
 
+	public static String secondToTime(Long totalPracticeTime) {
+		if (totalPracticeTime == null) {
+			return "0秒";
+		}
+		long hour = totalPracticeTime / 3600;
+		long minute = (totalPracticeTime % 3600) / 60;
+		long second = totalPracticeTime % 60;
+		// 优化显示
+		if (hour > 0) {
+			return hour + "小时" + minute + "分钟";
+		} else if (minute > 0) {
+			return minute + "分钟" + second + "秒";
+		} else {
+			return second + "秒";
+		}
+	}
+
 	/**
 	 * @describe 时间区段辅助类
 	 * @author Joburgess
@@ -1584,4 +1601,17 @@ public class DateUtil {
 //				DateUtil.parse("2022-01-05",DEFAULT_PATTERN),
 //				DateUtil.parse("2022-02-04",DEFAULT_PATTERN)));
 	}
+
+
+	public static int daysBetweenUp(Date date, Date maxTime) {
+		long epochSecond = date.toInstant().getEpochSecond();
+		long epochSecond1 = maxTime.toInstant().getEpochSecond();
+		long i = (epochSecond1 - epochSecond)/(24*60*60)  ;
+		long j = (epochSecond1 - epochSecond)%(24*60*60)  ;
+		if (j >0) {
+			i++;
+		}
+		return (int)i;
+	}
+
 }