Преглед изворни кода

Merge branch 'feature/0712_vip' into feature/0722-kf

# Conflicts:
#	cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/TeacherSearch.java
#	cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
#	cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherVo.java
yuanliang пре 1 година
родитељ
комит
1a97857193
85 измењених фајлова са 2143 додато и 576 уклоњено
  1. 6 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/MemberPriceSettingsController.java
  2. 11 10
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  3. 13 13
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  4. 53 6
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/VipCardRecordController.java
  5. 12 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TeacherBindingUserVo.java
  6. 3 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/teacher/TeacherVO.java
  7. 18 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MemberPriceSettingsController.java
  8. 23 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MusicSheetController.java
  9. 9 4
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/UserOrderController.java
  10. 17 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MemberPriceSettingsController.java
  11. 22 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java
  12. 33 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/UserOrderController.java
  13. 1 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/website/controller/MusicSheetController.java
  14. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java
  15. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/RewardTypeEnum.java
  16. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/UnitEnum.java
  17. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentType.java
  18. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/StudentDao.java
  19. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/VipCardRecordDao.java
  20. 35 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/OrderReq.java
  21. 7 13
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MemberPriceSettingsSearch.java
  22. 11 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicSheetRelatedQueryInfo.java
  23. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicSheetSearch.java
  24. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/OrderSearch.java
  25. 13 9
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentSearch.java
  26. 6 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/TeacherSearch.java
  27. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/VipRecordSearch.java
  28. 12 58
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MemberPriceSettings.java
  29. 16 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/StudentTime.java
  30. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderDetail.java
  31. 27 130
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/VipCardRecord.java
  32. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/AccountBizTypeEnum.java
  33. 33 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EUserVipType.java
  34. 37 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipRecordStatus.java
  35. 46 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipType.java
  36. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/GoodTypeEnum.java
  37. 24 8
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  38. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/OrderTypeEnum.java
  39. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/PeriodEnum.java
  40. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/SourceTypeEnum.java
  41. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/coupon/CouponCategoryEnum.java
  42. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MemberPriceSettingsService.java
  43. 2 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetService.java
  44. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/StudentService.java
  45. 40 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/VipCardRecordService.java
  46. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityRewardServiceImpl.java
  47. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/HomeServiceImpl.java
  48. 219 41
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MemberPriceSettingsServiceImpl.java
  49. 29 8
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetServiceImpl.java
  50. 12 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentDivMemberRecordServiceImpl.java
  51. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PlatformCashAccountRecordServiceImpl.java
  52. 55 6
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  53. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentTimeServiceImpl.java
  54. 59 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  55. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserAccountRecordServiceImpl.java
  56. 19 6
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserBindingTeacherServiceImpl.java
  57. 11 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserMusicServiceImpl.java
  58. 16 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java
  59. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java
  60. 43 43
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantAlbumRecordServiceImpl.java
  61. 619 40
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardRecordServiceImpl.java
  62. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetDetailVo.java
  63. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MyFens.java
  64. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MyFollow.java
  65. 6 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentHomeVo.java
  66. 17 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentVo.java
  67. 9 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherHomeVo.java
  68. 17 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherVo.java
  69. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/HomeTotalStudent.java
  70. 5 119
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/OrderCreateRes.java
  71. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/userBindingTeacher/UserBindingTeacherWrapper.java
  72. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/MusicSheetWrapper.java
  73. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StudentWrapper.java
  74. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserMusicWrapper.java
  75. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserPaymentOrderWrapper.java
  76. 131 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/VipCardRecordWrapper.java
  77. 16 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/HomeMapper.xml
  78. 15 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MemberPriceSettingsMapper.xml
  79. 18 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetMapper.xml
  80. 35 14
      cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentMapper.xml
  81. 2 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentTimeMapper.xml
  82. 35 12
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherMapper.xml
  83. 2 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderDetailMapper.xml
  84. 3 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderMapper.xml
  85. 50 8
      cooleshow-user/user-biz/src/main/resources/config/mybatis/VipCardRecordMapper.xml

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

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

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

@@ -274,16 +274,16 @@ public class StudentController extends BaseController {
         }
     }
 
-    @PostMapping("/addVip")
-    @ApiOperation(value = "添加会员")
-    @PreAuthorize("@pcs.hasPermissions('student/addVip')")
-    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null || sysUser.getId() == null) {
-            return failed("用户信息获取失败");
-        }
-        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.STUDENT, sysUser));
-    }
+//    @PostMapping("/addVip")
+//    @ApiOperation(value = "添加会员")
+//    @PreAuthorize("@pcs.hasPermissions('student/addVip')")
+//    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
+//        SysUser sysUser = sysUserFeignService.queryUserInfo();
+//        if (sysUser == null || sysUser.getId() == null) {
+//            return failed("用户信息获取失败");
+//        }
+//        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.STUDENT, sysUser));
+//    }
 
 
     @PostMapping("/vipRecord")
@@ -291,6 +291,7 @@ public class StudentController extends BaseController {
     @PreAuthorize("@pcs.hasPermissions('student/vipRecord')")
     public HttpResponseResult<PageInfo<VipRecordVo>> vipRecord(@Valid @RequestBody VipRecordSearch recordSearch) {
 
+        recordSearch.setDisplayFlag(true);
         recordSearch.setClient(ClientEnum.STUDENT);
         return succeed(vipCardRecordService.vipRecord(recordSearch));
     }

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

@@ -242,25 +242,25 @@ public class TeacherController extends BaseController {
         }
     }
 
-    @PostMapping("/addVip")
-    @ApiOperation(value = "添加会员")
-    @PreAuthorize("@pcs.hasPermissions('teacher/addVip')")
-    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
-
-
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null  || sysUser.getId() == null) {
-            return failed("用户信息获取失败");
-        }
-        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.TEACHER,sysUser));
-    }
+//    @PostMapping("/addVip")
+//    @ApiOperation(value = "添加会员")
+//    @PreAuthorize("@pcs.hasPermissions('teacher/addVip')")
+//    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
+//
+//
+//        SysUser sysUser = sysUserFeignService.queryUserInfo();
+//        if (sysUser == null  || sysUser.getId() == null) {
+//            return failed("用户信息获取失败");
+//        }
+//        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.TEACHER,sysUser));
+//    }
 
 
     @PostMapping("/vipRecord")
     @ApiOperation(value = "会员记录")
     @PreAuthorize("@pcs.hasPermissions('teacher/vipRecord')")
     public HttpResponseResult<PageInfo<VipRecordVo>> vipRecord(@Valid @RequestBody VipRecordSearch recordSearch) {
-
+        recordSearch.setDisplayFlag(false);
         recordSearch.setClient(ClientEnum.TEACHER);
         return succeed(vipCardRecordService.vipRecord(recordSearch));
     }

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

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

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

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

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

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

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

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

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

@@ -25,6 +25,7 @@ import com.yonge.cooleshow.biz.dal.vo.CheckVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
+import com.yonge.cooleshow.biz.dal.wrapper.MusicSheetWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.music.MusicCompareWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -96,6 +97,27 @@ public class MusicSheetController extends BaseController {
         return succeed(musicSheetService.detail(id, sysUser, ClientEnum.STUDENT,tenantAlbumId));
     }
 
