Browse Source

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

刘俊驰 7 months ago
parent
commit
eb6956fe7a
17 changed files with 328 additions and 84 deletions
  1. 26 9
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/CourseHomeworkController.java
  2. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseHomeworkDao.java
  3. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/UserOrderDetailDao.java
  4. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseGroupService.java
  5. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseHomeworkService.java
  6. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserOrderService.java
  7. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserPaymentCoreService.java
  8. 90 46
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java
  9. 8 7
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseHomeworkServiceImpl.java
  10. 23 11
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java
  11. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentDivMemberRecordServiceImpl.java
  12. 51 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java
  13. 64 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/HomeworkWrapper.java
  14. 6 6
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseGroupMapper.xml
  15. 20 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseHomeworkMapper.xml
  16. 6 3
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleMapper.xml
  17. 8 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderDetailMapper.xml

+ 26 - 9
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/CourseHomeworkController.java

@@ -1,11 +1,14 @@
 package com.yonge.cooleshow.admin.controller;
 
 import com.yonge.cooleshow.biz.dal.dto.search.HomeworkAdminSearch;
+import com.yonge.cooleshow.biz.dal.entity.StudentCourseHomework;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.service.CourseHomeworkService;
 import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
+import com.yonge.cooleshow.biz.dal.service.StudentCourseHomeworkService;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo;
+import com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -14,15 +17,10 @@ import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.ArrayList;
 import java.util.List;
@@ -32,12 +30,15 @@ import java.util.List;
 @Api(value = "课程作业表", tags = "课程作业表")
 public class CourseHomeworkController extends BaseController {
 
-    @Autowired
+    @Resource
     private CourseHomeworkService courseHomeworkService;
 
-	@Autowired
+	@Resource
 	private CourseScheduleService courseScheduleService;
 
+	@Resource
+	private StudentCourseHomeworkService studentCourseHomeworkService;
+
 	@ApiOperation(value = "课后作业-列表", httpMethod = "POST", consumes = "application/json", produces = "application/json")
 	@PostMapping(value = "/list", consumes = "application/json", produces = "application/json")
 	@PreAuthorize("@pcs.hasPermissions('homework/list')")
@@ -71,4 +72,20 @@ public class CourseHomeworkController extends BaseController {
 		courseScheduleService.sendTodayNotRepliedAndNotDecorateHomework();
 		return HttpResponseResult.succeed();
 	}
+
+	//课程组关联的作业列表
+	@ApiOperation(value = "课程组关联的作业列表", httpMethod = "POST", consumes = "application/json", produces = "application/json")
+	@PostMapping(value = "/groupList", consumes = "application/json", produces = "application/json")
+	@PreAuthorize("@pcs.hasPermissions('homework/groupList')")
+	public HttpResponseResult<List<HomeworkWrapper.GroupHomework>> groupList(@RequestBody HomeworkWrapper.GroupHomeworkSearch query) {
+		return succeed(courseHomeworkService.groupList(query));
+	}
+
+	//根据作业编号,获取学员作业列表
+	@ApiOperation(value = "根据作业编号,获取学员作业列表")
+	@GetMapping(value = "/studentList")
+	@PreAuthorize("@pcs.hasPermissions('homework/studentList')")
+	public HttpResponseResult<List<StudentCourseHomework>> studentList(Long homeworkId) {
+		return succeed(studentCourseHomeworkService.lambdaQuery().eq(StudentCourseHomework::getCourseHomeworkId, homeworkId).list());
+	}
 }

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

@@ -9,6 +9,7 @@ import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseScheduleHomeworkVo;
 import com.yonge.cooleshow.biz.dal.vo.StudentHomeworkVo;
+import com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -120,4 +121,8 @@ public interface CourseHomeworkDao extends BaseMapper<CourseHomework> {
 	 * @return
 	 */
 	List<CourseHomeworkVo> selectAbsenteeism(@Param("practiceRecord") List<Long> practiceRecord, @Param("studentId") Long studentId);
+
+    List<HomeworkWrapper.GroupHomework> selectGroupHomeworkList(@Param("param") HomeworkWrapper.GroupHomeworkSearch query);
+
+	void updateSubmitNum(@Param("homeworkId") Long homeworkId);
 }

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/UserOrderDetailDao.java

