Explorar el Código

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

zouxuan hace 6 meses
padre
commit
576aa97d87
Se han modificado 16 ficheros con 859 adiciones y 56 borrados
  1. 81 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/DiscountCardRecordController.java
  2. 27 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/SubjectController.java
  3. 20 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherHomeController.java
  4. 26 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/DiscountCardRecord.java
  5. 45 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EDeductionStatus.java
  6. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  7. 2 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/PeriodEnum.java
  8. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/SourceTypeEnum.java
  9. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/DiscountCardRecordMapper.java
  10. 19 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/DiscountCardRecordService.java
  11. 278 49
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/DiscountCardRecordServiceImpl.java
  12. 245 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/DiscountCardRecordWrapper.java
  13. 29 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TeacherIndexWrapper.java
  14. 61 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/DiscountCardRecordMapper.xml
  15. 2 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml
  16. 13 0
      toolset/utils/src/main/java/com/yonge/toolset/utils/date/DateUtil.java

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

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

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

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

+ 20 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherHomeController.java

@@ -1,20 +1,28 @@
 package com.yonge.cooleshow.teacher.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.biz.dal.dto.excel.UserWithdrawalExport;
+import com.yonge.cooleshow.biz.dal.dto.search.TeacherWithdrawalSearch;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.PianoRoomTimeVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherHomeStatisticalVo;
+import com.yonge.cooleshow.biz.dal.vo.UserWithdrawalVo;
 import com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherHomeWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
+import com.yonge.toolset.utils.easyexcel.ExcelUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.BeanUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -138,4 +146,16 @@ public class TeacherHomeController extends BaseController {
         return succeed(teacherIncomePageInfo);
     }
 
+    @PostMapping("/exportStudentPractice")
+    @ApiOperation(value = "查询导出首页练习数据学员列表")
+    public void exportExcel(@RequestBody TeacherIndexWrapper.StudentSearch studentSearch) {
+        studentSearch.setTeacherId(sysUserService.getUserId());
+        studentSearch.setLimit(10000);
+        List<TeacherIndexWrapper.StudentPracticeSummaryDto> teacherHomeStudent = homeService.getTeacherHomeStudent(studentSearch);
+        List<TeacherIndexWrapper.StudentPracticeSummaryExportDto> list =
+                JSON.parseArray(JSON.toJSONString(teacherHomeStudent), TeacherIndexWrapper.StudentPracticeSummaryExportDto.class);
+        ExcelUtils.exportExcel(list, "学员练习统计" + System.currentTimeMillis(),
+                "列表数据");
+    }
+
 }

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

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

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

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

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

@@ -190,6 +190,8 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     GROUP_SUCCESS_TEACHER("小组课已成课"),
     GROUP_FAIL_STUDENT("小组课成课失败"),
     GROUP_FAIL_TEACHER("小组课成课失败"),
+    DEDUCTION_DISCOUNT_SMS("扣减畅学卡"),
+    ADD_DISCOUNT_SMS("添加畅学卡"),
     ;
 
     MessageTypeEnum(String msg) {

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

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

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

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

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

@@ -1,10 +1,12 @@
 package com.yonge.cooleshow.biz.dal.mapper;
 
+import java.util.Date;
 import java.util.List;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.entity.MemberPriceSettings;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 import com.yonge.cooleshow.biz.dal.entity.DiscountCardRecord;
@@ -18,5 +20,10 @@ public interface DiscountCardRecordMapper extends BaseMapper<DiscountCardRecord>
 
     MemberPriceSettings detail(@Param("userId") Long userId, @Param("orderDetilId") Long orderDetilId);
 
+    IPage<DiscountCardRecordWrapper.DiscountCardRecord> selectPage(@Param("page") IPage<DiscountCardRecordWrapper.DiscountCardRecord> page,
+                                                                   @Param("param") DiscountCardRecordWrapper.DiscountCardRecordQuery query);
+
+    void updateUserDiscountTime(@Param("userId") Long userId, @Param("startTime") Date startTime, @Param("endTime") Date endTime);
+
     void updateMsgStatus(@Param("ids") List<Long> ids, @Param("msgStatus") int msgStatus);
 }

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

@@ -1,8 +1,10 @@
 package com.yonge.cooleshow.biz.dal.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.entity.DiscountCardRecord;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
+import com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper;
 
 /**
  * 购买会员卡记录表
@@ -13,5 +15,22 @@ public interface DiscountCardRecordService extends IService<DiscountCardRecord>
 
     void orderSuccess(UserOrderDetailVo userPaymentOrder);
 
+
+    void addStudentVip(DiscountCardRecordWrapper.AddDiscountCardRecord result);
+
+    IPage<DiscountCardRecordWrapper.DiscountCardRecord> selectPage(IPage<DiscountCardRecordWrapper.DiscountCardRecord> page, DiscountCardRecordWrapper.DiscountCardRecordQuery query);
+
+    /**
+     * 获取剩余时长
+     *
+     */
+    DiscountCardRecordWrapper.Info info(DiscountCardRecordWrapper.InfoQuery infoQuery);
+
+    /**
+     * 扣减畅学卡
+     *
+     */
+    void deduction(DiscountCardRecordWrapper.DeductionDiscountCardRecord result);
+
     void pollExpireMsg();
 }

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

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

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

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

+ 29 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TeacherIndexWrapper.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.wrapper;
 
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -53,6 +54,9 @@ public class TeacherIndexWrapper {
 
         @ApiModelProperty("排序方式 ,ASC升序,DESC降序")
         private String sortType;
+
+        @ApiModelProperty("查询条数")
+        private Integer limit = 10;
     }
 
     @Data