+
+
+    @GetMapping("/detailUse/{id}")
+    @ApiOperation(value = "是否可使用")
+    public HttpResponseResult<MusicSheetWrapper.MusicUse> detailUse(@ApiParam(value = "曲谱编号", required = true) @PathVariable("id") String id,
+                                                        @RequestParam(required = false) String tenantAlbumId) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            sysUser = null;
+        }
+        MusicSheetDetailVo detail = musicSheetService.detail(id, sysUser, ClientEnum.STUDENT, tenantAlbumId);
+        if (detail == null) {
+            return failed("曲目不存在");
+        }
+
+        MusicSheetWrapper.MusicUse musicUse = new MusicSheetWrapper.MusicUse();
+        musicUse.setBuyed(detail.getBuyed());
+        musicUse.setPlay(detail.getPlay());
+        return succeed(musicUse);
+    }
+
     @ApiOperation(value = "曲目分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/list", consumes="application/json", produces="application/json")
     public HttpResponseResult<PageInfo<MusicSheetVo>> list(@RequestBody StudentMusicSheetSearch query) {
@@ -330,7 +352,7 @@ public class MusicSheetController extends BaseController {
     @GetMapping(value="/queryRelatedList")
     public HttpResponseResult<PageInfo<MusicSheetVo>> queryRelatedList(MusicSheetRelatedQueryInfo queryInfo) {
     	
-    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo.getAlbumId(), queryInfo.getMusicSheetId());
+    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo);
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 

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

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

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

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

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

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

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

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

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

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

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

@@ -110,6 +110,7 @@ public interface SysConfigConstant {
      * @updateTime 2022/4/20 11:43
      */
     String GOOD_LOGO_VIP = "good_logo_vip";
+    String GOOD_LOGO_SVIP = "good_logo_svip";
     /***
      * 商品视频课图片
      * @author liweifan

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -8,7 +8,17 @@ public class MusicSheetRelatedQueryInfo extends QueryInfo {
 	
 	private Long musicSheetId;
 
-	public Long getAlbumId() {
+    private Long subjectId;
+
+    public Long getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Long subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public Long getAlbumId() {
 		return albumId;
 	}
 

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

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

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

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

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

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

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

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

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

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

+ 12 - 58
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MemberPriceSettings.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -10,6 +10,7 @@ import com.yonge.cooleshow.biz.dal.dto.ReasonDto;
 import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
 import com.yonge.cooleshow.biz.dal.dto.search.*;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
+import com.yonge.cooleshow.biz.dal.entity.MusicSheetAccompaniment;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.OrderTypeEnum;
 import com.yonge.cooleshow.biz.dal.vo.*;
@@ -45,7 +46,7 @@ public interface MusicSheetService extends IService<MusicSheet> {
 
     IPage<MusicSheetVoResult> selectCbsPage(IPage<MusicSheetVo> page, MusicSheetSearch query);
     
-    IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, Long albumId, Long musicSheetId);
+    IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, MusicSheetRelatedQueryInfo queryInfo);
 
     /**
      * 曲目状态修改 启用、停用

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

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

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

@@ -7,6 +7,7 @@ import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
@@ -15,8 +16,13 @@ import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
 import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
 import com.yonge.cooleshow.biz.dal.dto.search.VipCardRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.page.PageInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 购买会员卡记录表 服务类
@@ -83,4 +89,38 @@ public interface VipCardRecordService extends IService<VipCardRecord> {
      * @return
      */
     PageInfo<VipRecordVo> vipRecord(VipRecordSearch recordSearch);
+
+    /**
+     * 获取生效中的会员记录
+     *
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    List<VipCardRecord> getEfficientVipRecord(List<Long> userId, ClientEnum clientEnum);
+
+    /**
+     * 用户会员信息
+     *
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    VipCardRecordWrapper.UserVip UserVipInfo(Long userId, ClientEnum clientEnum);
+
+    void add(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord);
+
+    /**
+     * 获取用户会员类型
+     *
+     * @param studentIds
+     * @param client
+     * @return
+     */
+    Map<Long, EVipType> getVipTypeMapByUserIds(List<Long> studentIds, ClientEnum client);
+
+    // 会员添加
+    VipCardRecord addVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord);
+
+    List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(List<Long> userIdList , String clientType);
 }

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

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

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

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

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

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

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

@@ -255,24 +255,43 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
     }
 
     @Override
-    public IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, Long albumId, Long musicSheetId) {
+    public IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, MusicSheetRelatedQueryInfo queryInfo) {
 
-        if (albumId == null) {
+
+        MusicSheet musicSheet = baseMapper.selectById(queryInfo.getMusicSheetId());
+        if (queryInfo.getAlbumId() == null) {
             // 查询专辑下的所有曲目
 
-            MusicSheet musicSheet = baseMapper.selectById(musicSheetId);
 
             if (musicSheet != null) {
                 MusicAlbumDetailSearch query = new MusicAlbumDetailSearch();
                 query.setMusicTagIds(musicSheet.getMusicTag());
                 query.setAuditVersion(musicSheet.getAuditVersion());
+                query.setMusicSheetType(musicSheet.getMusicSheetType());
+                if (queryInfo.getSubjectId() !=null) {
+                    query.setSubjectIdList(Lists.newArrayList(queryInfo.getSubjectId()));
+                }
+                query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
+                if (StringUtils.isNotBlank(musicSheet.getMusicSubject())) {
+                    List<Long> subjectIds = Arrays.stream(musicSheet.getMusicSubject().split(",")).filter(StringUtils::isNotBlank).map(Long::parseLong).collect(Collectors.toList());
+                    query.setMustMatchSubjectIds(subjectIds);
+                }
                 return page.setRecords(baseMapper.selectPage(page, query));
             }
         } else {
             // 查询带有当前曲目标签的所有曲目
             MusicAlbumDetailSearch query = new MusicAlbumDetailSearch();
-            query.setId(albumId);
+            query.setId(queryInfo.getAlbumId());
             query.setType(2);
+            if (queryInfo.getSubjectId() !=null) {
+                query.setSubjectIdList(Lists.newArrayList(queryInfo.getSubjectId()));
+            }
+            query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
+            if (StringUtils.isNotBlank(musicSheet.getMusicSubject())) {
+                List<Long> subjectIds = Arrays.stream(musicSheet.getMusicSubject().split(",")).filter(StringUtils::isNotBlank).map(Long::parseLong).collect(Collectors.toList());
+                query.setMustMatchSubjectIds(subjectIds);
+            }
+            query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
             return page.setRecords(baseMapper.selectAlbumDetailPage(page, query));
         }
         return null;
@@ -724,6 +743,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 detail.setOrderNo(musicSheetPurchaseRecord.getOrderNo());
                 if (OrderStatusEnum.PAID.getCode().equals(musicSheetPurchaseRecord.getOrderStatus().getCode())) {
                     detail.setPlay(YesOrNoEnum.YES);
+                    detail.setBuyed(true);
                     return;
                 }
             }
@@ -738,12 +758,12 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
             // 会员 判断是否为会员, 会员可播放
             if (userType.equals(ClientEnum.STUDENT)) {
                 StudentVo studentVo = studentService.detail(studentId);
-                if (studentVo != null && YesOrNoEnum.YES.getCode().equals(studentVo.getIsVip().getCode())) {
+                if (studentVo != null && studentVo.getUserVip().getVipType() !=EVipType.NOT_VIP) {
                     detail.setPlay(YesOrNoEnum.YES);
                 }
             } else if (userType.equals(ClientEnum.TEACHER)) {
                 TeacherVo teacher = teacherService.detail(studentId);
-                if (teacher != null && YesOrNoEnum.YES.getCode().equals(teacher.getIsVip().getCode())) {
+                if (teacher != null && teacher.getUserVip().getVipType() !=EVipType.NOT_VIP) {
                     detail.setPlay(YesOrNoEnum.YES);
                 }
             }
@@ -777,6 +797,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                     .count();
             if (count > 0) {
                 detail.setPlay(YesOrNoEnum.YES);
+                detail.setBuyed(true);
                 return;
             }
         }
@@ -790,7 +811,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByIds(tenantAlbumIds);
                 if (musicSheetIds.contains(detail.getId())) {
                     detail.setPlay(YesOrNoEnum.YES);
-                    return;
+                    detail.setBuyed(true);
                 }
             }
         } else if (ClientEnum.TEACHER == userType) {
@@ -800,7 +821,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByTenantIds(teacher.getTenantId());
                 if (musicSheetIds.contains(detail.getId())) {
                     detail.setPlay(YesOrNoEnum.YES);
-                    return;
+                    detail.setBuyed(true);
                 }
             }
         }

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

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

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

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

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

@@ -17,10 +17,7 @@ import com.yonge.cooleshow.biz.dal.dao.*;
 import com.yonge.cooleshow.biz.dal.dto.search.QueryMyFollowSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
-import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
-import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
-import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumRefMapper;
@@ -34,6 +31,7 @@ import com.yonge.cooleshow.biz.dal.vo.StudentHomeVo;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
 import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -116,6 +114,9 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Autowired
     private SysMessageService sysMessageService;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
     @Override
     public StudentDao getDao() {
         return baseMapper;
@@ -134,7 +135,16 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     private TenantGroupAlbumMapper tenantGroupAlbumMapper;
     @Override
     public StudentVo detail(Long userId) {
-        return baseMapper.detail(userId);
+        StudentVo detail = baseMapper.detail(userId);
+        VipCardRecordWrapper.UserVip userVip = vipCardRecordService.UserVipInfo(userId, ClientEnum.STUDENT);
+        detail.setUserVip(userVip);
+        detail.setVipType(EUserVipType.NORMAL);
+        List<VipCardRecordWrapper.UserVipInfo> userVipInfos = vipCardRecordService.queryUserVipInfo(Collections.singletonList(userId), ClientEnum.STUDENT.getCode());
+        Map<Long, VipCardRecordWrapper.UserVipInfo> curVipMap = userVipInfos.stream().collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, Function.identity()));
+        VipCardRecordWrapper.UserVipInfo vipType = curVipMap.getOrDefault(userId, new VipCardRecordWrapper.UserVipInfo());
+        detail.setMembershipEndTime(vipType.getCurrentVipSvipEndTime());
+        detail.setVipType(vipType.getCurrentVipType());
+        return detail;
     }
 
     @Override