@@ -56,4 +56,6 @@ public interface UserOrderDetailDao extends BaseMapper<UserOrderDetail>{
 
 	List<TeacherIndexWrapper.CourseExposureTotal> musicSheetBuyTotal(@Param("param") TeacherIndexWrapper.CourseExposureSearch search,
 																	 @Param("groupBy") String groupBy);
+
+	List<String> getPayingCourseGroupOrder(@Param("groupId") Long groupId);
 }

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

@@ -274,6 +274,8 @@ public interface CourseGroupService extends IService<CourseGroup> {
     @Transactional
     void closeCourseGroup(CourseGroup courseGroup);
 
+    void groupSuccess(CourseGroup courseGroup);
+
     /**
      * 课程组管理-琴房课
      *

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

@@ -12,6 +12,9 @@ import com.yonge.cooleshow.biz.dal.entity.CourseHomework;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseScheduleHomeworkVo;
+import com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper;
+
+import java.util.List;
 
 /**
  * 课程作业表 服务类
@@ -82,4 +85,6 @@ public interface CourseHomeworkService extends IService<CourseHomework>  {
 	 * @return
 	 */
 	CourseScheduleHomeworkVo getCourseHomeworkDetailByCourseId(CourseScheduleHomeworkSearch query);
+
+    List<HomeworkWrapper.GroupHomework> groupList(HomeworkWrapper.GroupHomeworkSearch query);
 }

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

@@ -252,4 +252,5 @@ public interface UserOrderService extends IService<UserOrder> {
     void discountCard(UserPaymentOrderWrapper.OrderGoodsInfo orderGoodsInfo);
 
     void updateOrderBizId(String subOrderNo, Long groupId);
+
 }

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

@@ -114,4 +114,11 @@ public interface UserPaymentCoreService {
     void paymentStatus(String orderNo);
 
     void scanRefundOrderRecord();
+
+    /**
+     * 关闭课程组订单未支付成功的订单
+     *
+     * @param groupId 课程组id
+     */
+    void closeCourseGroupOrder(Long groupId);
 }

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

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
+import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.constant.CourseConstant;
 import com.yonge.cooleshow.biz.dal.dao.CourseGroupDao;
@@ -36,6 +37,7 @@ import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.base.string.MessageFormatter;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import com.yonge.toolset.payment.core.util.SpringBeansUtil;
+import com.yonge.toolset.payment.util.DistributedLock;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.date.DateUtil;
 import org.apache.commons.collections.CollectionUtils;
@@ -121,6 +123,10 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
     @Autowired
     private StudentService studentService;
 
+
+    @Autowired
+    private RedisCacheService redisCacheService;
+
     @Override
     public CourseGroupDao getDao() {
         return this.baseMapper;
@@ -168,6 +174,7 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
         result.setSalesStartDate(group.getSalesStartDate());
         result.setSalesEndDate(group.getSalesEndDate());
         result.setMixStudentNum(group.getMixStudentNum());
+        result.setMaxStudentNum(group.getMaxStudentNum());
         result.setImGroupId(group.getImGroupId());
         result.setAuditVersion(group.getAuditVersion());
         SysUser teacherUser = sysUserService.getByUserId(group.getTeacherId());
@@ -1539,34 +1546,20 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
     @Override
     public void closeCourseGroup(CourseGroup courseGroup) {
         try {
+            // 关闭未支付的订单
+            userPaymentCoreService.closeCourseGroupOrder(courseGroup.getId());
+
+
             List<CourseScheduleStudentPayment> list = courseScheduleStudentPaymentService.list(Wrappers.<CourseScheduleStudentPayment>lambdaQuery()
-                                       .eq(CourseScheduleStudentPayment::getCourseGroupId, courseGroup.getId()));
+                    .eq(CourseScheduleStudentPayment::getCourseGroupId, courseGroup.getId()));
             Set<Long> userIds = list.stream().map(CourseScheduleStudentPayment::getUserId).collect(Collectors.toSet());
             if (courseGroup.getPreStudentNum() >= courseGroup.getMixStudentNum() && courseGroup.getStatus().equals(CourseGroupEnum.APPLY.getCode())) {
-                //人数达标则修改课程组为进行中状态
-                courseGroup.setStatus(CourseGroupEnum.ING.getCode());
-                List<Long> noGroupJoinUserIds = Lists.newArrayList();
-                //创建群聊 并添加人员到群中
-                String imGroupId = imGroupService.autoCreate(courseGroup.getId(), courseGroup.getType(), noGroupJoinUserIds);
-
-                // 排除未进群的学生
-                if (CollectionUtils.isNotEmpty(noGroupJoinUserIds)) {
-                    noGroupJoinUserIds.forEach(userIds::remove);
-                }
-                // 更新已进群用户身份
-                imGroupMemberService.initGroupMembers(imGroupId, userIds, ImGroupMemberRoleType.STUDENT);
-                //添加老师进群
-                imGroupMemberService.initGroupMembers(imGroupId, Collections.singleton(courseGroup.getTeacherId()), ImGroupMemberRoleType.TEACHER);
-                courseGroup.setImGroupId(imGroupId);
-
-                // 小组课成课推送
-                if (courseGroup.getType().equals(CourseScheduleEnum.GROUP.getCode())) {
-                    // 极光-消息推送-老师端-通知老师小组课程组成课
-                    sendGroupSuccessMessage(courseGroup,true);
-                }
+                groupSuccess(courseGroup);
             } else {
                 //人数未达标则修改课程组为取消状态
                 courseGroup.setStatus(CourseGroupEnum.CANCEL.getCode());
+                courseGroup.setPreStudentNum(0);
+                courseGroup.setLockNum(0);
                 //更新课程组下课程状态为取消
                 courseScheduleService.update(Wrappers.<CourseSchedule>lambdaUpdate()
                         .eq(CourseSchedule::getCourseGroupId, courseGroup.getId())
@@ -1589,9 +1582,9 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
                     this.sendStudentMessage(userIds, courseGroup);
                 }
 
+                courseGroup.setUpdatedTime(new Date());
+                this.updateById(courseGroup);
             }
-            courseGroup.setUpdatedTime(new Date());
-            this.updateById(courseGroup);
         } catch (Exception e) {
             log.error("closeCourseGroup error >>> courseGroup: {} ", JSON.toJSONString(courseGroup));
             log.error("closeCourseGroup error >>> ", e);
@@ -1599,6 +1592,45 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
         }
     }
 