@@ -69,9 +73,6 @@ public class TeacherIndexWrapper {
 
         @ApiModelProperty("练习人数")
         private List<PracticeTimeDto> practiceCounts;
-
-        @ApiModelProperty("学员练习统计")
-        private List<StudentPracticeSummaryDto> studentPracticeSummary;
     }
 
     @Data
@@ -111,6 +112,9 @@ public class TeacherIndexWrapper {
         @ApiModelProperty("学员姓名")
         private String studentName;
 
+        @ApiModelProperty("学员头像")
+        private String avatar;
+
         @ApiModelProperty("乐器")
         private String subjectName;
 
@@ -127,6 +131,28 @@ public class TeacherIndexWrapper {
     @Data
     @Builder
     @NoArgsConstructor
+    @AllArgsConstructor
+    public static class StudentPracticeSummaryExportDto{
+
+        @ExcelProperty(value = "学员姓名",index = 0)
+        private String studentName;
+
+        @ExcelProperty(value = "乐器",index = 1)
+        private String subjectName;
+
+        @ExcelProperty(value = "练习总时长",index = 2)
+        private Long totalPracticeTime;
+
+        @ExcelProperty(value = "练习天数",index = 3)
+        private Integer practiceDays;
+
+        @ExcelProperty(value = "平均练习时长",index = 4)
+        private Long averagePracticeTime;
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
     public static class CourseExposureTotal{
 
         @ApiModelProperty("日期")

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

@@ -49,4 +49,65 @@
             and t.user_id_ = #{userId}
         </if>
     </select>
+
+    <select id="selectPage"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.DiscountCardRecordWrapper$DiscountCardRecord">
+        select t.id_,
+               t.user_id_,
+               t.order_no_,
+               t.source_type_,
+               t.client_type_,
+               t.create_time_,
+                if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) as operatorId,
+               t.type_,
+               t.times_,
+                if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) as reason,
+               t.deduction_time_,
+               t.deduction_status_
+        from discount_card_record t
+
+        <if test="param.keyword != null and param.keyword != ''">
+            left join sys_user t1
+                      on if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) = t1.id_
+        </if>
+        <where>
+            t.display_flag_ = 1
+            <if test="param.userId != null">
+                and t.user_id_ = #{param.userId}
+                and t.client_type_ = 'STUDENT'
+            </if>
+            <if test="param.sourceType != null">
+                and t.source_type_ = #{param.sourceType}
+            </if>
+            <if test="param.deductionStatus != null">
+                and t.deduction_status_ = #{param.deductionStatus}
+            </if>
+            <if test="param.keyword != null and param.keyword != ''">
+                and (t1.username_ like CONCAT('%', #{param.keyword}, '%')
+                    or
+                     if(t.source_type_ = 'ORDER' and t.order_no_ is not null, t.order_no_, '') like
+                     CONCAT('%', #{param.keyword}, '%')
+                    or if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) like
+                       CONCAT('%', #{param.keyword}, '%')
+                    )
+            </if>
+            <if test="param.startTime != null">
+                and t.create_time_ &gt;= #{param.startTime}
+            </if>
+            <if test="param.endTime != null">
+                and t.create_time_ &lt;= #{param.endTime}
+            </if>
+            <if test="param.deductionStartTime != null">
+                and t.deduction_time_ &gt;= #{param.deductionStartTime}
+            </if>
+            <if test="param.deductionEndTime != null">
+                and t.deduction_time_ &lt;= #{param.deductionEndTime}
+            </if>
+        </where>
+        order by t.id_ desc
+    </select>
+
+    <update id="updateUserDiscountTime">
+        update student t set t.discount_end_time_ = #{endTime},t.discount_start_time_ = ifnull(t.discount_start_time_,#{startTime}) where t.user_id_ = #{userId}
+    </update>
 </mapper>

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

@@ -635,7 +635,7 @@
 	</select>
 	<select id="getStudentTrainOverViewList"
 			resultType="com.yonge.cooleshow.biz.dal.wrapper.TeacherIndexWrapper$StudentPracticeSummaryDto">
-		select su.username_ studentName,sb.name_ subjectName,SUM(smcr.play_time_) totalPracticeTime,
+		select su.username_ studentName,su.avatar_ avatar,sb.name_ subjectName,SUM(smcr.play_time_) totalPracticeTime,
 		       COUNT(DISTINCT DATE_FORMAT(smcr.create_time_, '%Y-%m-%d')) practiceDays,
 		       SUM(smcr.play_time_) / COUNT(DISTINCT DATE_FORMAT(smcr.create_time_, '%Y-%m-%d')) averagePracticeTime
 		from sys_music_compare_record smcr
@@ -656,7 +656,7 @@
 		<if test="param.sortField == null or param.sortField == ''">
 			ORDER BY totalPracticeTime DESC
 		</if>
-		LIMIT 10
+		LIMIT ${param.limit}
 	</select>
 	<!--曲目练习统计-->
 

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

@@ -1584,4 +1584,17 @@ public class DateUtil {
 //				DateUtil.parse("2022-01-05",DEFAULT_PATTERN),
 //				DateUtil.parse("2022-02-04",DEFAULT_PATTERN)));
 	}
+
+
+	public static int daysBetweenUp(Date date, Date maxTime) {
+		long epochSecond = date.toInstant().getEpochSecond();
+		long epochSecond1 = maxTime.toInstant().getEpochSecond();
+		long i = (epochSecond1 - epochSecond)/(24*60*60)  ;
+		long j = (epochSecond1 - epochSecond)%(24*60*60)  ;
+		if (j >0) {
+			i++;
+		}
+		return (int)i;
+	}
+
 }