@@ -144,7 +154,26 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
 
     @Override
     public IPage<StudentVo> selectPage(IPage<StudentVo> page, StudentSearch studentSearch) {
-        return page.setRecords(baseMapper.selectPage(page, studentSearch));
+        List<StudentVo> records = baseMapper.selectPage(page, studentSearch);
+        for (StudentVo record : records) {
+            EUserVipType vipType = record.getVipType();
+            if (EUserVipType.NORMAL.equals(vipType)) {
+                record.setMembershipEndTime(Optional.ofNullable(record.getVipEndTime()).orElse(record.getSvipEndTime()));
+            }
+            if (EUserVipType.SVIP.equals(vipType)) {
+                Date perSvipEndTime = record.getPerSvipEndTime();
+                if (perSvipEndTime != null) {
+                    // 永久会员
+                    record.setMembershipEndTime(null);
+                } else {
+                    record.setMembershipEndTime(record.getSvipEndTime());
+                }
+            }
+            if (EUserVipType.VIP.equals(vipType)) {
+                record.setMembershipEndTime(record.getVipEndTime());
+            }
+        }
+        return page.setRecords(records);
     }
 
     @Override
@@ -190,6 +219,12 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         studentHomeVo.setMusicAlbumNum(null == total.getMusicAlbumNum() ? 0 : total.getMusicAlbumNum());
         studentHomeVo.setMusicSheetNum(null == total.getMusicSheetNum() ? 0 : total.getMusicSheetNum());
 
+        // 设置会员信息
+
+
+        studentHomeVo.setUserVip(vipCardRecordService.UserVipInfo(user.getId(), ClientEnum.STUDENT));
+
+
         // IM聊天用户ID
         studentHomeVo.setImUserId(imGroupService.getImUserId(String.valueOf(detail.getUserId()), ClientEnum.STUDENT.name()));
 
@@ -284,6 +319,20 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Override
     public IPage<MyFollow> queryMyFollow(IPage<MyFollow> page, QueryMyFollowSearch query) {
         List<MyFollow> teacherVos = baseMapper.queryMyFollow(page, query);
+        if (CollectionUtils.isEmpty(teacherVos)) {
+            return page.setRecords(teacherVos);
+        }
+
+        // 老师ID集合
+        List<Long> teacherIds = teacherVos.stream().filter(o -> o.getTeacher() != null).map(o -> o.getTeacher().getUserId()).collect(Collectors.toList());
+        Map<Long, EVipType> vipTypeMapByUserIds = vipCardRecordService.getVipTypeMapByUserIds(teacherIds, ClientEnum.TEACHER);
+        for (MyFollow teacherVo : teacherVos) {
+            teacherVo.setVipType(EVipType.NOT_VIP);
+            if (teacherVo.getTeacher() != null) {
+                teacherVo.setVipType(vipTypeMapByUserIds.getOrDefault(teacherVo.getTeacher().getUserId(),EVipType.NOT_VIP));
+            }
+        }
+
         return page.setRecords(teacherVos);
     }
 

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

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

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

@@ -20,6 +20,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.TeacherSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
 import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
@@ -55,7 +56,9 @@ import com.yonge.cooleshow.biz.dal.vo.TeacherHomeVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
 import com.yonge.cooleshow.biz.dal.wordfilter.WordFilter;
 import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
@@ -85,6 +88,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static com.yonge.cooleshow.biz.dal.constant.LiveRoomConstant.TEACHER_TEMP_LIVE_ROOM;
@@ -188,6 +192,8 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     @Autowired
     private UserTenantBindRecordMapper userTenantBindRecordMapper;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
 
     @Override
     public TeacherDao getDao() {
@@ -223,6 +229,14 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 detail.setTenantName(tenantInfo == null ? "" : tenantInfo.getName());
             }
         }
+
+        // 会员信息
+        detail.setUserVip(vipCardRecordService.UserVipInfo(detail.getUserId(), ClientEnum.TEACHER));
+        List<VipCardRecordWrapper.UserVipInfo> userVipInfos = vipCardRecordService.queryUserVipInfo(Collections.singletonList(userId), ClientEnum.TEACHER.getCode());
+        Map<Long, VipCardRecordWrapper.UserVipInfo> curVipMap = userVipInfos.stream().collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, Function.identity()));
+        VipCardRecordWrapper.UserVipInfo vipType = curVipMap.getOrDefault(userId, new VipCardRecordWrapper.UserVipInfo());
+        detail.setMembershipEndTime(vipType.getCurrentVipSvipEndTime());
+        detail.setVipType(vipType.getCurrentVipType());
         return detail;
     }
 
@@ -230,6 +244,25 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<TeacherVo> selectPage(IPage<TeacherVo> page, TeacherSearch search) {
         List<TeacherVo> teacherVos = baseMapper.selectPage(page, search);
 
+        for (TeacherVo record : teacherVos) {
+            EUserVipType vipType = record.getVipType();
+            if (EUserVipType.NORMAL.equals(vipType)) {
+                record.setMembershipEndTime(Optional.ofNullable(record.getVipEndTime()).orElse(record.getSvipEndTime()));
+            }
+            if (EUserVipType.SVIP.equals(vipType)) {
+                Date perSvipEndTime = record.getPerSvipEndTime();
+                if (perSvipEndTime != null) {
+                    // 永久会员
+                    record.setMembershipEndTime(null);
+                } else {
+                    record.setMembershipEndTime(record.getSvipEndTime());
+                }
+            }
+            if (EUserVipType.VIP.equals(vipType)) {
+                record.setMembershipEndTime(record.getVipEndTime());
+            }
+        }
+
         if (CollectionUtils.isEmpty(teacherVos)) {
             return page.setRecords(teacherVos);
         }
@@ -284,6 +317,10 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             }).filter(Objects::nonNull).collect(Collectors.joining(","));
             teacherVo.setSubjectName(subjectNames);
         }
+
+
+
+
         return page.setRecords(teacherVos);
     }
 
@@ -356,6 +393,11 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             }
         }
 
+        // 会员信息
+
+        teacherHomeVo.setUserVip(vipCardRecordService.UserVipInfo(teacherHomeVo.getUserId(), ClientEnum.TEACHER));
+
+
         if (YesOrNoEnum.YES.equals(teacher.getMusicianFlag())) {
             teacherHomeVo.setMusicianAuthStatus(AuthStatusEnum.PASS);
         } else {
@@ -921,6 +963,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<MyFens> queryMyFans(IPage<MyFens> page, Long teacherId) {
         List<MyFens> teacherVos = baseMapper.queryMyFans(page,
                 TeacherQueryInfo.FansQuery.builder().teacherId(teacherId).build());
+        setVip(teacherVos);
         return page.setRecords(teacherVos);
     }
 
@@ -935,6 +978,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<MyFens> queryMyFans(IPage<MyFens> page, TeacherQueryInfo.FansQuery query) {
 
         List<MyFens> teacherVos = baseMapper.queryMyFans(page, query);
+        setVip(teacherVos);
         return page.setRecords(teacherVos);
     }
 
@@ -1042,7 +1086,6 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
 
             teacherInfo.setStudentNums(studentNumsMap.getOrDefault(teacherId, 0));
         }
-
         return teacherInfo;
     }
 
@@ -1263,6 +1306,21 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 receivers, null, 0, null, ClientEnum.SYSTEM.getCode(), tenantInfo.getName());
     }
 
+    private void setVip(List<MyFens> teacherVos) {
+        if (CollectionUtils.isEmpty(teacherVos)) {
+            return;
+        }
+        List<Long> studentIds = teacherVos.stream().map(n -> Long.valueOf(n.getUserId())).collect(Collectors.toList());
+        Map<Long, EUserVipType> vipMap = vipCardRecordService.queryUserVipInfo(studentIds, ClientEnum.STUDENT.getCode()).stream()
+                .collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, VipCardRecordWrapper.UserVipInfo::getCurrentVipType));
+
+        for (MyFens teacherVo : teacherVos) {
+            EUserVipType vipType = vipMap.getOrDefault(Long.valueOf(teacherVo.getUserId()), EUserVipType.NORMAL);
+            teacherVo.setIsVip(EUserVipType.NORMAL.equals(vipType) ? YesOrNoEnum.NO : YesOrNoEnum.YES);
+            teacherVo.setVipType(vipType);
+        }
+    }
+
     /**
      * 获取学生好友最少的一个客服
      * @return 客服

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

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

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

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

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

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

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

@@ -171,6 +171,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         /**********订单生成前******************/
         //vip开通缴费
         orderCreate.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderCreate);
+        orderCreate.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderCreate);
         //直播课程购买
         orderCreate.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourse);
         //陪练课购买