+    @Transactional
+    @Override
+    public void groupSuccess(CourseGroup courseGroup){
+
+
+        List<CourseScheduleStudentPayment> list = courseScheduleStudentPaymentService.list(Wrappers.<CourseScheduleStudentPayment>lambdaQuery()
+                .eq(CourseScheduleStudentPayment::getCourseGroupId, courseGroup.getId()));
+        Set<Long> userIds = list.stream().map(CourseScheduleStudentPayment::getUserId).collect(Collectors.toSet());
+
+        //人数达标则修改课程组为进行中状态
+        courseGroup.setStatus(CourseGroupEnum.ING.getCode());
+        List<Long> noGroupJoinUserIds = Lists.newArrayList();
+        //创建群聊 并添加人员到群中
+        String imGroupId = null;
+        try {
+            imGroupId = imGroupService.autoCreate(courseGroup.getId(), courseGroup.getType(), noGroupJoinUserIds);
+        } catch (Exception e) {
+            log.error("创建群聊失败,{}", JSON.toJSONString(courseGroup),e);
+        }
+
+        // 排除未进群的学生
+        if (CollectionUtils.isNotEmpty(noGroupJoinUserIds)) {
+            noGroupJoinUserIds.forEach(userIds::remove);
+        }
+        // 更新已进群用户身份
+        imGroupMemberService.initGroupMembers(imGroupId, userIds, ImGroupMemberRoleType.STUDENT);
+        //添加老师进群
+        imGroupMemberService.initGroupMembers(imGroupId, Collections.singleton(courseGroup.getTeacherId()), ImGroupMemberRoleType.TEACHER);
+        courseGroup.setImGroupId(imGroupId);
+
+        courseGroup.setUpdatedTime(new Date());
+        this.updateById(courseGroup);
+        // 小组课成课推送
+        if (courseGroup.getType().equals(CourseScheduleEnum.GROUP.getCode())) {
+            // 极光-消息推送-老师端-通知老师小组课程组成课
+            sendGroupSuccessMessage(courseGroup,true);
+        }
+    }
+
     private void sendGroupSuccessMessage(CourseGroup courseGroup,boolean success) {
         // 老师
         SysUser sysUser = sysUserService.getByUserId(courseGroup.getTeacherId());
@@ -1671,32 +1703,44 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
         Collection<UserOrder> userOrders = mapByOrderNos.values();
 
         for (UserOrder order : userOrders) {
-            try {
 
-                // 直播课成课失败退款,只退课程费用,不退畅学卡
-                UserOrderVo detail = userOrderService.detail(order.getId());
+            // 任务执行锁
+            String lockName = redisCacheService.getPaymentCacheKey(order.getOrderNo());
+            DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
 
-                List<Long> orderDetailIds = new ArrayList<>();
-                if (CollectionUtils.isNotEmpty(detail.getOrderDetailList())) {
-                    detail.getOrderDetailList().stream()
-                            .filter(orderDetail -> orderDetail.getGoodType() == GoodTypeEnum.LIVE || orderDetail.getGoodType() == GoodTypeEnum.GROUP)
-                            .filter(orderDetail -> orderDetail.getBizId().equals(courseGroup.getId()))
-                            .forEach(orderDetail -> orderDetailIds.add(orderDetail.getId()));
-                }
-                if (order.getPaymentVersion().equals(EPaymentVersion.V1)) {
-                    userOrderRefundService.orderRefund(order.getOrderNo(), CourseScheduleEnum.valueOf(courseGroup.getType()).getMsg() +"成课失败退款");
-                } else {
-                    userPaymentCoreService.refundPayment(order.getOrderNo(),CourseScheduleEnum.valueOf(courseGroup.getType()).getMsg() +"成课失败退款", orderDetailIds);
-                }
+                try {
+                    if (order.getStatus() == OrderStatusEnum.WAIT_PAY || order.getStatus() == OrderStatusEnum.PAYING) {
+                        // 取消订单
+                        userPaymentCoreService.cancelPayment(JwtUserInfo.builder().userId(order.getUserId().toString()).clientType(ClientEnum.STUDENT.getCode()).build(),order.getOrderNo());
+                    } else if (order.getStatus() == OrderStatusEnum.PAID) {
+
+                        // 直播课成课失败退款,只退课程费用,不退畅学卡
+                        UserOrderVo detail = userOrderService.detail(order.getId());
+
+                        List<Long> orderDetailIds = new ArrayList<>();
+                        if (CollectionUtils.isNotEmpty(detail.getOrderDetailList())) {
+                            detail.getOrderDetailList().stream()
+                                    .filter(orderDetail -> orderDetail.getGoodType() == GoodTypeEnum.LIVE || orderDetail.getGoodType() == GoodTypeEnum.GROUP)
+                                    .filter(orderDetail -> orderDetail.getBizId().equals(courseGroup.getId()))
+                                    .forEach(orderDetail -> orderDetailIds.add(orderDetail.getId()));
+                        }
+                        if (order.getPaymentVersion().equals(EPaymentVersion.V1)) {
+                            userOrderRefundService.orderRefund(order.getOrderNo(), CourseScheduleEnum.valueOf(courseGroup.getType()).getMsg() + "成课失败退款");
+                        } else {
+                            userPaymentCoreService.refundPayment(order.getOrderNo(), CourseScheduleEnum.valueOf(courseGroup.getType()).getMsg() + "成课失败退款", orderDetailIds);
+                        }
 
-                //退还优惠券
-                if (orderDetailIds.size() == detail.getOrderDetailList().size()) {
-                    couponInfoService.updateUserOrderCouponInfo(CouponOrderWrapper.builder().orderNo(order.getOrderNo()).reset(true).build());
+                        //退还优惠券
+                        if (orderDetailIds.size() == detail.getOrderDetailList().size()) {
+                            couponInfoService.updateUserOrderCouponInfo(CouponOrderWrapper.builder().orderNo(order.getOrderNo()).reset(true).build());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.warn("成课失败退款 退款失败,退款订单号 {}", order);
+                    log.error("成课失败退款 退款失败", e);
                 }
-            } catch (Exception e) {
-                log.warn("成课失败退款 退款失败,退款订单号 {}", order);
-                log.error("成课失败退款 退款失败", e);
-            }
+
+            }, 10L, TimeUnit.SECONDS);
         }
     }
 

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

@@ -25,6 +25,7 @@ import com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo;
 import com.yonge.cooleshow.biz.dal.vo.CourseScheduleHomeworkVo;
 import com.yonge.cooleshow.biz.dal.vo.StudentHomeworkVo;
 import com.yonge.cooleshow.biz.dal.wordfilter.WordFilter;
+import com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
@@ -401,13 +402,8 @@ public class CourseHomeworkServiceImpl extends ServiceImpl<CourseHomeworkDao, Co
         boolean submitCourseHome = studentCourseHomeworkService
                 .submitCourseHome(courseHomeworkDetailVo, submitDto.getSubmit(),submitDto.getStudentId());
         if (submitCourseHome) {
-            CourseHomework courseHomework = this.getById(courseHomeworkDetailVo.getId());
-            if (courseHomework.getCompletedNum() == null) {
-                courseHomework.setCompletedNum(0);
-            }
-            courseHomework.setCompletedNum(courseHomework.getCompletedNum() + 1);
-            this.updateById(courseHomework);
-
+            // 更新作业提交人数
+            this.getBaseMapper().updateSubmitNum(courseHomeworkDetailVo.getId());
             try {
                 sendSubmitMessage(submitDto, courseHomeworkDetailVo);
             }catch (Exception e) {
@@ -481,6 +477,11 @@ public class CourseHomeworkServiceImpl extends ServiceImpl<CourseHomeworkDao, Co
 
     }
 
+    @Override
+    public List<HomeworkWrapper.GroupHomework> groupList(HomeworkWrapper.GroupHomeworkSearch query) {
+        return baseMapper.selectGroupHomeworkList(query);
+    }
+
     /**
      * 检查课程能否布置作业
      *

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

@@ -1154,6 +1154,18 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
     }
 
     /**
+     * 批量检查学生课时在数据库是否重复
+     *
+     * @param studentIds 老师id
+     * @param timeList  时间集合
+     */
+    private <T> void batchCheckStudentCourseTime(List<Long> studentIds, List<T> timeList, Function<T, Date> startTimeFun, Function<T, Date> endTimeFun) {
+        for (Long studentId : studentIds) {
+            batchCheckStudentCourseTime(studentId, timeList, startTimeFun, endTimeFun);
+        }
+    }
+
+    /**
      * @Description: 趣纠课购买记录
      * @Author: cy
      * @Date: 2022/5/16
@@ -1459,9 +1471,8 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         }
 
         //查询是否有人购买
-        CourseScheduleStudentPayment studentPayment = paymentDao.selectOne(Wrappers.<CourseScheduleStudentPayment>lambdaQuery()
-                .eq(CourseScheduleStudentPayment::getCourseId, courseId));
-        if (ObjectUtil.isEmpty(studentPayment)) {
+        List<CourseScheduleStudentPayment> studentPayments = paymentDao.queryByCourseId(courseId.longValue());
+        if (CollectionUtils.isEmpty(studentPayments)) {
             throw new BizException("课程无人购买");
         }
 
@@ -1487,21 +1498,21 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         //校验老师课程是否冲突
         this.batchCheckTeacherCourseTime(teacherId, timeList, CourseTimeEntity::getStartTime, CourseTimeEntity::getFreeEndTime);
         //校验学生课程是否冲突
-        this.batchCheckStudentCourseTime(studentPayment.getUserId(), timeList, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime);
-
+        List<Long> studentIds = studentPayments.stream().map(CourseScheduleStudentPayment::getUserId).collect(Collectors.toList());
+        this.batchCheckStudentCourseTime(studentIds, timeList, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime);
         baseMapper.courseAdjust(adjustVo);
-
         // 课程调整后给学生发消息
-        sendCourseAdjustMessage(teacherId,studentPayment.getUserId(),adjustVo.getCourseId(),adjustVo.getStartTime(),oldStartTime);
+        sendCourseAdjustMessage(teacherId,studentIds,adjustVo.getCourseId(),adjustVo.getStartTime(),oldStartTime);
     }
 
+
     //{老师昵称}已将{课程类型趣纠课、琴房课}{课程名称}课调整到{上课时间yyyy-MM-dd HH:mm:ss},请注意查看
-    private void sendCourseAdjustMessage(Long teacherId,Long studentId,Integer courseScheduleId,Date date,Date oldStartTime) {
+    private void sendCourseAdjustMessage(Long teacherId,List<Long> studentIds,Integer courseScheduleId,Date date,Date oldStartTime) {
         //  趣纠课调整模板
         try {
             //  发送消息
             SysUser teacher = sysUserService.getByUserId(teacherId);
-            SysUser student = sysUserService.getByUserId(studentId);
+            List<com.yonge.cooleshow.biz.dal.entity.SysUser> sysUsers = sysUserService.getDao().selectBatchIds(studentIds);
 
             CourseSchedule courseSchedule = this.getById(courseScheduleId);
             CourseGroup courseGroup = courseGroupService.getById(courseSchedule.getCourseGroupId());
@@ -1517,8 +1528,8 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
             }else if(CourseTypeEnum.valueOf(courseGroup.getType()) == CourseTypeEnum.GROUP){
                 messageType = MessageTypeEnum.GROUP_ADJUST;
             }
-            Map<Long, String> receivers = new HashMap<>();
-            receivers.put(studentId, student.getPhone());
+            Map<Long, String> receivers = sysUsers.stream()
+                    .collect(Collectors.toMap(com.yonge.cooleshow.biz.dal.entity.SysUser::getId, com.yonge.cooleshow.biz.dal.entity.SysUser::getPhone));
 //            String url = sysMessageService.selectConfigUrl(MessageTypeEnum.PRACTICE_ADJUST.getCode(),courseSchedule.getId());
             sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                     messageType,
@@ -2871,6 +2882,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         //获取所有学生列表
         List<CourseScheduleStudentPayment> studentPayments = courseScheduleStudentPaymentService.lambdaQuery()
                 .in(CourseScheduleStudentPayment::getCourseId, courseScheduleIds)
+                .orderByDesc(CourseScheduleStudentPayment::getId)
                 .list();
         if (CollectionUtils.isEmpty(studentPayments)) {
             return Lists.newArrayList();

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

@@ -640,6 +640,10 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
 
             saveData(userPaymentOrder, tenantdivMap, teacherMap, bizMap, serviceFeeAmount);
         }
+        CourseGroup group = courseGroupService.getById(courseGroup.getId());
+        if (group.getType().equals(CourseScheduleEnum.GROUP.name()) && Objects.equals(group.getMaxStudentNum(), group.getPreStudentNum()) &&group.getStatus().equals(CourseGroupEnum.APPLY.getCode())) {
+            courseGroupService.groupSuccess(group);
+        }
         log.info("buyLiveCourseSuccess ok");
         //课程购买成功后进行消息推送
 

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

@@ -412,6 +412,7 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         }
     }
 
+
     /**
      * 取消订单支付
      *
@@ -421,6 +422,15 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
     @Transactional
     @Override
     public void cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentResp paymentResp) {
+        cancelPayment(paymentOrder, paymentResp, false);
+    }
+    /**
+     * 取消订单支付
+     *
+     * @param paymentOrder UserPaymentOrderWrapper.UserPaymentOrder
+     * @param paymentResp  PaymentResp
+     */
+    private void cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentResp paymentResp,boolean closeFlag) {
 
         // 同步三方订单支付状态
         String lockName = redisCacheService.getPaymentCacheKey(paymentOrder.getOrderNo());
@@ -478,6 +488,9 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
 
                                 // 更新订单退款异常信息
                                 userPaymentOrderService.updateById(order);
+                                if (closeFlag) {
+                                    closeWaitOrder(paymentOrder);
+                                }
 
                             });
                             throw new BizException("查询交易中,请耐心等待!");
