Explorar el Código

Merge remote-tracking branch 'origin/feature/1219_opt' into feature/1219_opt

zouxuan hace 6 meses
padre
commit
9bd17921d4

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

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

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

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

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

@@ -53,11 +53,11 @@ public class DiscountCardRecord implements Serializable {
 
 
     @ApiModelProperty("预计开始时间")
-    @TableField(value = "estimated_end_time_")
+    @TableField(value = "estimated_start_time_")
     private Date estimatedStartTime;
 
     @ApiModelProperty("预计结束时间")
-    @TableField(value = "estimated_start_time_")
+    @TableField(value = "estimated_end_time_")
     private Date estimatedEndTime;
 
 

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

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

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

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EDeductionStatus;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import lombok.Data;
 
@@ -57,6 +58,16 @@ public class UserTenantAlbumRecord implements Serializable {
 	@TableField(value = "sub_order_no_")
     private String subOrderNo;
 
+
+
+    @ApiModelProperty("预计开始时间")
+    @TableField(value = "estimated_start_time_")
+    private Date estimatedStartTime;
+
+    @ApiModelProperty("预计结束时间")
+    @TableField(value = "estimated_end_time_")
+    private Date estimatedEndTime;
+
     @ApiModelProperty("开始时间") 
 	@TableField(value = "start_time_")
     private Date startTime;
@@ -93,4 +104,24 @@ public class UserTenantAlbumRecord implements Serializable {
 	@TableField(value = "reason_")
     private String reason;
 
+    @ApiModelProperty("是否有效 1:有效,0:失效")
+    @TableField(value = "efficient_flag_")
+    private Boolean efficientFlag;
+
+    @ApiModelProperty("扣减状态")
+    @TableField(value = "deduction_status_")
+    private EDeductionStatus deductionStatus;
+
+    @ApiModelProperty("扣减时间")
+    @TableField(value = "deduction_time_")
+    private Date deductionTime;
+
+    @ApiModelProperty("扣减原因")
+    @TableField(value = "deduction_reason_")
+    private String deductionReason;
+
+    @ApiModelProperty("扣减操作人")
+    @TableField(value = "deduction_by_")
+    private Long deductionBy;
+
 }

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

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

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

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

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

@@ -2,8 +2,6 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.microsvc.toolkit.common.response.ParamResponse;
-import com.yonge.cooleshow.biz.dal.entity.TenantAlbum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper;
@@ -39,7 +37,7 @@ public interface UserTenantAlbumRecordService extends IService<UserTenantAlbumRe
      * @param userTenantAlbumRecord UserTenantAlbumRecordWrapper.UserTenantAlbumRecord
      * @return Boolean
      */
-     Boolean add(UserTenantAlbumRecord userTenantAlbumRecord);
+     Boolean add(UserTenantAlbumRecord userTenantAlbumRecord,boolean sendMsg);
 
     /**
      * 更新
@@ -86,4 +84,15 @@ public interface UserTenantAlbumRecordService extends IService<UserTenantAlbumRe
     UserTenantAlbumRecord getNewestByTenantAlbumId(Long tenantAlbumId, Long userId, ClientEnum client);
 
     List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> list(UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query);
+
+    /**
+     * 扣除用户专辑记录
+     *
+     * @return
+     */
+    void deduction(UserTenantAlbumRecordWrapper.DeductionUserTenantAlbumRecord result);
+
+    IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> selectAdminPage(IPage<UserTenantAlbumRecordWrapper.AdminUserTenantAlbumRecord> page, UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery query);
+
+    List<UserTenantAlbumRecordWrapper.Info> info(UserTenantAlbumRecordWrapper.InfoQuery infoQuery);
 }

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

@@ -65,6 +65,7 @@ public class DiscountCardRecordServiceImpl extends ServiceImpl<DiscountCardRecor
         discountCardRecord.setClientType(orderDetailVo.getOrderClient());
         discountCardRecord.setSubOrderNo(orderDetailVo.getSubOrderNo());
         discountCardRecord.setType(detail.getPeriod());
+        discountCardRecord.setCreateBy(orderDetailVo.getUserId());
         discountCardRecord.setTimes(orderDetailVo.getGoodNum());
         discountCardRecord.setStatus(EVipRecordStatus.ADD);
 
@@ -207,8 +208,8 @@ public class DiscountCardRecordServiceImpl extends ServiceImpl<DiscountCardRecor
 
         discountCardRecord.setEndTime(addTime(discountCardRecord.getStartTime(), discountCardRecord.getType(), discountCardRecord.getTimes(),1));
         formatVipRecordTime(discountCardRecord);
-        discountCardRecord.setEstimatedEndTime(discountCardRecord.getStartTime());
-        discountCardRecord.setEstimatedStartTime(discountCardRecord.getEndTime());
+        discountCardRecord.setEstimatedEndTime(discountCardRecord.getEndTime());
+        discountCardRecord.setEstimatedStartTime(discountCardRecord.getStartTime());
         this.save(discountCardRecord);
 
         updateUserTime(discountCardRecord.getUserId(),discountCardRecord.getClientType());
@@ -278,6 +279,7 @@ public class DiscountCardRecordServiceImpl extends ServiceImpl<DiscountCardRecor
      *
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void deduction(DiscountCardRecordWrapper.DeductionDiscountCardRecord result) {
         // 判断是否是生效中
 

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

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

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

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

+ 66 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserTenantAlbumRecordMapper.xml

@@ -159,4 +159,70 @@
         group by t.tenant_album_id_
 
     </select>
+
+    <select id="selectAdminPage"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper$AdminUserTenantAlbumRecord">
+        SELECT t.id_,
+               t.user_id_,
+               t.tenant_album_id_,
+               t.order_no_,
+               t.source_type_,
+               t.client_type_,
+               t.start_time_,
+               t.end_time_,
+               t.create_time_,
+                if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) as operatorId,
+               t.type_,
+               t.times_,
+                if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) as reason,
+               t.deduction_time_,
+               t.deduction_status_
+        from user_tenant_album_record t
+
+        <if test="param.keyword != null and param.keyword != ''">
+            left join sys_user t1
+                      on if(t.deduction_by_ is not null, t.deduction_by_, t.create_by_) = t1.id_
+            left join tenant_album t2 on t.tenant_album_id_ = t2.id_
+        </if>
+        <where>
+            <if test="param.keyword != null and param.keyword != ''">
+                and (
+                if(t.source_type_ = 'ORDER' and t.order_no_ is not null, t.order_no_, '') like
+                CONCAT('%', #{param.keyword}, '%')
+                    or if(t.deduction_reason_ is not null, t.deduction_reason_, t.reason_) like
+                       CONCAT('%', #{param.keyword}, '%')
+                    or t1.username_ like CONCAT('%', #{param.keyword}, '%')
+                    or t2.name_ like CONCAT('%', #{param.keyword}, '%')
+                )
+            </if>
+            <if test="param.userId != null">
+                AND t.user_id_ = #{param.userId}
+            </if>
+            <if test="param.startTime != null">
+                AND t.create_time_ >= #{param.startTime}
+            </if>
+            <if test="param.endTime != null">
+                AND t.create_time_ &lt; #{param.endTime}
+            </if>
+            <if test="param.sourceType != null">
+                AND t.source_type_ = #{param.sourceType}
+            </if>
+            <if test="param.tenantId != null">
+                AND t.tenant_id_ = #{param.tenantId}
+            </if>
+            <if test="param.tenantGroupId != null">
+                AND t.tenant_album_id_ = #{param.tenantGroupId}
+            </if>
+            <if test="param.deductionStatus != null">
+                AND t.deduction_status_ = #{param.deductionStatus}
+            </if>
+            <if test="param.deductionStartTime != null">
+                AND t.deduction_time_ >= #{param.deductionStartTime}
+            </if>
+            <if test="param.deductionEndTime != null">
+                AND t.deduction_time_ &lt; #{param.deductionEndTime}
+            </if>
+        </where>
+        order by id_ desc
+    </select>
 </mapper>