@@ -195,6 +196,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         /**********订单完成后******************/
         //vip开通缴费
         orderSuccess.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderSuccess);
+        orderSuccess.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderSuccess);
         //直播课程购买
         orderSuccess.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourseSuccess);
         //陪练课购买
@@ -535,6 +537,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                     break;
                 }
                 case VIP:
+                case SVIP:
                 {
 
                     for (UserOrderDetailVo userOrderDetailVo : list) {
@@ -589,6 +592,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             info.setRecomUserId(orderReq.getRecomUserId());
             info.setActivityId(orderReq.getActivityId());
             info.setActualPrice(orderReq.getActualPrice());
+            info.setOrderClient(orderReq.getOrderClient());
             HttpResponseResult<OrderCreateRes> createResult = createFunction.apply(info);
             OrderCreateRes createRes = createResult.getData();
             if (!createResult.getStatus() || null == createRes || !createRes.getRes()) {
@@ -922,6 +926,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
 
             UserOrderDetailVo orderDetail = new UserOrderDetailVo();
             orderDetail.setOrderNo(data.getOrderNo());
+            orderDetail.setBizJson(res.getBizJson());
             orderDetail.setOrderType(orderReq.getOrderType());
             orderDetail.setSubOrderNo(data.getSubOrderNo());
             orderDetail.setMerchId(res.getMerchId());
@@ -1036,6 +1041,8 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_ACTI_REGIST);
         } else if (GoodTypeEnum.ALBUM.equals(goodTypeEnum)) {
             configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_ALBUM);
+        } else if (GoodTypeEnum.SVIP.equals(goodTypeEnum)) {
+            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_SVIP);
         }
         return configValue;
     }