@@ -1238,6 +1251,8 @@ DISCOUNT("畅学卡")
 
     }
 
+
+
     /**
      * 用户取消支付
      *
@@ -1247,6 +1262,16 @@ DISCOUNT("畅学卡")
     @Transactional
     @Override
     public void cancelPayment(JwtUserInfo<?> userInfo, String orderNo) {
+        cancelPayment(userInfo, orderNo, false);
+
+    }
+    /**
+     * 用户取消支付
+     *
+     * @param userInfo JwtUserInfo
+     * @param orderNo  订单编号
+     */
+    private void cancelPayment(JwtUserInfo<?> userInfo, String orderNo,boolean closeFlag) {
 
         // 查询订单信息,支付状态
         UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByUserId(Long.parseLong(userInfo.getUserId()), orderNo);
@@ -1289,7 +1314,7 @@ DISCOUNT("畅学卡")
                 UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(paymentOrder));
 
                 // 订单取消执行流程
-                cancelPayment(order, paymentResp);
+                cancelPayment(order, paymentResp,closeFlag);
             }
 
         }, 10L, TimeUnit.SECONDS);
@@ -1379,6 +1404,7 @@ DISCOUNT("畅学卡")
                 }
                 break;
             }
+            case GROUP:
             case LIVE: {
                 CourseGroup courseGroup = courseGroupService.getById(payTypeReq.getBizId());
                 if (Objects.isNull(courseGroup)) {
@@ -1956,4 +1982,28 @@ DISCOUNT("畅学卡")
         }
 
     }
+
+    @Override
+    @Transactional
+    public void closeCourseGroupOrder(Long groupId) {
+        List<String> payingCourseGroupOrder = userOrderDetailDao.getPayingCourseGroupOrder(groupId);
+        if (CollectionUtils.isEmpty(payingCourseGroupOrder)) {
+            return;
+        }
+
+        for (String orderNo : payingCourseGroupOrder) {
+            // 任务执行锁
+            String lockName = redisCacheService.getPaymentCacheKey(orderNo);
+            DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
+
+                try {
+                    UserOrder userOrder = userOrderService.getByOrderNo(orderNo);
+                    this.cancelPayment(JwtUserInfo.builder().userId(userOrder.getUserId().toString()).clientType(ClientEnum.STUDENT.getCode()).build(), orderNo,true);
+                } catch (Exception e) {
+                    log.error("closeCourseGroupOrder orderNo={}", orderNo, e);
+                }
+            }, 10L, TimeUnit.SECONDS);
+        }
+
+    }
 }

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

@@ -0,0 +1,64 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
+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.lang3.StringUtils;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class HomeworkWrapper {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("课程组作业")
+    public static class GroupHomework implements Serializable {
+        @ApiModelProperty("作业编号")
+        private Long homeworkId;
+
+        @ApiModelProperty("课程编号")
+        private Long courseId;
+
+        @ApiModelProperty("课次")
+        private Integer classNum;
+
+        @ApiModelProperty("作业内容")
+        private String content;
+
+        @ApiModelProperty("总人数")
+        private Integer studentNum;
+
+        @ApiModelProperty("提交人数")
+        private Integer completedNum;
+
+        @ApiModelProperty("点评数")
+        private Integer repliedNum;
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("课程组作业")
+    public static class GroupHomeworkSearch implements Serializable {
+
+        @ApiModelProperty("作业内容/课程编号")
+        private String search;
+
+        @ApiModelProperty("课程组编号")
+        private Long courseGroupId;
+    }
+}

+ 6 - 6
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseGroupMapper.xml

@@ -343,10 +343,10 @@
         cssp.order_no_ as orderNo,
         sa.id_ as studentAttendanceId
         from course_schedule cs
-        left join course_schedule_student_payment cssp on cs.id_ = cssp.course_id_
-        left join student_attendance sa on cssp.course_id_ = sa.course_schedule_id_
+        left join course_schedule_student_payment cssp on cs.id_ = cssp.course_id_ and #{param.studentId} = cssp.user_id_
+        left join student_attendance sa on cs.id_ = sa.course_schedule_id_ and #{param.studentId} = sa.student_id_
         <where>
-            cs.status_ !=  '${@ com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum@CANCEL}'
+            cs.status_ !=  '${@com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum@CANCEL}'
             <if test="param.studentId != null">
                 and cssp.user_id_ = #{param.studentId}
             </if>
@@ -356,8 +356,7 @@
                         and sa.id_ is null AND cs.status_ IN ('ING','COMPLETE')
                     </when>
                     <when test="param.status == @com.yonge.cooleshow.biz.dal.enums.StudentCourseEnum@ATTENDCLASS">
-                        and sa.id_ is not null
-                        and #{param.studentId} = sa.student_id_
+                        and sa.id_ is not null and #{param.studentId} = sa.student_id_
                     </when>
                     <when test="param.status == @com.yonge.cooleshow.biz.dal.enums.StudentCourseEnum@NOTSTART">
                         and cs.status_ = '${@ com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum@NOT_START}'
@@ -1078,6 +1077,7 @@
                 AND cg.name_ LIKE concat('%',#{param.search},'%')
             </if>
         </where>
+        GROUP BY cg.id_ DESC
     </select>
     <select id="studentCourseGroup"
             resultType="com.yonge.cooleshow.biz.dal.wrapper.course.CourseGroupWrapper$StudentCourseGroupDto">
@@ -1118,7 +1118,7 @@
                 AND (cg.name_ LIKE concat('%',#{param.search},'%') OR su.username_ LIKE concat('%',#{param.search},'%'))
             </if>
         </where>
-        GROUP BY cg.id_
+        GROUP BY cg.id_ DESC
     </select>
 
     <update id="updateLockNum">

+ 20 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseHomeworkMapper.xml

@@ -29,6 +29,10 @@
         , t.create_time_
         , t.update_time_
         </sql>
+    <update id="updateSubmitNum">
+        update course_homework set completed_num_ =
+        (select COUNT(1) from student_course_homework where course_homework_id_ = #{homeworkId}) WHERE id_ = #{homeworkId}
+    </update>
 
     <select id="detail" resultType="com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo">
         SELECT
@@ -368,7 +372,6 @@
         else 'REVIEWED' end ) as homeworkStatus,
         (select group_concat(s2.name_) from subject s2
         where find_in_set(s2.id_,st.subject_id_) and s2.del_flag_ = 0 ) as subjectName
-
         from course_schedule_student_payment cssp
         left join sys_user s on cssp.user_id_ = s.id_
         left  join student st on st.user_id_ = s.id_
@@ -378,6 +381,7 @@
                 and cssp.course_id_ = #{courseId}
             </if>
         </where>
+        ORDER BY cssp.id_ DESC
     </select>
 
 	<select id="selectAbsenteeism" resultType="com.yonge.cooleshow.biz.dal.vo.CourseHomeworkVo">
@@ -396,4 +400,19 @@
             </if>
         </where>
     </select>
+    <select id="selectGroupHomeworkList"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.HomeworkWrapper$GroupHomework">
+        select ch.id_ homeworkId,ch.course_schedule_id_ courseId,cs.class_num_ classNum,ch.content_ content,
+               ch.completed_num_ completedNum,cg.pre_student_num_ studentNum,
+               COUNT(CASE WHEN sch.id_ IS NULL OR sch.teacher_replied_ IS NULL OR sch.teacher_replied_ = '' THEN NULL ELSE 1 END) repliedNum
+        from course_homework ch
+                 left join course_schedule cs ON cs.id_ = ch.course_schedule_id_
+                 left join student_course_homework sch ON sch.course_homework_id_ = ch.id_
+                 left join course_group cg ON cg.id_ = ch.course_group_id_
+        WHERE ch.course_group_id_ = #{param.courseGroupId}
+        <if test="param.search != null and param.search != ''">
+            AND (ch.course_schedule_id_ = #{param.search} OR ch.content_ LIKE CONCAT('%',#{param.search},'%'))
+        </if>
+        GROUP BY ch.id_ ORDER BY cs.class_num_
+    </select>
 </mapper>

+ 6 - 3
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleMapper.xml

@@ -60,7 +60,8 @@
                 sum(if(a.end_time_ &lt;= now(),1,0)) as expTime,
                 sum(if(a.end_time_ &gt; now(),1,0)) as unExpTime
             from course_schedule a
-            where a.lock_ = 0 and a.type_ in ('PRACTICE','PIANO_ROOM_CLASS','VIP','LIVE','GROUP')
+            LEFT JOIN course_group cg ON cg.id_ = a.course_group_id_
+            where a.lock_ = 0 AND cg.status_ IN ('COMPLETE','ING')
             <if test="userId != null and userId != ''">
                 and a.teacher_id_ = #{userId}
             </if>
@@ -72,8 +73,9 @@
                 a.teacher_id_ as userId,
                 avg (b.score_) as starGrade
             from course_schedule a
+            LEFT JOIN course_group cg ON cg.id_ = a.course_group_id_
             join course_schedule_replied b on a.id_ = b.course_schedule_id_
-            where a.lock_ = 0 and a.type_ in ('PRACTICE','PIANO_ROOM_CLASS','VIP','LIVE','GROUP') and b.score_ is not null
+            where a.lock_ = 0 AND cg.status_ IN ('COMPLETE','ING') and b.score_ is not null
             <if test="userId != null and userId != ''">
                 and a.teacher_id_ = #{userId}
             </if>
@@ -93,7 +95,8 @@
         from student t
         left join course_schedule_student_payment a on t.user_id_ = a.user_id_
         left join course_schedule b on a.course_id_ = b.id_
-        where b.lock_ = 0 and b.type_ in ('PRACTICE','PIANO_ROOM_CLASS','VIP','LIVE','GROUP')
+        LEFT JOIN course_group cg ON cg.id_ = b.course_group_id_
+        where b.lock_ = 0 AND cg.status_ IN ('COMPLETE','ING')
             <if test="userId != null and userId != ''">
                 and t.user_id_ = #{userId}
             </if>

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

@@ -186,4 +186,12 @@
           AND DATE_FORMAT(uod.create_time_, '%Y-%m-%d') BETWEEN #{param.startTime} AND #{param.endTime}
         group by 'date' order by 'date'
     </select>
+
+	<select id="getPayingCourseGroupOrder" resultType="java.lang.String">
+        SELECT distinct t.order_no_ FROM user_order_detail t
+        LEFT JOIN user_order o ON t.order_no_ = o.order_no_
+        WHERE t.biz_id_ = #{groupId}
+        AND t.good_type_ in ('LIVE','GROUP')
+        AND o.status_ IN ('WAIT_PAY','PAYING')
+    </select>
 </mapper>