@@ -1278,7 +1285,12 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                 //入老师账户
                 BigDecimal shareFee = platformFee.multiply(shareFeeRate).setScale(2, RoundingMode.HALF_UP);
                 if (shareFee.compareTo(BigDecimal.ZERO) > 0) {
-                    AccountBizTypeEnum bizTypeEnum = AccountBizTypeEnum.valueOf(orderDetailVo.getGoodType().getCode() + "_SHARE");
+                    AccountBizTypeEnum bizTypeEnum;
+                    if (orderDetailVo.getGoodType() == GoodTypeEnum.SVIP || orderDetailVo.getGoodType() == GoodTypeEnum.VIP) {
+                        bizTypeEnum= AccountBizTypeEnum.VIP_SHARE;
+                    } else {
+                        bizTypeEnum = AccountBizTypeEnum.valueOf(orderDetailVo.getGoodType().getCode() + "_SHARE");
+                    }
                     if (null != bizTypeEnum) {
                         //插入分润老师账户变更记录-分润老师预收
                         HttpResponseResult<UserAccountRecord> recomRecordRes = userAccountService.accountRecord(
@@ -1308,7 +1320,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         Calendar instance = Calendar.getInstance();
         GoodTypeEnum goodType = orderDetailVo.getGoodType();
 
-        if (GoodTypeEnum.VIP.equals(goodType)) {
+        if (GoodTypeEnum.VIP.equals(goodType) || GoodTypeEnum.SVIP.equals(goodType)) {
             instance.add(Calendar.DAY_OF_MONTH, Integer.parseInt(sysConfigService.findConfigValue(SysConfigConstant.VIP_ACCOUNT_PERIOD)));
         } else if (GoodTypeEnum.PRACTICE.equals(goodType)) {
             instance.add(Calendar.DAY_OF_MONTH, Integer.parseInt(sysConfigService.findConfigValue(SysConfigConstant.PRACTICE_ACCOUNT_PERIOD)));
@@ -1337,7 +1349,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
      */
     @Override
     public BigDecimal getShareFreeByGoodType(GoodTypeEnum goodType, Long bizId) {
-        if (GoodTypeEnum.VIP.equals(goodType)) {
+        if (GoodTypeEnum.VIP.equals(goodType) ||GoodTypeEnum.SVIP.equals(goodType)) {
             return getShareFreeByConfigName(SysConfigConstant.VIP_SHARE_FEE);
         }
         if (GoodTypeEnum.LIVE.equals(goodType)) {
@@ -1391,7 +1403,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
      */
     private BigDecimal getPlatformFreeByGoodType(GoodTypeEnum goodType) {
         //会员|琴房时长,平台全额收益
-        if (GoodTypeEnum.VIP.equals(goodType) || GoodTypeEnum.PIANO_ROOM.equals(goodType)
+        if (GoodTypeEnum.VIP.equals(goodType)|| GoodTypeEnum.SVIP.equals(goodType) || GoodTypeEnum.PIANO_ROOM.equals(goodType)
                 || GoodTypeEnum.ACTI_REGIST.equals(goodType)) {
             return BigDecimal.ONE;
         }

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

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

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

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

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

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

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

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

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
 import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -36,6 +37,8 @@ public class MyFens implements Serializable {
     @ApiModelProperty(value = "是否会员 0否 1是")
     private YesOrNoEnum isVip;
 
+    private EUserVipType vipType;
+
     @ApiModelProperty("手机号")
     private String phone;
 
@@ -148,4 +151,12 @@ public class MyFens implements Serializable {
     public void setAge(Integer age) {
         this.age = age;
     }
+
+    public EUserVipType getVipType() {
+        return vipType;
+    }
+
+    public void setVipType(EUserVipType vipType) {
+        this.vipType = vipType;
+    }
 }

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
 import com.yonge.cooleshow.common.entity.BaseEntity;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -44,6 +45,17 @@ public class MyFollow implements Serializable {
     @ApiModelProperty("老师对象")
     private Teacher teacher;
 
+    @ApiModelProperty(value = "vip类型 VIP:会员 SVIP:SVIP,NOT_VIP:不是vip")
+    private EVipType vipType;
+
+    public EVipType getVipType() {
+        return vipType;
+    }
+
+    public void setVipType(EVipType vipType) {
+        this.vipType = vipType;
+    }
+
     public String getRoomUid() {
         return roomUid;
     }

+ 6 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentHomeVo.java

@@ -2,7 +2,9 @@ package com.yonge.cooleshow.biz.dal.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -57,9 +59,12 @@ public class StudentHomeVo extends Student {
     private Integer musicAlbumNum;
     @ApiModelProperty("曲谱数 ")
     private Integer musicSheetNum;
-    @ApiModelProperty(value = "是否会员 0否 1是")
+    @ApiModelProperty(value = "是否会员 0否 1是 弃用")
     private YesOrNoEnum isVip;
 
+    @ApiModelProperty(value = "会员信息")
+    private VipCardRecordWrapper.UserVip userVip;
+
     @ApiModelProperty(value = "IM用户ID")
     private String imUserId;
 

+ 17 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentVo.java

@@ -1,6 +1,8 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
 import com.alibaba.excel.annotation.ExcelProperty;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -79,6 +81,21 @@ public class StudentVo extends Student {
 
     private String imUserId;
 
+    @ApiModelProperty(value = "会员信息")
+    private VipCardRecordWrapper.UserVip userVip;
+
+    @ApiModelProperty(value = "用户会员类型,普通用户:NORMAL,会员:VIP,SVIP:SVIP")
+    private EUserVipType vipType;
+
+   @ApiModelProperty("vip结束时间")
+    private Date vipEndTime;
+
+    @ApiModelProperty("svip结束时间")
+    private Date svipEndTime;
+
+    @ApiModelProperty("svip结束时间")
+    private Date perSvipEndTime;
+
     public YesOrNoEnum getDelFlag() {
         return delFlag;
     }

+ 9 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherHomeVo.java

@@ -5,9 +5,11 @@ import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.entity.TeacherStyleVideo;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serializable;
@@ -18,6 +20,7 @@ import java.util.List;
  * @Author: liweifan
  * @Data: 2022/3/21 18:37
  */
+@Data
 @ApiModel(value = "TeacherHomeVo对象", description = "老师主页基本信息返回")
 public class TeacherHomeVo extends Teacher implements Serializable {
     private static final long serialVersionUID = 1L;
@@ -81,6 +84,10 @@ public class TeacherHomeVo extends Teacher implements Serializable {
     private String userType;
 
 
+
+    @ApiModelProperty(value = "会员信息")
+    private VipCardRecordWrapper.UserVip userVip;
+
     @ApiModelProperty(value = "默认查询声部名称 ")
     private String defaultSubjectName;
 
@@ -95,6 +102,7 @@ public class TeacherHomeVo extends Teacher implements Serializable {
     @ApiModelProperty(value = "imToken")
     private String imToken;
 
+
     public String getTenantName() {
         return tenantName;
     }
@@ -123,7 +131,7 @@ public class TeacherHomeVo extends Teacher implements Serializable {
         this.membershipDays = membershipDays;
     }
 
-    @ApiModelProperty(value = "是否会员 0否 1是")
+    @ApiModelProperty(value = "是否会员 0否 1是 弃用")
     private YesOrNoEnum isVip;
 
     public YesOrNoEnum getIsVip() {

+ 17 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherVo.java

@@ -3,7 +3,9 @@ package com.yonge.cooleshow.biz.dal.vo;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.entity.TeacherStyleVideo;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.enums.ESettlementFrom;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.UserStatusEnum;
@@ -102,6 +104,21 @@ public class TeacherVo extends Teacher {
     @ApiModelProperty("机构小组名称")
     private String tenantGroupName;
 
+    @ApiModelProperty(value = "会员信息")
+    private VipCardRecordWrapper.UserVip userVip;
+
+    @ApiModelProperty(value = "用户会员类型,普通用户:NORMAL,会员:VIP,SVIP:SVIP")
+    private EUserVipType vipType;
+
+    @ApiModelProperty("vip结束时间")
+    private Date vipEndTime;
+
+    @ApiModelProperty("svip结束时间")
+    private Date svipEndTime;
+
+    @ApiModelProperty("svip结束时间")
+    private Date perSvipEndTime;
+
     @ApiModelProperty("是否客服")
     private Boolean customerService;
 

+ 10 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/HomeTotalStudent.java

@@ -15,6 +15,8 @@ public class HomeTotalStudent {
     private Integer registerNum;
     @ApiModelProperty("新增会员学员 ")
     private Integer vipNum;
+    @ApiModelProperty("新增会员学员 ")
+    private Integer svipNum;
     @ApiModelProperty("新增陪练课学员 ")
     private Integer practiceNum;
     @ApiModelProperty("新增视频课学员 ")
@@ -112,4 +114,12 @@ public class HomeTotalStudent {
     public void setInfoList(List<HomeTotalStudent> infoList) {
         this.infoList = infoList;
     }
+
+    public Integer getSvipNum() {
+        return svipNum;
+    }
+
+    public void setSvipNum(Integer svipNum) {
+        this.svipNum = svipNum;
+    }
 }

+ 5 - 119
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/OrderCreateRes.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.biz.dal.enums.OrderTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 import java.math.BigDecimal;
 
@@ -13,6 +14,7 @@ import java.math.BigDecimal;
  * @Data: 2022/3/31 16:18
  */
 @ApiModel(value = "OrderCheckRes", description = "订单创建业务返回对象")
+@Data
 public class OrderCreateRes {
     @ApiModelProperty("验证结果")
     private Boolean res;
@@ -41,6 +43,9 @@ public class OrderCreateRes {
     @ApiModelProperty("奖品id")
     private Long rewardId;
 
+    @ApiModelProperty(value = "业务数据")
+    private String bizJson;
+
     @ApiModelProperty(value = "冗余字段,用于传递参数用")
     private Object bizParam;
 
@@ -50,123 +55,4 @@ public class OrderCreateRes {
     // 商品来源
     private SourceTypeEnum sourceType;
 
-    public SourceTypeEnum getSourceType() {
-        return sourceType;
-    }
-
-    public void setSourceType(SourceTypeEnum sourceType) {
-        this.sourceType = sourceType;
-    }
-
-    public Long getRewardId() {
-        return rewardId;
-    }
-
-    public void setRewardId(Long rewardId) {
-        this.rewardId = rewardId;
-    }
-
-    public Long getActivityId() {
-        return activityId;
-    }
-
-    public void setActivityId(Long activityId) {
-        this.activityId = activityId;
-    }
-
-    public Boolean getRes() {
-        return res;
-    }
-
-    public void setRes(Boolean res) {
-        this.res = res;
-    }
-
-    public Long getMerchId() {
-        return merchId;
-    }
-
-    public void setMerchId(Long merchId) {
-        this.merchId = merchId;
-    }
-
-    public Long getBizId() {
-        return bizId;
-    }
-
-    public void setBizId(Long bizId) {
-        this.bizId = bizId;
-    }
-
-    public BigDecimal getOriginalPrice() {
-        return originalPrice;
-    }
-
-    public void setOriginalPrice(BigDecimal originalPrice) {
-        this.originalPrice = originalPrice;
-    }
-
-    public BigDecimal getExpectPrice() {
-        return expectPrice;
-    }
-
-    public void setExpectPrice(BigDecimal expectPrice) {
-        this.expectPrice = expectPrice;
-    }
-
-    public String getBizContent() {
-        return bizContent;
-    }
-
-    public void setBizContent(String bizContent) {
-        this.bizContent = bizContent;
-    }
-
-    public Integer getGoodNum() {
-        return goodNum;
-    }
-
-    public void setGoodNum(Integer goodNum) {
-        this.goodNum = goodNum;
-    }
-
-    public GoodTypeEnum getGoodType() {
-        return goodType;
-    }
-
-    public void setGoodType(GoodTypeEnum goodType) {
-        this.goodType = goodType;
-    }
-
-    public Object getBizParam() {
-        return bizParam;
-    }
-
-    public void setBizParam(Object bizParam) {
-        this.bizParam = bizParam;
-    }
-
-    public BigDecimal getActualPrice() {
-        return actualPrice;
-    }
-
-    public void setActualPrice(BigDecimal actualPrice) {
-        this.actualPrice = actualPrice;
-    }
-
-    public BigDecimal getCouponAmount() {
-        return couponAmount;
-    }
-
-    public void setCouponAmount(BigDecimal couponAmount) {
-        this.couponAmount = couponAmount;
-    }
-
-    public OrderTypeEnum getOrderType() {
-        return orderType;
-    }
-
-    public void setOrderType(OrderTypeEnum orderType) {
-        this.orderType = orderType;
-    }
 }

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.vo.userBindingTeacher;
 
 import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -39,6 +40,8 @@ public class UserBindingTeacherWrapper {
     // 是否会员 0否 1是
     private YesOrNoEnum isVip;
 
+    private EUserVipType vipType;
+
 
     // 课程数
     private Integer courseNum;
@@ -151,6 +154,14 @@ public class UserBindingTeacherWrapper {
         this.bindingTime = bindingTime;
     }
 
+    public EUserVipType getVipType() {
+        return vipType;
+    }
+
+    public void setVipType(EUserVipType vipType) {
+        this.vipType = vipType;
+    }
+
     public static class CourseNum {
 
         // 学生id

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

@@ -852,4 +852,14 @@ public class MusicSheetWrapper {
         }
     }
 
+
+    @Data
+    public static class MusicUse{
+
+        @ApiModelProperty("是否能播放(0:否,1:是) 学生端进入小酷Ai判断 试用/完整 播放")
+        private YesOrNoEnum play;
+
+        @ApiModelProperty("是否购买(0:否,1:是)")
+        private Boolean buyed = false;
+    }
 }

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

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.wrapper;
 
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.yonge.cooleshow.biz.dal.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -12,7 +13,6 @@ import org.apache.commons.lang3.StringUtils;
 
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
-import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserMusicWrapper.java

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.biz.dal.wrapper;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.common.enums.EUserMusicType;
 import com.microsvc.toolkit.common.response.paging.QueryInfo;
 import io.swagger.annotations.ApiModel;
@@ -109,6 +110,10 @@ public class UserMusicWrapper {
         @ApiModelProperty(value = "是否会员")
         private Boolean vipFlag;
 
+
+        @ApiModelProperty(value = "vip类型 VIP:会员 SVIP:SVIP,NOT_VIP:不是vip")
+        private EVipType vipType;
+
         @ApiModelProperty("关联练习数据ID")
         private Long musicPracticeRecordId;
 

+ 10 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserPaymentOrderWrapper.java

@@ -846,6 +846,8 @@ public class UserPaymentOrderWrapper {
         @ApiModelProperty("业务内容 ")
         private Object bizContent;
 
+        @ApiModelProperty(value = "vip剩余天数")
+        private Integer vipEndDays;
 
         @ApiModelProperty("商品数量 ")
         private Integer goodNum;
@@ -932,4 +934,12 @@ public class UserPaymentOrderWrapper {
             return JSON.toJSONString(this);
         }
     }
+
+
+    @Data
+    public static class VipDays implements Serializable {
+
+
+        private Integer vipEndDays;
+    }
 }

+ 131 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/VipCardRecordWrapper.java

@@ -0,0 +1,131 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.yonge.cooleshow.biz.dal.enums.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.Optional;
+
+public class VipCardRecordWrapper {
+
+    @Data
+    public static class UserVip{
+
+
+        @ApiModelProperty(value = "vip类型 VIP:会员 SVIP:SVIP,PERMANENT_SVIP:永久SVIP,NOT_VIP:不是vip")
+        private EVipType vipType;
+
+
+        @ApiModelProperty(value = "vip过期类型 VIP:会员 SVIP:SVIP,ALL_VIP:全vip")
+        private EVipType expireVipType;
+
+
+        @ApiModelProperty(value = "vip结束时间")
+        private Date vipEndDate;
+
+
+        @ApiModelProperty(value = "vip剩余天数")
+        private Integer vipEndDays =0;
+
+        @ApiModelProperty(value = "svip结束时间")
+        private Date svipEndDate;
+
+
+        @ApiModelProperty(value = "svip剩余天数")
+        private Integer svipEndDays =0;
+    }
+
+    @ApiModel("添加/扣减会员")
+    @Data
+    public static class AddVipCardRecord {
+
+        @ApiModelProperty("用户ID")
+        @NotNull(message = "用户不能为空")
+        private Long userId;
+
+        @ApiModelProperty("用户类型")
+        @NotNull(message = "用户类型不能为空")
+        private ClientEnum clientType;
+
+        @ApiModelProperty("状态 ADD:新增,DEDUCTION:扣减,UPDATE:变更")
+        @NotNull
+        private EVipRecordStatus status;
+
+        @ApiModelProperty("会员类型,VIP,SVIP")
+        @NotNull
+        private EVipType vipType;
+
+        @ApiModelProperty("时间类型 DAY:天 MONTH:月 ,QUARTERLY : 季度 YEAR_HALF : 半年 YEAR:年,永久:PERMANENT")
+        @NotNull
+        private PeriodEnum type;
+
+        @ApiModelProperty("数量")
+        @Min(value = 1, message = "最小数量为1")
+        @Max(value = 999, message = "最大数量为999")
+        private Integer times;
+
+        @ApiModelProperty("扣减原因")
+        @NotNull
+        private String reason;
+
+        @ApiModelProperty("是否发送推送,是:true,否:false")
+        @NotNull
+        private Boolean sendMsg;
+
+        @ApiModelProperty(value = "创建人",hidden = true)
+        private Long createBy;
+
+        @ApiModelProperty(value = "转换VIP天数",hidden = true)
+        private Integer vipDays;
+
+
+        @ApiModelProperty("来源类型 : ACTIVITY :活动 ,ORDER:订单")
+        private SourceTypeEnum sourceType;
+
+        private String orderNo;
+        private Long vipCardId;
+        private String subOrderNo;
+    }
+
+    @Data
+    public static class UserVipInfo {
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+        @ApiModelProperty("当前会员类型")
+        private EUserVipType currentVipType;
+
+        @ApiModelProperty("VIP的结束时间")
+        private Date currentVipSvipEndTime;
+
+        @ApiModelProperty("vip结束时间")
+        private Date vipEndTime;
+
+        @ApiModelProperty("svip结束时间")
+        private Date svipEndTime;
+
+        @ApiModelProperty("svip结束时间")
+        private Date perSvipEndTime;
+
+        public Date getCurrentVipSvipEndTime() {
+            if (EUserVipType.NORMAL.equals(currentVipType)) {
+                return Optional.ofNullable(vipEndTime).orElse(svipEndTime);
+            } else if (EUserVipType.VIP.equals(currentVipType)) {
+                return vipEndTime;
+            } else {
+                if (perSvipEndTime != null) { // 永久SVIP
+                    return null;
+                } else {
+                    return svipEndTime;
+                }
+            }
+        }
+    }
+}

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

@@ -120,6 +120,7 @@
 			</if>
 			sum(a.registerNum) as registerNum,
 			sum(b.vipNum) as vipNum,
+			sum(b2.svipNum) as svipNum,
 			sum(c.practiceNum) as practiceNum,
 			sum(d.videoNum) as videoNum,
 			sum(e.liveNum) as liveNum,
@@ -159,6 +160,21 @@
 		) b on t.sys_day_ymd_ = b.timeStr
 		left join (
 		select
+		DATE_FORMAT(t.first_svip_time_,'%Y-%m-%d') as timeStr,
+		count(1) as svipNum
+		from student_time t
+		<where>
+			<if test="param.startTime !=null">
+				<![CDATA[AND t.first_svip_time_ >= #{param.startTime} ]]>
+			</if>
+			<if test="param.endTime !=null">
+				<![CDATA[AND t.first_svip_time_ < #{param.endTime} ]]>
+			</if>
+		</where>
+		group by DATE_FORMAT(t.first_svip_time_,'%Y-%m-%d')
+		) b2 on t.sys_day_ymd_ = b2.timeStr
+		left join (
+		select
 			DATE_FORMAT(t.first_pay_time_,'%Y-%m-%d') as timeStr,
 			count(1) as payNum
 		from student_time t

+ 15 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/MemberPriceSettingsMapper.xml

@@ -10,6 +10,9 @@
 		<result column="update_time_" property="updateTime" />
 		<result column="create_by_" property="createBy" />
 		<result column="update_by_" property="updateBy" />
+		<result column="status_" property="status" />
+		<result column="desc_" property="desc" />
+		<result column="vip_type_" property="vipType" />
 	</resultMap>
 
 	<!-- 表字段 -->
@@ -22,6 +25,9 @@
         , t.update_time_ as updateTime
         , t.create_by_ as createBy
         , t.update_by_ as updateBy
+        , t.status_ as status
+        , t.desc_ as `desc`
+        , t.vip_type_ as vipType
         </sql>
 
 	<select id="detail" resultType="com.yonge.cooleshow.biz.dal.vo.MemberPriceSettingsVo">
@@ -39,6 +45,14 @@
 		ifnull(u.real_name_,u.username_) as modifierName
 		FROM member_price_settings t
 		LEFT JOIN sys_user u on t.update_by_ = u.id_
+		<where>
+			<if test="param.status != null">
+				and t.status_ = #{param.status}
+			</if>
+			<if test="param.vipType != null">
+				and t.vip_type_ = #{param.vipType}
+			</if>
+		</where>
 	</sql>
 
 	<select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.vo.MemberPriceSettingsVo">
@@ -55,6 +69,6 @@
 			<include refid="baseColumns"/>
 		FROM user_order_detail d
 		left join member_price_settings t on d.biz_id_ = t.id_
-		where d.good_type_ = 'VIP' and  d.id_ = #{orderDetilId}
+		where d.good_type_ in ('VIP','SVIP') and  d.id_ = #{orderDetilId}
 	</select>
 </mapper>

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

@@ -139,6 +139,18 @@
         </if>
         <where>
             1=1
+            <if test="param.excludeMusicIds != null and param.excludeMusicIds.size() != 0">
+                and t.id_ not in
+                <foreach collection="param.excludeMusicIds" separator="," item="item" open="(" close=")">
+                    #{item}
+                </foreach>
+            </if>
+            <if test="param.mustMatchSubjectIds != null and param.mustMatchSubjectIds.size() != 0">
+                and
+                <foreach collection="param.mustMatchSubjectIds" separator="and" item="item" open="(" close=")">
+                    find_in_set(#{item},t.music_subject_)
+                </foreach>
+            </if>
             <include refid="QueryInfo"/>
             <if test="param.auditStatus == null">
                 AND t.cbs_music_sheet_id_ IS NOT NULL
@@ -277,6 +289,12 @@
             <if test="param.chargeType != null">
                 and t.charge_type_ = #{param.chargeType}
             </if>
+            <if test="param.excludeMusicIds != null and param.excludeMusicIds.size() != 0">
+                and t.id_ not in
+                <foreach collection="param.excludeMusicIds" separator="," item="item" open="(" close=")">
+                    #{item}
+                </foreach>
+            </if>
             <if test="param.musicTagIds != null and param.musicTagIds != ''">
                 and
                 <foreach collection="param.musicTagIdList" separator="or" item="item"  open="(" close=")" >

+ 35 - 14
cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentMapper.xml

@@ -24,8 +24,8 @@
         , t.subject_id_ as `subjectId`
         , t.current_grade_num_ as `currentGradeNum`
         , t.member_rank_setting_id_ as `memberRankSettingId`
-        , t.membership_start_time_ as `membershipStartTime`
-        , t.membership_end_time_ as `membershipEndTime`
+<!--        , t.membership_start_time_ as `membershipStartTime`-->
+<!--        , t.membership_end_time_ as `membershipEndTime`-->
         , t.cloud_study_sequence_days_ as `cloudStudySequenceDays`
         , t.cloud_study_use_last_day_ as `cloudStudyUseLastDay`
         , t.train_time_ as trainTime
@@ -103,7 +103,13 @@
             u.phone_ as phone,
             !isnull(birthdate_) as isReal,
             u.real_name_ as realName,
-            (!isnull(membership_end_time_) and membership_end_time_ > now()) as isVip,
+            ifnull(vcr2.vip_type_ ,'NORMAL') as vipType,
+<!--            if(vcr.type_ = 'PERMANENT',null,vcr.end_time_) as membershipEndTime,-->
+            max(if(vcr.vip_type_ = 'VIP', vcr.end_time_, null)) vipEndTime,
+            max(if(vcr.vip_type_ = 'SVIP' and vcr.type_ = 'PERPETUAL', vcr.end_time_ , null)) perSvipEndTime,
+            max(if(vcr.vip_type_ = 'SVIP' , vcr.end_time_, null)) svipEndTime,
+            max(vcr.end_time_) currentVipEndTime,
+<!--            (!isnull(membership_end_time_) and membership_end_time_ > now()) as isVip,-->
             (
             SELECT GROUP_CONCAT(name_ ORDER by locate(id_,t.subject_id_)) FROM subject WHERE FIND_IN_SET(id_,t.subject_id_)
             ) as subjectName,
@@ -111,6 +117,8 @@
         FROM student t
         left join sys_user u on t.user_id_ = u.id_
         left join tenant_info ti on t.tenant_id_ = ti.id_
+        left join vip_card_record vcr on t.user_id_ = vcr.user_id_ and vcr.efficient_flag_ = 1 and vcr.client_type_='STUDENT'
+        left join vip_card_record vcr2 on t.user_id_ = vcr2.user_id_ and vcr2.efficient_flag_ = 1 and vcr2.end_time_ > now() and now() >= vcr2.start_time_ and vcr2.client_type_='STUDENT'
         <where>
             <if test="null != param.search and '' != param.search">
                 AND (
@@ -126,14 +134,22 @@
             <if test="null != param.subjectId and '' != param.subjectId">
                 AND FIND_IN_SET(t.subject_id_, #{param.subjectId})
             </if>
-            <if test="null != param.isVip">
-                <if test="1 == param.isVip.code">
-                    and t.membership_end_time_ &gt; now()
+            <if test="param.vipType != null">
+                <if test="param.vipType.code == 'NORMAL'">
+                    and vcr2.id_ is null
                 </if>
-                <if test="0 == param.isVip.code">
-                    and (t.membership_end_time_ is null or t.membership_end_time_ &lt;= now())
+                <if test="param.vipType.code != 'NORMAL'">
+                    and vcr2.vip_type_ = #{param.vipType}
                 </if>
             </if>
+<!--            <if test="null != param.isVip">-->
+<!--                <if test="1 == param.isVip.code">-->
+<!--                    and t.membership_end_time_ &gt; now()-->
+<!--                </if>-->
+<!--                <if test="0 == param.isVip.code">-->
+<!--                    and (t.membership_end_time_ is null or t.membership_end_time_ &lt;= now())-->
+<!--                </if>-->
+<!--            </if>-->
             <if test="param.startTime !=null">
                 <![CDATA[AND t.create_time_ >= #{param.startTime} ]]>
             </if>
@@ -146,12 +162,12 @@
             <if test="null != param.delFlag">
                 and u.del_flag_ = #{param.delFlag}
             </if>
-            <if test="null != param.vipEndTime">
-                and t.membership_end_time_ &lt;= #{param.vipEndTime}
-            </if>
-            <if test="null != param.vipStartTime">
-                and t.membership_end_time_ &gt;= #{param.vipStartTime}
-            </if>
+<!--            <if test="null != param.vipEndTime">-->
+<!--                and vcr.end_time_ &lt;= #{param.vipEndTime}-->
+<!--            </if>-->
+<!--            <if test="null != param.vipStartTime">-->
+<!--                and vcr.end_time_ &gt;= #{param.vipStartTime}-->
+<!--            </if>-->
             <if test="param.trainFlag != null">
                 AND t.train_time_ > 0
             </if>
@@ -183,6 +199,11 @@
                 AND FIND_IN_SET(t.tenant_group_id_, #{param.tenantGroupId})
             </if>
         </where>
+        group by t.user_id_
+        <if test="param.vipStartTime != null and param.vipEndTime != null">
+<!--        having  ((vipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> vipEndTime) or (svipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> svipEndTime))-->
+        having  currentVipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> currentVipEndTime
+        </if>
         <choose>
             <when test="param.orderBy != null and param.orderBy.trim() != ''">
                 order by ${param.orderBy}

+ 2 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/StudentTimeMapper.xml

@@ -4,6 +4,7 @@
     <resultMap id="BaseResultMap" type="com.yonge.cooleshow.biz.dal.entity.StudentTime">
         <result column="user_id_" property="userId" />
         <result column="first_vip_time_" property="firstVipTime" />
+        <result column="first_svip_time_" property="firstSvipTime" />
         <result column="first_practice_time_" property="firstPracticeTime" />
         <result column="first_video_time_" property="firstVideoTime" />
         <result column="first_live_time_" property="firstLiveTime" />
@@ -17,6 +18,7 @@
     <sql id="baseColumns">
          t.user_id_ as userId
         , t.first_vip_time_ as firstVipTime
+        , t.first_svip_time_ as firstSvipTime
         , t.first_practice_time_ as firstPracticeTime
         , t.first_video_time_ as firstVideoTime
         , t.first_live_time_ as firstLiveTime

+ 35 - 12
cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherMapper.xml

@@ -78,8 +78,8 @@
         , t.degree_flag_ as "degreeFlag"
         , t.teacher_flag_ as "teacherFlag"
         , t.member_rank_setting_id_ as "memberRankSettingId"
-        , t.membership_start_time_ as "membershipStartTime"
-        , t.membership_end_time_ as "membershipEndTime"
+<!--        , t.membership_start_time_ as "membershipStartTime"-->
+<!--        , t.membership_end_time_ as "membershipEndTime"-->
         , t.browse_ as "browse"
         , t.memo_ as "memo"
         , t.tag_ as "tag"
@@ -106,9 +106,14 @@
         u.avatar_ as avatar,
         u.birthdate_ as birthdate,
         u.gender_ as gender,
-        (case when t.membership_end_time_ &gt;= now() then 1 else 0 end) isVip,
+<!--        (case when t.membership_end_time_ &gt;= now() then 1 else 0 end) isVip,-->
         <!--            t.tag_ tag,-->
         u.del_flag_ as delFlag,
+        ifnull(vcr2.vip_type_ ,'NORMAL') as vipType,
+        max(if(vcr.vip_type_ = 'VIP', vcr.end_time_, null)) vipEndTime,
+        max(if(vcr.vip_type_ = 'SVIP' and vcr.type_ = 'PERPETUAL', vcr.end_time_ , null)) perSvipEndTime,
+        max(if(vcr.vip_type_ = 'SVIP', vcr.end_time_, null)) svipEndTime,
+        max(vcr.end_time_) currentVipEndTime,
         (case when isnull(u.id_card_no_) then 0 else 1 end) as isReal,
         (case when isnull(b.user_id_) then 0 else 1 end) as isBank,
         (case when t.tenant_id_ = -1 then '平台' else ti.name_ end) as tenantName
@@ -118,6 +123,8 @@
         select distinct user_id_ from user_bank_card where del_flag_ = 0
         ) b on t.user_id_ = b.user_id_
         left join tenant_info ti on t.tenant_id_ = ti.id_
+        left join vip_card_record vcr on t.user_id_ = vcr.user_id_ and vcr.efficient_flag_ = 1 and vcr.client_type_='STUDENT'
+        left join vip_card_record vcr2 on t.user_id_ = vcr2.user_id_ and vcr2.efficient_flag_ = 1 and vcr2.end_time_ > now() and now() >= vcr2.start_time_ and vcr2.client_type_='STUDENT'
         <where>
             <if test="null != param.search and '' != param.search">
                 AND (
@@ -141,14 +148,22 @@
                 </if>
                 )
             </if>
-            <if test="param.isVip != null">
-                <if test="param.isVip == 0">
-                    and (t.membership_end_time_ is null or t.membership_end_time_ &lt; now())
+            <if test="param.vipType != null">
+                <if test="param.vipType.code == 'NORMAL'">
+                    and vcr2.id_ is null
                 </if>
-                <if test="param.isVip == 1">
-                    and t.membership_end_time_ &gt;= now()
+                <if test="param.vipType.code != 'NORMAL'">
+                    and vcr2.vip_type_ = #{param.vipType}
                 </if>
             </if>
+<!--            <if test="param.isVip != null">-->
+<!--                <if test="param.isVip == 0">-->
+<!--                    and (t.membership_end_time_ is null or t.membership_end_time_ &lt; now())-->
+<!--                </if>-->
+<!--                <if test="param.isVip == 1">-->
+<!--                    and t.membership_end_time_ &gt;= now()-->
+<!--                </if>-->
+<!--            </if>-->
             <if test="param.tag != null">
                 and find_in_set(#{param.tag},t.tag_)
             </if>
@@ -168,10 +183,10 @@
                 and t.is_test_user_ = #{param.isTestUser}
             </if>
             <if test="null != param.vipEndTime">
-                and t.membership_end_time_ &lt;= #{param.vipEndTime}
+                and vcr.end_time_ &lt;= #{param.vipEndTime}
             </if>
             <if test="null != param.vipStartTime">
-                and t.membership_end_time_ &gt;= #{param.vipStartTime}
+                and vcr.end_time_ &gt;= #{param.vipStartTime}
             </if>
             <if test="param.trainFlag != null">
                 AND t.train_time_ > 0
@@ -198,6 +213,11 @@
                 AND t.customer_service_ = #{param.customerService}
             </if>
         </where>
+        group by t.user_id_
+        <if test="param.vipStartTime != null and param.vipEndTime != null">
+<!--            having  ((vipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> vipEndTime) or (svipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> svipEndTime))-->
+            having  currentVipEndTime >= #{param.vipStartTime} and #{param.vipEndTime}> currentVipEndTime
+        </if>
         <choose>
             <when test="param.orderBy != null and param.orderBy.trim() != ''">
                 order by ${param.orderBy}
@@ -244,6 +264,7 @@
         (!isnull(membership_end_time_) and membership_end_time_ > now()) as isVip,
         u.real_name_ as realName,
         u.id_card_no_ as idCardNo,
+        if(vcr.type_ = 'PERMANENT',null,vcr.end_time_) as membershipEndTime,
         (case when isnull(b.user_id_) then 0 else 1 end) as isBank,
         (
         SELECT GROUP_CONCAT(name_ ORDER by locate(id_,t.subject_id_)) FROM subject WHERE FIND_IN_SET(id_,t.subject_id_)
@@ -254,6 +275,8 @@
         left join (
         select distinct user_id_ from user_bank_card where del_flag_ = 0 and user_id_ = #{userId}
         ) b on t.user_id_ = b.user_id_
+        left join vip_card_record vcr on t.user_id_ = vcr.user_id_ and vcr.client_type_ = 'TEACHER'
+        and vcr.efficient_flag_ = 1 and vcr.end_time_ >= now() and now() > vcr.start_time_ and (vcr.vip_type_ = 'VIP' or vcr.vip_type_ = 'SVIP') and vcr.client_type_ = 'TEACHER'
         where u.del_flag_ = 0 and t.user_id_ = #{userId}
     </select>
 
@@ -326,8 +349,8 @@
         u.gender_ AS gender,
         u.phone_ AS phone,
         u.birthdate_ AS birthdate,
-        (SELECT group_concat(name_) FROM `subject` WHERE find_in_set(id_,sr.subject_id_)) AS subjectName,
-        if(sr.membership_start_time_ &lt;= now() and sr.membership_end_time_ &gt;= now(),1,0) AS isVip
+        (SELECT group_concat(name_) FROM `subject` WHERE find_in_set(id_,sr.subject_id_)) AS subjectName
+<!--        if(sr.membership_start_time_ &lt;= now() and sr.membership_end_time_ &gt;= now(),1,0) AS isVip-->
         FROM student_star s
         LEFT JOIN sys_user u ON s.student_id_ = u.id_
         LEFT JOIN student sr ON s.student_id_ = sr.user_id_

+ 2 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderDetailMapper.xml

@@ -22,6 +22,7 @@
 	        <result column="create_time_" property="createTime" />
 	        <result column="update_time_" property="updateTime" />
 	        <result column="tenant_group_album_id_" property="tenantGroupAlbumId" />
+	        <result column="biz_json_" property="bizJson" />
 		</resultMap>
 
     <!-- 表字段 -->
@@ -47,6 +48,7 @@
         , t.tenant_group_album_id_ as tenantGroupAlbumId
         , t.create_time_ as createTime
         , t.update_time_ as updateTime
+        , t.biz_json_ as bizJson
         </sql>
 
     <select id="detail" resultType="com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo">

+ 3 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderMapper.xml

@@ -244,7 +244,9 @@
             and d.good_type_ = #{param.goodType}
             <choose>
                 <when test="param.goodType != null and param.goodType != 'PRACTICE'">
-                    and d.biz_id_ = #{param.bizId}
+                    <if test="param.bizId != null">
+                        and d.biz_id_ = #{param.bizId}
+                    </if>
                 </when>
             </choose>
         )

+ 50 - 8
cooleshow-user/user-biz/src/main/resources/config/mybatis/VipCardRecordMapper.xml

@@ -17,6 +17,11 @@
             <result column="times_" property="times" />
             <result column="create_by_" property="createBy" />
             <result column="reason_" property="reason" />
+            <result column="vip_type_" property="vipType" />
+            <result column="status_" property="status" />
+            <result column="display_flag_" property="displayFlag" />
+            <result column="ref_id_" property="refId" />
+            <result column="efficient_flag_" property="efficientFlag" />
 		</resultMap>
 
     <!-- 表字段 -->
@@ -37,6 +42,11 @@
         ,t.times_ as times
         ,t.create_by_ as createBy
         ,t.reason_ as reason
+        ,t.vip_type_ as vipType
+        ,t.status_ as status
+        ,t.display_flag_ as displayFlag
+        ,t.ref_id_ as refId
+        ,t.efficient_flag_ as efficientFlag
         </sql>
 
     <select id="detail" resultType="com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo">
@@ -46,7 +56,7 @@
             s.sale_price_ as salePrice,
             s.period_ as `period`
         FROM user_order_detail a
-        left join vip_card_record t on a.order_no_ = t.order_no_ and a.sub_order_no_ = t.sub_order_no_
+        left join vip_card_record t on a.order_no_ = t.order_no_ and a.sub_order_no_ = t.sub_order_no_ and t.display_flag_ = 1
         left join member_price_settings s on t.vip_card_id_ = s.id_
         where a.id_ = #{orderDetilId}
         <if test="userId != null">
@@ -71,23 +81,31 @@
             <include refid="baseColumns"/>,
             u.phone_ as phone
         from (
-            select max(id_) as id_ from vip_card_record group by user_id_
+            select any_value(id_) id_
+            from (
+            select * from vip_card_record where efficient_flag_ = 1 and end_time_ &gt;= now() and end_time_ &lt; DATE_ADD(now(),INTERVAL 3 DAY) order by end_time_ desc
+            ) t group by t.user_id_,t.client_type_,t.vip_type_
         ) a
         left join vip_card_record t on a.id_ = t.id_
         left join sys_user u on t.user_id_ = u.id_
-        where t.end_time_ &gt;= now()
-        and t.end_time_ &lt; DATE_ADD(now(),INTERVAL 3 DAY)
-        and msg_status_ = 0
-        order by end_time_ desc
+        where t.msg_status_ = 0
+        order by t.end_time_ desc
     </select>
 
     <select id="selectExpireRecord" resultType="com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo">
         select
             <include refid="baseColumns"/>,
             u.phone_ as phone
-        from vip_card_record t
+        from (
+            select any_value(id_) id_
+            from (
+            select * from vip_card_record where efficient_flag_ = 1 order by end_time_ desc
+            ) t group by t.user_id_,t.client_type_,t.vip_type_
+        ) a
+        left join vip_card_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 t.efficient_flag_ = 1
+        and t.end_time_ &lt;= now()
         and msg_status_ in (0,1)
         order by end_time_ desc
     </select>
@@ -117,7 +135,31 @@
           <if test="param.sourceType != null">
               and t.source_type_ = #{param.sourceType}
           </if>
+          <if test="param.displayFlag != null">
+              and t.display_flag_ = #{param.displayFlag}
+          </if>
+          <if test="param.vipType != null">
+              and t.vip_type_ = #{param.vipType}
+          </if>
       </where>
         order by  t.id_ desc
     </select>
+
+    <select id="queryUserVipInfo" resultType="com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper$UserVipInfo">
+        select m.*
+        , ifnull(vcr.vip_type_, 'NORMAL') currentVipType
+        from (select t.user_id_ userId
+        , max(if(t.vip_type_ = 'VIP', t.end_time_, null)) vipEndTime
+        , max(if(t.vip_type_ = 'SVIP' and t.type_ = 'PERPETUAL', t.end_time_, null)) perSvipEndTime
+        , max(if(t.vip_type_ = 'SVIP', t.end_time_, null)) svipEndTime
+        from vip_card_record t
+        where t.user_id_ in
+        <foreach collection="userIdList" separator="," item="item" open="(" close=")">
+            #{item}
+        </foreach>
+        and t.client_type_ = 'STUDENT'
+        and t.efficient_flag_ = 1
+        group by t.user_id_) m
+        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
+    </select>
 </mapper>