com.ruoyi
diff --git a/ruoyi-system/ruoyi-system.iml b/ruoyi-system/ruoyi-system.iml
index 6d5841c..5796973 100644
--- a/ruoyi-system/ruoyi-system.iml
+++ b/ruoyi-system/ruoyi-system.iml
@@ -101,7 +101,11 @@
-
+
+
+
+
+
@@ -179,6 +183,7 @@
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjAppreciate.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjAppreciate.java
index 525f549..c0b5225 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjAppreciate.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjAppreciate.java
@@ -1,6 +1,7 @@
package com.ruoyi.basic.domain;
import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
@@ -74,7 +75,8 @@ public class YjAppreciate implements Serializable {
/**
* 所属门店id
*/
- private String visitStore;
+ @TableField("dept_id")
+ private String deptId;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjHealthy.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjHealthy.java
index 9bc1863..13a815f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjHealthy.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjHealthy.java
@@ -1,6 +1,7 @@
package com.ruoyi.basic.domain;
import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
@@ -74,7 +75,8 @@ public class YjHealthy implements Serializable {
/**
* 所属门店id
*/
- private String visitStore;
+ @TableField("dept_id")
+ private String deptId;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjInherit.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjInherit.java
index cf64826..b87eb52 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjInherit.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjInherit.java
@@ -75,7 +75,7 @@ public class YjInherit implements Serializable {
*
* 所属商户id
*/
- private String visitStore;
+ private String deptId;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjPracticeMoments.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjPracticeMoments.java
index 0d240be..b236cc3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjPracticeMoments.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjPracticeMoments.java
@@ -73,5 +73,5 @@ public class YjPracticeMoments implements Serializable {
/**
* 所属商户id
*/
- private String visitStore;
+ private String deptId;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjSense.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjSense.java
index 00f1e9f..c3dd03e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjSense.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjSense.java
@@ -74,7 +74,7 @@ public class YjSense implements Serializable {
/**
* 所属门店id
*/
- private String visitStore;
+ private String deptId;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjStore.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjStore.java
index 6b57003..dca69b2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjStore.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjStore.java
@@ -3,12 +3,14 @@ package com.ruoyi.basic.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
+import java.util.List;
/**
*
@@ -20,24 +22,19 @@ import java.util.Date;
*/
@Data
@EqualsAndHashCode(callSuper = false)
+@TableName("yj_store")
public class YjStore implements Serializable {
private static final long serialVersionUID=1L;
- @TableId(value = "id", type = IdType.ASSIGN_UUID)
- private String id;
-
- /**
- * 负责人id
- */
- private Long responsibleId;//负责人id
- //有效期至,终身/长期用户不判断
- private Date validUntil;
- /**
- * 是否正常运营
- * 状态 0申请,1审核中,2审核通过,3停止运营
- */
- private Integer status;
+ @TableId(value = "dept_id", type = IdType.ASSIGN_UUID)
+ private Long id;
+ //总店id
+ @TableField(exist = false)
+ private Long parentId;
+ //租户id
+ @TableField(exist = false)
+ private String tenantId;
@ApiModelProperty("banner图")
private String banner;
@@ -51,10 +48,11 @@ public class YjStore implements Serializable {
private String founder;
// 企业/门店简介(富文本)
private String profile;
- //租户id
- private String tenantId;
- //总店id
- private String parentId;
+
+ @TableField(exist = false)
+ private List childList;
+
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjTenant.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjTenant.java
deleted file mode 100644
index 5f000f6..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/YjTenant.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.ruoyi.basic.domain;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- *
- * 商户表
- *
- *
- * @author xn
- * @since 2022-09-28
- */
-@Data
-@EqualsAndHashCode(callSuper = false)
-public class YjTenant implements Serializable {
-
- private static final long serialVersionUID=1L;
-
- @TableId(value = "id", type = IdType.ASSIGN_UUID)
- private String id;
-
- /**
- * 负责人id
- */
- private Long responsibleId;//负责人id
-
- private String businessLicense;//营业执照编号/统一信用编码
-
- private byte[] businessLicensePicture;//营业执照照片/扫描件
-
- private String legalPerson;//法人姓名
-
- private String legalPersonTel;//法人联系方式
-
- private String legalPersonCard;//法人证件号码
-
- private byte[] legalPersonCardPicturePositive;//法人证件照片/扫描件正面
-
- private byte[] legalPersonCardPictureBack;//法人证件照片/扫描件背面
-
- private String vip;//付费级别
-
- private String vipPrice;//付费金额
-
- private String vipPriceType;//付费方式,试用,年付,终身/长期
-
- private String vipPayType;//支付方式,支付宝,微信,转账银行
-
- private String bankCardId;//银行转账账号
-
- private Date validUntil;//有效期至,终身/长期用户不判断
-
- private Date reminderDate;//年付用户预付款提醒开始日期,提醒截止日期到宽限期结束
-
- private Integer gracePeriod;//宽限期
-
- /**
- * 是否正常运营
- */
- private Integer status;//状态 0申请,1审核中,2审核通过,3停止运营
-
- @TableField(exist = false)
- private String legalPersonCardPicturePositive1;//法人证件照片/扫描件正面
-
- @TableField(exist = false)
- private String legalPersonCardPictureBack1;//法人证件照片/扫描件背面
-
- @TableField(exist = false)
- private String businessLicensePicture1;//营业执照照片/扫描件
-
-
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/StoreDto.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/StoreDto.java
deleted file mode 100644
index ec35ac0..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/StoreDto.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.basic.domain.dto;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.ruoyi.basic.domain.YjStore;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- *
- * 门店表
- *
- *
- * @author xn
- * @since 2022-09-28
- */
-@Data
-@EqualsAndHashCode(callSuper = false)
-public class StoreDto implements Serializable {
-
- private static final long serialVersionUID=1L;
-
- private String id;
-
- @ApiModelProperty("企业名称")
- private String storeName;
- //总店id
- private String parentId;
- private List childList;
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/YjVenueDto.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/YjVenueDto.java
index e919c16..11902a6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/YjVenueDto.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/YjVenueDto.java
@@ -19,7 +19,7 @@ public class YjVenueDto {
private Long deptId;
/**
- * 商户id
+ * 门店id
*/
private String storeId;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java
index 1bdb2ea..a2b7d7c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java
@@ -3,8 +3,6 @@ package com.ruoyi.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.basic.domain.YjStore;
-import com.ruoyi.basic.domain.dto.StoreDto;
-import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -18,7 +16,9 @@ import java.util.List;
*/
public interface YjStoreMapper extends BaseMapper {
+ YjStore getOne(Long deptId);
+ List getStoreListByTenantId(String tenantId);
- List getListForLogin();
- List getChilds(String id);
+ List getStoreList();
+ List getChilds(Long id);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java
index c7d42ea..2bb0b76 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java
@@ -2,8 +2,11 @@ package com.ruoyi.basic.service;
import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.RestResponse;
import com.ruoyi.basic.domain.YjStore;
+import java.util.List;
+
/**
*
* 商户表 服务类
@@ -13,5 +16,9 @@ import com.ruoyi.basic.domain.YjStore;
* @since 2022-09-28
*/
public interface YjStoreService extends IService {
+ RestResponse storesTree();
+ RestResponse changeStore(Long visitStoreId);
+ List getStoreListByTenantId(String tenantId);
+ YjStore getOne(Long id);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java
index 9553698..5ba7a97 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java
@@ -1,12 +1,25 @@
package com.ruoyi.basic.service.impl;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.RestResponse;
import com.ruoyi.basic.domain.YjStore;
import com.ruoyi.basic.mapper.YjStoreMapper;
+import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.basic.service.YjStoreService;
+import com.ruoyi.common.core.domain.entity.AppUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
*
* 商户表 服务实现类
@@ -17,5 +30,55 @@ import org.springframework.stereotype.Service;
*/
@Service
public class YjStoreServiceImpl extends ServiceImpl implements YjStoreService {
+ @Autowired
+ private YjAppUserService appUserService;
+
+
+ @Override
+ public RestResponse storesTree(){
+ Long userId = SecurityUtils.getAppLoginUser().getAppUserId();
+ AppUser appUser =appUserService.getById(userId);
+ if (ObjectUtil.isEmpty(appUser.getVisitStore())){
+ List dtoList= baseMapper.getStoreList();
+ dtoList.forEach(l->{
+ l.setStoreName(l.getStoreName()+"(总店)");
+ l.setChildList(baseMapper.getChilds(l.getId()));
+ });
+ return new RestResponse().setSuccess(true).setData(dtoList);
+ }
+
+ String tenantId= baseMapper.getOne(appUser.getVisitStore()).getTenantId();
+
+ List list=getStoreListByTenantId(tenantId);
+
+ list.forEach(l->{
+ if (l.getParentId().equals("0")){
+ l.setStoreName(l.getStoreName()+"(总店)");
+ }
+
+ });
+ return new RestResponse().setSuccess(true).setData(list);
+ }
+
+ @Override
+ public RestResponse changeStore(Long visitStoreId){
+ AppUser appUser = SecurityUtils.getAppLoginUser().getAppUser();
+ appUserService.update(new UpdateWrapper()
+ .eq("app_user_id",appUser.getId())
+ .set("visit_store",visitStoreId));
+
+ //返回新切换的门店信息
+ YjStore yjStore= this.baseMapper.getOne(visitStoreId);
+ return new RestResponse().setSuccess(true).setData(yjStore);
+ }
+
+ @Override
+ public List getStoreListByTenantId(String tenantId){
+ return baseMapper.getStoreListByTenantId(tenantId);
+ }
+ @Override
+ public YjStore getOne(Long id){
+ return baseMapper.getOne(id);
+ }
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/Context.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/Context.java
index 0405b44..9ae7e69 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/Context.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/Context.java
@@ -1,7 +1,5 @@
package com.ruoyi.course.domain;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -13,9 +11,8 @@ import java.io.Serializable;
public class Context implements Serializable {
private static final long serialVersionUID=1L;
- @TableId(value = "sys_user", type = IdType.AUTO)
-// @JsonFormat (pattern = "yyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Integer userId;
+
@ApiModelProperty(value = "教练姓名")
private String userName;
@ApiModelProperty(value = "性别")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourse.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourse.java
new file mode 100644
index 0000000..d60f2aa
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourse.java
@@ -0,0 +1,129 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 排课信息
+ *
+ *
+ *
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_book_course")
+public class ScBookCourse implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 排课编号
+ */
+ @TableField(value = "course_time_id")
+ @JsonSerialize(using = ToStringSerializer.class)
+ private Long courseTimeId;
+
+ /**
+ * 预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;5- >预约失败;
+ */
+ @TableField("book_status")
+ private int bookStatus;
+
+ /**
+ * 学员id
+ */
+ @TableField("student_id")
+ private Long studentId;
+
+ /**
+ * 创建预约时间
+ */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ @TableField("create_time")
+ private Date createTime;
+
+
+ @TableField("code")
+ private Long code;
+
+ @TableField("qr_code")
+ private String qrCode;
+
+ //*0未签到 1签到
+ @TableField("check_in")
+ private int checkIn;
+
+
+ @TableField("check_in_time")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date checkInTime;
+
+
+ /**
+ * 收费模式 count:课时 days:时间 total_fee:储值
+ */
+ @TableField("charge_type")
+ private String chargeType;
+
+ /**
+ * 卡号
+ */
+ @TableField(value = "card_no")
+ private String cardNo;
+
+
+ /**
+ * 划扣次数
+ */
+ @TableField(value = "deduct_cnt")
+ private BigDecimal deductCnt;
+
+ /**
+ * 划扣金额
+ */
+ @TableField(value = "deduct_fee")
+ private BigDecimal deductFee;
+
+ @TableField(value = "check_in_manager")
+ private Long userId;
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+
+ /**
+ * 课程id
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ @TableField("cla_id")
+ private Long claId;
+ /**
+ * 开班校区
+ */
+ @TableField("depart_id")
+ private Long departId;
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourseLog.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourseLog.java
new file mode 100644
index 0000000..8743028
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScBookCourseLog.java
@@ -0,0 +1,64 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 排课信息
+ *
+ *
+ *
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_book_course_log")
+public class ScBookCourseLog implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private Long id;
+ @TableField(value = "book_id")
+ private Long bookId;
+
+ /**
+ * 预约状态:0->预约成功/待上课;1->已取消;2->已完成 3->待评价;
+ */
+ @TableField("update_time")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date updateTime;
+
+ /**
+ * 学员id
+ */
+ @TableField("update_user_id")
+ private Long updateUser;
+
+ /**
+ * 备注
+ */
+ @TableField("remarks")
+ private String remarks;
+
+
+ /**
+ * 预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;5- >预约失败;
+ */
+ @TableField("book_status")
+ private int bookStatus;
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java
index 4ed2dff..1d0503a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java
@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@@ -18,8 +21,8 @@ import java.util.Date;
* 排课信息
*
*
- * @author zhangby
- * @since 2020-09-16
+ *
+ *
*/
@Data
@EqualsAndHashCode(callSuper = false)
@@ -33,6 +36,7 @@ public class ScClaTime implements Serializable {
* 排课编号
*/
@TableId(value = "course_time_id", type = IdType.ASSIGN_ID)
+ @JsonSerialize(using = ToStringSerializer.class)
private Long courseTimeId;
/**
@@ -107,23 +111,15 @@ public class ScClaTime implements Serializable {
@TableField("real_end_time")
private String realEndTime;
- /**
- * 课时变更数量
- */
- @TableField("pay_hour")
- private BigDecimal payHour;
- /**
- * 总课时消耗
- */
- @TableField("pay_total_hour")
- private BigDecimal payTotalHour;
+
+
/**
- * 总学费消耗
+ * 老师获取的课时费
*/
- @TableField("pay_total_fee")
- private BigDecimal payTotalFee;
+ @TableField("teacher_fee")
+ private BigDecimal teacherFee;
/**
* 来源 1:重复排课 2:未排课上课 3:单个新增
@@ -138,10 +134,10 @@ public class ScClaTime implements Serializable {
private String status;
/**
- * 应到人数
+ * 预约人数
*/
- @TableField("need_attend_cnt")
- private Integer needAttendCnt;
+ @TableField("book_attend_cnt")
+ private Integer bookAttendCnt;
/**
* 实到人数
@@ -150,22 +146,18 @@ public class ScClaTime implements Serializable {
private Integer realAttendCnt;
/**
- * 到课人数
+ * 限制最高人数
*/
@TableField("at_class_cnt")
private Integer atClassCnt;
/**
- * 请假人数
+ * 最低开课人数
*/
- @TableField("leave_cnt")
- private Integer leaveCnt;
+ @TableField("less_cnt")
+ private Integer lessCnt;
+
- /**
- * 缺勤人数
- */
- @TableField("out_cnt")
- private Integer outCnt;
/**
* 备注
@@ -177,28 +169,33 @@ public class ScClaTime implements Serializable {
* 创建者
*/
@TableField("create_user")
- private String createUser;
+ private Long createUser;
/**
* 创建时间
*/
@TableField("create_time")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
- /**
- * 更新者
- */
- @TableField("last_update_user")
- private String lastUpdateUser;
-
/**
* 更新时间
*/
@TableField("last_update_time")
private Date lastUpdateTime;
+ @TableField("venue_fee")
+ private BigDecimal venueFee;
+ @TableField("room_usage_time")
+ private Double roomUsageTime;//不足0.5按0.5计,>0.5小时,按1小时计
+
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
@TableField(exist = false)
- private Long deptId;
+ private Long storeId;
@TableField(exist = false)
private String courseName;
@TableField(exist = false)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeAttend.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeAttend.java
new file mode 100644
index 0000000..1dadc4f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeAttend.java
@@ -0,0 +1,167 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 上课出勤表
+ *
+ *
+ *
+ * @since 2020-09-30 02:33:26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_cla_time_attend")
+public class ScClaTimeAttend implements Serializable {
+
+
+ /**
+ * 主键
+ */
+ @TableId(value = "attend_id", type = IdType.ASSIGN_ID)
+ private Long attendId;
+
+
+ /**
+ * sc_cla_time.course_time_id
+ */
+ @TableField("course_time_id")
+ @JsonSerialize(using = ToStringSerializer.class)
+ private Long courseTimeId;
+
+ @TableField("book_id")
+ private Long bookId;
+
+ /**
+ * 学生
+ */
+ @TableField("student_id")
+ private Long studentId;
+
+ /**
+ * 班级 冗余自动
+ */
+ @TableField("cla_id")
+ private Long claId;
+
+ /**
+ * 课程 冗余自动
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ /**
+ * 上课教师
+ */
+ @TableField("teacher_id")
+ private Long teacherId;
+
+ /**
+ * 教师名
+ */
+ @TableField("teacher_name")
+ private String teacherName;
+
+ /**
+ * 收费模式 count:课时 days:时间 total_fee:储值
+ */
+ @TableField("charge_type")
+ private String chargeType;
+
+ /**
+ * 出席状态 1:到课 2:请假 3:缺勤
+ */
+ @TableField("attend_status")
+ private String attendStatus;
+
+ /**
+ * 教师获取课时费(未使用)
+ */
+ @TableField("teacher_get_cla_fee")
+ private BigDecimal teacherGetClaFee;
+
+ /**
+ * 扣减课时数量
+ */
+ @TableField("pay_hour")
+ private BigDecimal payHour;
+
+ /**
+ * 学费消耗
+ */
+ @TableField("pay_fee")
+ private BigDecimal payFee;
+
+ /**
+ * 备注
+ */
+ @TableField("memo")
+ private String memo;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date createTime;
+
+
+ /**
+ * 卡ID
+ */
+ @TableField(value = "member_card_id")
+ private Long memberCardId;
+
+ /**
+ * 划扣前次数
+ */
+ @TableField(value = "count_before")
+ private BigDecimal countBefore;
+
+ /**
+ * 划扣后次数
+ */
+ @TableField(value = "count_after")
+ private BigDecimal countAfter;
+
+
+
+ /**
+ * 划扣前余额
+ */
+ @TableField(value = "fee_before")
+ private BigDecimal feeBefore;
+
+ /**
+ * 划扣后余额
+ */
+ @TableField(value = "fee_after")
+ private BigDecimal feeAfter;
+
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeRule.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeRule.java
new file mode 100644
index 0000000..4e0d5f6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTimeRule.java
@@ -0,0 +1,190 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 上课时间配置规则
+ *
+ *
+ *
+ * @since 2020-09-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_cla_time_rule")
+public class ScClaTimeRule implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 规则id
+ */
+ @TableId(value = "rule_id", type = IdType.ASSIGN_ID)
+ private Long ruleId;
+
+ /**
+ * 班级
+ */
+ @TableField("cla_id")
+ private Long claId;
+
+ /**
+ * 规则类型 1重复排课 2单次排课
+ */
+ @TableField("rule_type")
+ private String ruleType;
+
+ /**
+ * 开始日期
+ */
+ @TableField("begin_date")
+ private String beginDate;
+
+ /**
+ * 结束日期
+ */
+ @TableField("end_date")
+ private String endDate;
+
+ /**
+ * 单次排课 日期
+ */
+ @TableField("once_date")
+ private String onceDate;
+
+ /**
+ * 重复方式 1每周重复 2隔天重复 3隔周重复
+ */
+ @TableField("repeat_type")
+ private String repeatType;
+
+ /**
+ * 上课星期 周几上课
+ */
+ @TableField("week_day")
+ private String weekDay;
+
+ /**
+ * 是否过滤节假日 1过滤 0不过滤
+ */
+ @TableField("filter_holiday")
+ private boolean filterHoliday;
+
+ /**
+ * 上课时间
+ */
+ @TableField("start_time")
+ private String startTime;
+
+ /**
+ * 下课时间
+ */
+ @TableField("end_time")
+ private String endTime;
+
+ /**
+ * 任课教师
+ */
+ @TableField("teacher_id")
+ private Long teacherId;
+
+ /**
+ * 上课教室
+ */
+ @TableField("room_id")
+ private Long roomId;
+
+ /**
+ * 上课教室
+ */
+ @TableField("room_name")
+ private String roomName;
+
+ /**
+ * 上课主题
+ */
+ @TableField("class_theme")
+ private String classTheme;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ private Date lastUpdateTime;
+
+ /**
+ * 单次排课 选择的上课日期
+ */
+ @TableField(exist = false)
+ private String[] chooseDate;
+
+ /**
+ * 所属校区
+ */
+ @TableField(exist = false)
+ private Long deptId;
+
+// public boolean checkParam() {
+// if (null == claId || null == teacherId) {
+// return false;
+// }
+// if (StringUtils.isAnyEmpty(ruleType)) {
+// return false;
+// }
+// if (ClaTimeRuleTypeEnums.ONCE_RULE.getRuleType().equals(ruleType)) {
+// if (StringUtils.isAnyEmpty(startTime, endTime)) {
+// return false;
+// } else if (null == chooseDate || chooseDate.length == 0) {
+// return false;
+// }
+// }
+// if ("1".equals(ruleType) && StringUtils.isAnyEmpty(repeatType)) {
+// return false;
+// }
+// if (ClaTimeRepeatTypeEnums.EVERY_WEEK.getRepeatType().equals(repeatType)
+// || ClaTimeRepeatTypeEnums.EVERY_SECOND_WEEK.getRepeatType().equals(repeatType)) {
+// if (StringUtils.isAnyEmpty(weekDay, startTime, endTime, beginDate, endDate)) {
+// return false;
+// }
+// } else {
+// if (StringUtils.isAnyEmpty(startTime, endTime)) {
+// return false;
+// }
+// }
+// return true;
+// }
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCommissionPlans.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCommissionPlans.java
new file mode 100644
index 0000000..8e8c241
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCommissionPlans.java
@@ -0,0 +1,49 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 预约学员信息
+ */
+@Data
+@TableName("sc_commission_plans")
+public class ScCommissionPlans {
+
+ private Long id;
+ //方案名称
+ private String planName;
+ // 第一阶梯阈值(0-?元)
+ private BigDecimal tier1Threshold;
+ // 第一阶梯比例(8%)
+ private BigDecimal tier1Rate;
+ // 第二阶梯阈值(30000)
+ private BigDecimal tier2Threshold;
+ // 第二阶梯比例(10%)
+ private BigDecimal tier2Rate;
+ // 第三阶梯阈值(50000)
+ private BigDecimal tier3Threshold;
+ // 第三阶梯比例(12%)
+ private BigDecimal tier3Rate;
+
+ // 第四阶梯比例(15%)
+ private BigDecimal tier4Rate;
+ // 续费率(5%)
+ private BigDecimal renewalRate;
+ // 转介绍率(8-10%)
+ private BigDecimal referralRate;
+ // 是否生效(默认0未生效 1生效 )
+ private int isActive;
+ // 生效日期
+ private Date effectiveDate;
+ // 创建时间
+ private Date createdAt;
+
+
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourse.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourse.java
new file mode 100644
index 0000000..f307a35
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourse.java
@@ -0,0 +1,118 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 课程信息
+ *
+ *
+
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_course")
+public class ScCourse implements Serializable {
+
+
+ /**
+ * 课程id
+ */
+ @TableId(value = "course_id")
+ private Long courseId;
+
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+
+ /**
+ * 课程名称
+ */
+ @TableField("course_name")
+ private String courseName;
+
+ /**
+ * 课程类型
+ */
+ @TableField("course_type_id")
+ private Long courseTypeId;
+
+ /**
+ * 授课模式 1 班课 2 一对一
+ */
+ @TableField("teaching_mode")
+ private String teachingMode;
+
+ /**
+ * 课程简介
+ */
+ @TableField("course_intro")
+ private String courseIntro;
+
+ /**
+ * 是否在售 1在售 0停售
+ */
+ @TableField("sale")
+ private String sale;
+
+ /**
+ * 删除标志(1删除 0在用)
+ */
+ @TableField("delete_flag")
+ @TableLogic
+ private String deleteFlag;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ @JsonIgnore
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ @JsonIgnore
+ private Date lastUpdateTime;
+
+ /**
+ * 课时费
+ */
+ @TableField("cla_fee")
+ private BigDecimal claFee;
+
+
+// /**
+// * 导入id
+// */
+// @TableId(value = "import_id")
+// @JsonIgnore
+// private Long importId;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCharge.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCharge.java
new file mode 100644
index 0000000..415cd94
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCharge.java
@@ -0,0 +1,88 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ *
+ * 课程收费模式
+ *
+ *
+ *
+ * @since 2020-07-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_course_charge")
+public class ScCourseCharge implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 收费编号
+ */
+ @TableId(value = "charge_id")
+ private Long chargeId;
+
+ /**
+ * 课程编号
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ /**
+ * 校区 -1为全部校区
+ */
+ @TableField("depart_id")
+ private Long departId;
+
+ /**
+ * 收费模式 hour:课时 date:时间 cycle:期
+ */
+ @TableField("charge_type")
+ private String chargeType;
+
+ /**
+ * 课时数量
+ */
+ @TableField("count")
+ private BigDecimal count;
+
+ /**
+ * 总价
+ */
+ @TableField("total_fee")
+ private BigDecimal totalFee;
+
+ /**
+ * 佣金方案id
+ */
+ @TableField("commission_plans_id")
+ private BigDecimal commissionPlansId;
+
+ /**
+ * 时间周期 天/月/季/年
+ */
+ @TableField("date_unit")
+ private String dateUnit;
+
+// public String getChargeName() {
+// if (CourseChargeTypeEnum.HOUR.getChargeType().equals(chargeType)) {
+// return "按课时 " + count.toString() + "课时=" + totalFee +"元";
+// } else if (CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+// return "按时间 " + count.toString() + ChargeDateUnitEnum.getDateUnitLabel(dateUnit) + "=" + totalFee+"元";
+// } else if (CourseChargeTypeEnum.CYCLE.getChargeType().equals(chargeType)) {
+// return "按周期 " + count.toString() + "课时=" + totalFee +"元";
+// }
+// return "";
+// }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCla.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCla.java
new file mode 100644
index 0000000..acdb9a2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseCla.java
@@ -0,0 +1,161 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 课程班级信息
+ *
+ *
+ *
+ * @since 2020-08-07
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_course_cla")
+public class ScCourseCla implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 班级id
+ */
+ @TableId(value = "cla_id")
+ private Long claId;
+
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+
+ /**
+ * 课程id
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ /**
+ * 开班校区
+ */
+ @TableField("depart_id")
+ private Long departId;
+
+ /**
+ * 班主任id
+ */
+ @TableField("staff_id")
+ private Long staffId;
+
+ /**
+ * 班级名称
+ */
+ @TableField("cla_name")
+ private String claName;
+
+ /**
+ * 班级颜色
+ */
+ @TableField("cla_color")
+ private String claColor;
+
+ /**
+ * 满班人数
+ */
+ @TableField("capacity")
+ private Integer capacity;
+
+ /**
+ * 招生状态 1开放 2满班后停止 0停止
+ */
+ @TableField("recruit_status")
+ private String recruitStatus;
+
+
+
+
+
+ /**
+ * 开班日期
+ */
+ @TableField("open_date")
+ private String openDate;
+
+ /**
+ * 结班日期
+ */
+ @TableField("close_date")
+ private String closeDate;
+
+ /**
+ * 备注
+ */
+ @TableField("memo")
+ private String memo;
+
+ /**
+ * 删除标志(1删除 0在用)
+ */
+ @TableField("delete_flag")
+ private String deleteFlag;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ private Date lastUpdateTime;
+
+ @TableField(exist = false)
+ private String deptName;
+
+ @TableField(exist = false)
+ private String teacherName;
+
+ // 当前班级人数
+ @TableField(exist = false)
+ private Integer studentCnt;
+
+ /**
+ * 校验参数
+ * @return
+ */
+// public APIBaseResponse checkParam(){
+// if(StringUtils.isAnyEmpty(claName,claColor,recruitStatus,openDate)){
+// return APIBaseResponse.fail("请求参数错误,请全部填写后,重新提交");
+// }
+// if(null == courseId || null == departId || null == staffId || null == capacity || null == everyStuLoseHour || null == everyTeaGetHour){
+// return APIBaseResponse.fail("请求参数错误,请全部填写后,重新提交");
+// }
+// return APIBaseResponse.success();
+// }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseType.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseType.java
new file mode 100644
index 0000000..990a1ce
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScCourseType.java
@@ -0,0 +1,66 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 课程类型
+ *
+ *
+ *
+ * @since 2020-07-09 08:10:25
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_course_type")
+public class ScCourseType implements Serializable {
+
+
+ @TableId(value = "course_type_id")
+ private Long courseTypeId;
+
+ /**
+ * 所属租户
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+
+ /**
+ * 课程类型名
+ */
+ @TableField("course_type")
+ private String courseType;
+
+ /**
+ * 排序
+ */
+ @TableField("sort")
+ private Integer sort;
+
+ /**
+ * 状态(1正常 0停用)
+ */
+ @TableField("in_use")
+ private String inUse;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScMemberCard.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScMemberCard.java
new file mode 100644
index 0000000..a4fa997
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScMemberCard.java
@@ -0,0 +1,358 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ruoyi.common.utils.SecurityUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 会员卡实体类
+ * 对应数据库表: sc_member_cards
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_member_cards")
+public class ScMemberCard implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @TableField(value = "tenant_id")
+ private String tenantId;
+
+ /**
+ * 卡号
+ */
+ @TableField(value = "card_no")
+ private String cardNo;
+
+ /**
+ * 会员ID
+ */
+ @TableField(value = "member_id")
+ private Long memberId;
+
+
+
+ /**
+ * 卡类型ID
+ */
+ @TableField(value = "card_type_id")
+ private Long cardTypeId;
+
+ /**
+ * 状态
+ * ACTIVE-激活, INACTIVE-未激活, EXPIRED-已过期,
+ * SUSPENDED-已暂停, DEPLETED-已用完
+ */
+ @TableField("status")
+ private String status;
+
+ /**
+ * 剩余次数
+ */
+ @TableField("remaining_count")
+ private BigDecimal remainingCount;
+
+ /**
+ * 剩余天数
+ */
+ @TableField(exist = false)
+ private Integer remainingDays ;
+
+ /**
+ * 总次数
+ */
+ @TableField("total_count")
+ private BigDecimal totalCount;
+
+ /**
+ * 总天数
+ */
+ @TableField("total_days")
+ private Integer totalDays ;
+
+ @TableField("total_fee")
+ private BigDecimal totalFee;
+
+ @TableField("count_fee")
+ private BigDecimal countFee;
+ @TableField("day_fee")
+ private BigDecimal dayFee;
+
+ @TableField("remaining_total_fee")
+ private BigDecimal remainingTotalFee;
+
+ //时间卡 是否激活 1:立刻激活 2:首次预约激活
+ @TableField("have_activation_date")
+ private String haveActivationDate;
+
+ //储值or次数卡 是否设置有效期 1:不限期,用完失效 2:设置有效期
+ @TableField("have_expiry_date")
+ private String haveExpiryDate;
+
+ /**
+ * 激活日期
+ */
+ @TableField("activation_date")
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private LocalDate activationDate;
+
+ /**
+ * 到期日期
+ */
+ @TableField("expiry_date")
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private LocalDate expiryDate;
+
+ /**
+ * 购买日期
+ */
+ @TableField(value = "purchase_date", fill = FieldFill.INSERT)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime purchaseDate;
+
+ /**
+ * 购买价格
+ */
+ @TableField("price")
+ private BigDecimal price;
+
+
+ /**
+ * 备注
+ */
+ @TableField("notes")
+ private String notes;
+
+ /**
+ * 收费模式 count:课时 days:时间 total_fee:储值
+ */
+ @TableField("charge_type")
+ private String chargeType;
+
+ /**
+ * 创建时间
+ */
+ @TableField(value = "created_at", fill = FieldFill.INSERT)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createdAt;
+
+ /**
+ * 更新时间
+ */
+ @TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime updatedAt;
+
+ /**
+ * 逻辑删除标志 (0-未删除,1-已删除)
+ */
+ @TableLogic
+ @TableField(value = "is_deleted")
+ private Integer isDeleted = 0;
+
+
+
+ /**
+ * 会员实体(关联查询用)
+ * 注意:MyBatis Plus 不支持直接实体关联,这里仅作为查询结果接收字段
+ */
+ @TableField(exist = false)
+ @JsonIgnore
+ private ScStudent member;
+
+ /**
+ * 卡类型实体(关联查询用)
+ * 注意:MyBatis Plus 不支持直接实体关联,这里仅作为查询结果接收字段
+ */
+
+ @TableField(exist = false)
+ private String cardName;
+
+ /**
+ * 是否有效(可用的卡)
+ */
+ @TableField(exist = false)
+ private Boolean valid;
+
+ /**
+ * 是否已过期
+ */
+ @TableField(exist = false)
+ private Boolean expired;
+
+ /**
+ * 是否可用(激活且未过期)
+ */
+ @TableField(exist = false)
+ private Boolean available;
+
+ /**
+ * 是否可以续费
+ */
+ @TableField(exist = false)
+ private Boolean canRenew;
+
+ // 枚举类
+ public enum CardStatus {
+ ACTIVE("激活"),
+ INACTIVE("未激活"),
+ EXPIRED("已过期"),
+ SUSPENDED("已暂停"),
+ DEPLETED("已用完");
+
+ private final String description;
+
+ CardStatus(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public static CardStatus fromString(String status) {
+ if (status == null) return null;
+ for (CardStatus s : CardStatus.values()) {
+ if (s.name().equalsIgnoreCase(status)) {
+ return s;
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * 获取卡状态枚举
+ */
+ public CardStatus getCardStatus() {
+ return CardStatus.fromString(this.status);
+ }
+
+
+
+ public Integer getRemainingDays() {
+ if (activationDate== null || expiryDate == null ) {
+ return totalDays;
+ }
+
+ if (expiryDate.isBefore(LocalDate.now())) {
+ return 0;
+ }
+ Long days= java.time.temporal.ChronoUnit.DAYS.between(
+ LocalDate.now(), expiryDate
+ );
+ return days.intValue();
+ }
+
+ /**
+ * 设置卡状态
+ */
+ public void setCardStatus(CardStatus cardStatus) {
+ this.status = cardStatus != null ? cardStatus.name() : null;
+ }
+
+ /**
+ * 是否有效(可用的卡)
+ */
+ public Boolean isValid() {
+ CardStatus currentStatus = getCardStatus();
+ return CardStatus.ACTIVE.equals(currentStatus) ||
+ CardStatus.INACTIVE.equals(currentStatus);
+ }
+
+ /**
+ * 是否已过期
+ */
+ public Boolean isExpired() {
+ if (CardStatus.EXPIRED.equals(getCardStatus())) {
+ return true;
+ }
+ if (expiryDate != null && LocalDate.now().isAfter(expiryDate)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 是否可用(激活且未过期)
+ */
+ public Boolean isAvailable() {
+ return CardStatus.ACTIVE.equals(getCardStatus()) && !isExpired();
+ }
+
+ /**
+ * 是否可以续费
+ */
+ public Boolean canRenew() {
+ CardStatus currentStatus = getCardStatus();
+ return CardStatus.ACTIVE.equals(currentStatus) ||
+ CardStatus.INACTIVE.equals(currentStatus) ||
+ CardStatus.EXPIRED.equals(currentStatus);
+ }
+
+ /**
+ * 使用次数
+ * @param count 使用次数
+ * @return 是否成功使用
+ */
+ public boolean consume(BigDecimal count) {
+ if (!isAvailable() || remainingCount == null || remainingCount.compareTo(count)<1) {
+ return false;
+ }
+ remainingCount= remainingCount .multiply(count);
+ return true;
+ }
+
+ /**
+ * 添加次数
+ * @param count 添加的次数
+ */
+ public void addCount(BigDecimal count) {
+ if (remainingCount == null) {
+ remainingCount = new BigDecimal(0);
+ }
+ if (totalCount == null) {
+ totalCount = new BigDecimal(0);
+ }
+ remainingCount=remainingCount.add(count);
+ totalCount=totalCount.add(count);
+ }
+
+ /**
+ * 计算剩余有效期天数
+ */
+ public Long calculateRemainingDays() {
+ if (expiryDate == null || LocalDate.now().isAfter(expiryDate)) {
+ return 0L;
+ }
+ return java.time.temporal.ChronoUnit.DAYS.between(
+ LocalDate.now(), expiryDate
+ );
+ }
+
+ /**
+ * 初始化计算字段
+ */
+ public void calculateFields() {
+ this.valid = isValid();
+ this.expired = isExpired();
+ this.available = isAvailable();
+ this.canRenew = canRenew();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScRoom.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScRoom.java
new file mode 100644
index 0000000..f03a6f1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScRoom.java
@@ -0,0 +1,41 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+import org.joda.time.PeriodType;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ * 学生基本信息
+ *
+ *
+ */
+@Data
+@TableName("sc_room")
+public class ScRoom implements Serializable {
+
+ @TableId(value = "room_id")
+ private Long roomId;
+ private Long deptId;
+ private String roomName;
+ private String memo;
+ private Long createUser;
+ private Date createTime;
+ private Long lastUpdateUser;
+ private Date lastUpdateTime;
+ private BigDecimal venueFee;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudent.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudent.java
new file mode 100644
index 0000000..49c3482
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudent.java
@@ -0,0 +1,138 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+import org.joda.time.PeriodType;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ * 学生基本信息
+ *
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_student")
+public class ScStudent implements Serializable {
+
+
+ /**
+ * 学生id
+ */
+ @TableId(value = "student_id")
+ private Long studentId;
+
+ /**
+ * 所属机构
+ */
+ @TableField("tenant_id")
+ private String tenantId;
+
+
+ /**
+ * 学生姓名
+ */
+ @TableField("student_name")
+ private String studentName;
+
+ /**
+ * 出生日期
+ */
+ @TableField("birth_day")
+ @JsonFormat(pattern="yyyy-MM-dd")
+ private Date birthDay;
+
+ /**
+ * 0->未知;1->女;2->男
+ */
+ @TableField("sex")
+ private String sex;
+
+ /**
+ * 联系电话
+ */
+ @TableField("phone")
+ private String phone;
+
+ @TableField("app_user_id")
+ private String appUserId;
+
+ /**
+ * 入校时间
+ */
+ @TableField("in_time")
+ private String inTime;
+
+ /**
+ * 删除标志(1删除 0在用)
+ */
+ @TableField("delete_flag")
+ @TableLogic
+ private String deleteFlag;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ private Date lastUpdateTime;
+
+ @TableField(exist = false)
+ private String schoolName;
+ @TableField(exist = false)
+ private Integer age;
+ @TableField(exist = false)
+ private String course_name;
+ @TableField(exist = false)
+ private BigDecimal receiptFee;
+ @TableField(exist = false)
+ private String orderStatus;
+
+
+
+ @TableField(exist = false)
+ List contactList;
+
+ public Integer getAge() {
+ if(null == age && null != birthDay) {
+ DateTime now = new DateTime();
+ DateTime birthDateTime = new DateTime(birthDay);
+ Period period = new Period(birthDateTime, now, PeriodType.years());
+ return period.getYears();
+ } else {
+ return age;
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentContact.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentContact.java
new file mode 100644
index 0000000..e657601
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentContact.java
@@ -0,0 +1,71 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 联系人
+ *
+ *
+ *
+ * @since 2020-09-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_student_contact")
+public class ScStudentContact implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 联系人编号
+ */
+ @TableId(value = "contact_id", type = IdType.ASSIGN_ID)
+ private Long contactId;
+
+ /**
+ * 学生
+ */
+ @TableField("student_id")
+ private Long studentId;
+
+ /**
+ * 联系人称呼
+ */
+ @TableField("contact_nick")
+ private String contactNick;
+
+ /**
+ * 与学生关系
+ */
+ @TableField("contact_relation")
+ private String contactRelation;
+
+ /**
+ * 联系电话
+ */
+ @TableField("contact_phone")
+ private String contactPhone;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourse.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourse.java
new file mode 100644
index 0000000..f4343d2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourse.java
@@ -0,0 +1,139 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 学生课程
+ *
+ *
+ *
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_student_course")
+public class ScStudentCourse implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "student_course_id", type = IdType.ASSIGN_ID)
+ private Long studentCourseId;
+
+ /**
+ * 学生
+ */
+ @TableField("student_id")
+ private Long studentId;
+
+ /**
+ * 课程
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ /**
+ * 课程
+ */
+ @TableField("course_name")
+ private String courseName;
+
+ /**
+ * 报读校区
+ */
+ @TableField("dept_id")
+ private Long deptId;
+
+ /**
+ * 班级
+ */
+ @TableField("cla_id")
+ private Long claId;
+
+ /**
+ * 班级
+ */
+ @TableField("cla_name")
+ private String claName;
+
+ /**
+ * 收费模式 hour:课时 date:时间 cycle:期
+ */
+ @TableField("charge_type")
+ private String chargeType;
+
+ /**
+ * 总天数
+ */
+ @TableField("total_day")
+ private BigDecimal totalDay;
+
+ /**
+ * 总课时
+ */
+ @TableField("total_hour")
+ private BigDecimal totalHour;
+
+ /**
+ * 剩余课时
+ */
+ @TableField("balance_hour")
+ private BigDecimal balanceHour;
+
+ /**
+ * 总学费
+ */
+ @TableField("total_fee")
+ private BigDecimal totalFee;
+
+ /**
+ * 状态 1在读 2停课
+ */
+ @TableField("status")
+ private String status;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ private Date lastUpdateTime;
+
+ /**
+ * 更新的途径app or sys
+ */
+ @TableField("update_user_type")
+ private String updateUserType;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseLog.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseLog.java
new file mode 100644
index 0000000..9291e2f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseLog.java
@@ -0,0 +1,132 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 课程缴费扣费记录
+ *
+ *
+ *
+ * @since 2020-12-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_student_course_log")
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ScStudentCourseLog implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "log_id", type = IdType.ASSIGN_ID)
+ private Long logId;
+
+ /**
+ * 学生
+ */
+ @TableField("student_id")
+ private Long studentId;
+
+ /**
+ * 日志类型 参照 LogTypeEnum
+ */
+ @TableField("log_type")
+ private String logType;
+
+ /**
+ * 课程
+ */
+ @TableField("course_id")
+ private Long courseId;
+
+ /**
+ * 课程名称
+ */
+ @TableField("course_name")
+ private String courseName;
+
+ /**
+ * 班级
+ */
+ @TableField("cla_id")
+ private Long claId;
+
+ /**
+ * 班级名称
+ */
+ @TableField("cla_name")
+ private String claName;
+
+ /**
+ * 经办校区
+ */
+ @TableField("dept_name")
+ private String deptName;
+
+ /**
+ * 变更课时
+ */
+ @TableField("change_hour")
+ private BigDecimal changeHour;
+
+ /**
+ * 变更后剩余课时
+ */
+ @TableField("after_balance_hour")
+ private BigDecimal afterBalanceHour;
+
+ /**
+ * 变更金额
+ */
+ @TableField("change_fee")
+ private BigDecimal changeFee;
+
+ /**
+ * 备注
+ */
+ @TableField("memo")
+ private String memo;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user_name")
+ private String createUserName;
+ /**
+ * 途径app or sys
+ */
+ @TableField("create_user_type")
+ private String createUserType;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ // 学生姓名
+ @TableField(exist = false)
+ private String studentName;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseOrder.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseOrder.java
new file mode 100644
index 0000000..461530c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScStudentCourseOrder.java
@@ -0,0 +1,130 @@
+package com.ruoyi.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ * 学生课程关联订单
+ *
+ */
+@Data
+@Builder
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("sc_student_course_order")
+public class ScStudentCourseOrder implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "course_order_id", type = IdType.ASSIGN_ID)
+ private Long courseOrderId;
+
+ @TableField("student_course_id")
+ private Long studentCourseId;
+
+ /**
+ * 订单
+ */
+ @TableField("order_id")
+ private Long orderId;
+
+ /**
+ * 购买课程订单
+ */
+ @TableField("order_detail_id")
+ private Long orderDetailId;
+
+ /**
+ * 购买课时数量
+ */
+ @TableField("total_hour")
+ private BigDecimal totalHour;
+
+ /**
+ * 剩余课时数量
+ */
+ @TableField("balance_hour")
+ private BigDecimal balanceHour;
+
+ /**
+ * 购买天数
+ */
+ @TableField("total_day")
+ private BigDecimal totalDay;
+
+ /**
+ * 开始时间 按时间收费
+ */
+ @TableField("begin_date")
+ private String beginDate;
+
+ /**
+ * 结束时间 按时间收费
+ */
+ @TableField("end_date")
+ private String endDate;
+
+ /**
+ * 失效时间
+ */
+ @TableField("expire_date")
+ private String expireDate;
+
+ /**
+ * 总金额
+ */
+ @TableField("total_fee")
+ private BigDecimal totalFee;
+
+ /**
+ * 单价
+ */
+ @TableField("unit_fee")
+ private BigDecimal unitFee;
+
+ /**
+ * 是否有效 1有效 0失效
+ */
+ @TableField("valid")
+ private Boolean valid;
+
+ /**
+ * 创建者
+ */
+ @TableField("create_user")
+ private Long createUser;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField("last_update_user")
+ private Long lastUpdateUser;
+
+ /**
+ * 更新时间
+ */
+ @TableField("last_update_time")
+ private Date lastUpdateTime;
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ChargeDateUnitEnum.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ChargeDateUnitEnum.java
new file mode 100644
index 0000000..f954c66
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ChargeDateUnitEnum.java
@@ -0,0 +1,41 @@
+package com.ruoyi.course.domain.enums;
+
+/**
+ * 按时间收费周期枚举
+ * @author :zhangbaoyu
+ * @date :Created in 2020/9/5 13:23
+ */
+public enum ChargeDateUnitEnum {
+
+ DAY("day","天"),
+ MONTH("month","月"),
+ SEASON("season","季"),
+ YEAR("year","年"),
+ ;
+
+ ChargeDateUnitEnum(String dateUnit, String dateUnitLabel) {
+ this.dateUnit = dateUnit;
+ this.dateUnitLabel = dateUnitLabel;
+ }
+
+ private final String dateUnit;
+
+ private final String dateUnitLabel;
+
+ public String getDateUnit() {
+ return dateUnit;
+ }
+
+ public String getDateUnitLabel() {
+ return dateUnitLabel;
+ }
+
+ public static String getDateUnitLabel(String dateUnit) {
+ for (ChargeDateUnitEnum dateUnitEnum : ChargeDateUnitEnum.values()) {
+ if (dateUnitEnum.getDateUnit().equals(dateUnit)) {
+ return dateUnitEnum.getDateUnitLabel();
+ }
+ }
+ return "";
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeAttendStatusEnums.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeAttendStatusEnums.java
new file mode 100644
index 0000000..07c3512
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeAttendStatusEnums.java
@@ -0,0 +1,45 @@
+package com.ruoyi.course.domain.enums;
+
+/**
+ * 到课状态
+ * @author :zhangbaoyu
+ * @date :Created in 2020/4/30 15:16
+ */
+public enum ClaTimeAttendStatusEnums {
+
+ AT_CLASS("1","到课"),
+ LEAVE_CLASS("2","请假"),
+ OUT_CLASS("3","缺勤"),
+ ;
+
+ private final String attendStatus;
+
+ private final String statusName;
+
+ ClaTimeAttendStatusEnums(String attendStatus, String statusName) {
+ this.attendStatus = attendStatus;
+ this.statusName = statusName;
+ }
+
+ public String getAttendStatus() {
+ return attendStatus;
+ }
+
+ public String getStatusName() {
+ return statusName;
+ }
+
+ /**
+ * 根据状态获取名称
+ * @param status
+ * @return
+ */
+ public static String getNameByStatus(String status) {
+ for (ClaTimeAttendStatusEnums value : ClaTimeAttendStatusEnums.values()) {
+ if(value.getAttendStatus().equals(status)) {
+ return value.getStatusName();
+ }
+ }
+ return "";
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeStatusEnums.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeStatusEnums.java
new file mode 100644
index 0000000..12b95b6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/ClaTimeStatusEnums.java
@@ -0,0 +1,31 @@
+package com.ruoyi.course.domain.enums;
+
+/**
+ * 排课 状态
+ * @author :zhangbaoyu
+ * @date :Created in 2020/4/30 15:16
+ */
+public enum ClaTimeStatusEnums {
+
+ WAIT_CLASS("1","待上课"),
+ HAD_CLASS("2","已上课"),
+ CHANGE_CLASS("3","已调课"),
+ ;
+
+ private final String status;
+
+ private final String statusName;
+
+ ClaTimeStatusEnums(String status, String statusName) {
+ this.status = status;
+ this.statusName = statusName;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public String getStatusName() {
+ return statusName;
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/CourseChargeTypeEnum.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/CourseChargeTypeEnum.java
new file mode 100644
index 0000000..fc9e363
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/CourseChargeTypeEnum.java
@@ -0,0 +1,42 @@
+package com.ruoyi.course.domain.enums;
+
+/**
+ * 课程收费模式
+ * @author :zhangbaoyu
+ * @date :Created in 2020/8/4 15:30
+ */
+public enum CourseChargeTypeEnum {
+
+ // 按课时
+ HOUR("hour", "按课时"),
+ // 按时间
+ DATE("date", "按时间"),
+ // 按期
+ CYCLE("cycle", "按期");
+
+ private final String chargeType;
+
+ private final String chargeTypeName;
+
+ CourseChargeTypeEnum(String chargeType, String chargeTypeName) {
+ this.chargeType = chargeType;
+ this.chargeTypeName = chargeTypeName;
+ }
+
+ public String getChargeType() {
+ return chargeType;
+ }
+
+ public String getChargeTypeName() {
+ return chargeTypeName;
+ }
+
+ public static String getChargeType(String chargeType) {
+ for (CourseChargeTypeEnum chargeTypeEnum : CourseChargeTypeEnum.values()) {
+ if (chargeTypeEnum.getChargeType().equals(chargeType)){
+ return chargeTypeEnum.getChargeTypeName();
+ }
+ }
+ return "未知";
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/LogTypeEnum.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/LogTypeEnum.java
new file mode 100644
index 0000000..46388a1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/enums/LogTypeEnum.java
@@ -0,0 +1,34 @@
+package com.ruoyi.course.domain.enums;
+
+/**
+ * 学生日志类型
+ * @author :zhangbaoyu
+ * @date :Created in 2020/12/19 10:15
+ */
+public enum LogTypeEnum {
+
+ PAY_FEE("1","缴费"),
+ ATTEND_CLA("2","上课"),
+ DELETE_ATTEND_CLA("3","删除上课记录"),
+ INVALID_ORDER("4","作废订单"),
+ OUT_CLA("5","退出班级"),
+ IN_CLA("6","进入班级"),
+ ;
+
+ private final String logType;
+
+ private final String logTypeName;
+
+ LogTypeEnum(String logType, String logTypeName) {
+ this.logType = logType;
+ this.logTypeName = logTypeName;
+ }
+
+ public String getLogType() {
+ return logType;
+ }
+
+ public String getLogTypeName() {
+ return logTypeName;
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttend.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttend.java
new file mode 100644
index 0000000..92de3ba
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttend.java
@@ -0,0 +1,106 @@
+package com.ruoyi.course.domain.req;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * 记上课请求参数
+ * 修改上课记录请求参数
+ */
+@Data
+public class ReqClaTimeAttend {
+
+ // 上课方式 排课记上课rule、自定义上课custom
+ private String attendType;
+
+ // 排课编号
+ @JsonSerialize(using = ToStringSerializer.class)
+ private Long courseTimeId;
+
+ private Long claId;
+
+ private Long teacherId;
+
+ private Long roomId;
+
+ private String claDate;
+
+ private String startTime;
+
+ private String endTime;
+
+ private String classTheme;
+
+ private String memo;
+
+ List studentAttendList;
+
+ /**
+ * 参数校验
+ * @return
+ */
+// public APIResponse checkParam() {
+// if(null == studentAttendList || studentAttendList.size() ==0) {
+// return APIResponse.toExceptionResponse("排课记上课,请选择上课学生");
+// }
+// for (ReqClaTimeAttendItem attendItem : studentAttendList) {
+// if(StringUtils.isAnyEmpty(attendItem.getAttendStatus())) {
+// return APIResponse.toExceptionResponse("请选择学员到课状态");
+// } else if(null == attendItem.getStudentCourseId()) {
+// return APIResponse.toExceptionResponse("请选择学员");
+// } else if(null == attendItem.getStuLoseHour()) {
+// return APIResponse.toExceptionResponse("请选择扣减课时");
+// }
+// }
+// if("rule".equals(attendType)) {
+// // 排课记上课
+// if(null == courseTimeId) {
+// return APIResponse.toExceptionResponse("排课记上课,未选择上课日期!");
+// } else if(StringUtils.isAnyEmpty(startTime,endTime)) {
+// return APIResponse.toExceptionResponse("排课记上课,未选择上下课时间!");
+// }
+//
+// } else if ("custom".equals(attendType)) {
+// // 自定义记上课
+// if(StringUtils.isAnyEmpty(claDate,startTime,endTime)) {
+// return APIResponse.toExceptionResponse("自定义记上课,未选择上课日期,上下课时间!");
+// } else if( null == teacherId) {
+// return APIResponse.toExceptionResponse("自定义记上课,请选择上课教师!");
+// }
+// }
+// return APIResponse.toOkResponse();
+// }
+
+ /**
+ * 已上课修改
+ * 参数校验
+ * @return
+ */
+// public APIResponse checkParamForUpdateHadClaTime() {
+// if(null == studentAttendList || studentAttendList.size() ==0) {
+// return APIResponse.toExceptionResponse("排课记上课,请选择上课学生");
+// }
+// for (ReqClaTimeAttendItem attendItem : studentAttendList) {
+// if(StringUtils.isAnyEmpty(attendItem.getAttendStatus())) {
+// return APIResponse.toExceptionResponse("请选择学员到课状态");
+// } else if(null == attendItem.getStudentCourseId()) {
+// return APIResponse.toExceptionResponse("请选择学员");
+// } else if(null == attendItem.getStuLoseHour()) {
+// return APIResponse.toExceptionResponse("请选择扣减课时");
+// }
+// }
+//
+// // 自定义记上课
+// if(StringUtils.isAnyEmpty(claDate,startTime,endTime)) {
+// return APIResponse.toExceptionResponse("自定义记上课,未选择上课日期,上下课时间!");
+// } else if( null == teacherId) {
+// return APIResponse.toExceptionResponse("自定义记上课,请选择上课教师!");
+// }
+// return APIResponse.toOkResponse();
+// }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttendItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttendItem.java
new file mode 100644
index 0000000..7cd8b29
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeAttendItem.java
@@ -0,0 +1,26 @@
+package com.ruoyi.course.domain.req;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author :zhangbaoyu
+ * @date :Created in 2020/10/1 19:47
+ */
+@Data
+public class ReqClaTimeAttendItem {
+
+ // 学生
+ private Long studentCourseId;
+
+ // 1:到课 2:请假 3:缺勤
+ private String attendStatus;
+
+ // 备注
+ private String memo;
+
+ // 学生消耗课时
+ private BigDecimal stuLoseHour;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqClaTimeCount.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeCount.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqClaTimeCount.java
rename to ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeCount.java
index bdc700c..a6f68a2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqClaTimeCount.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqClaTimeCount.java
@@ -1,4 +1,4 @@
-package com.ruoyi.course.domain;
+package com.ruoyi.course.domain.req;
import com.ruoyi.course.domain.page.ReqDeptCondition;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqSearchClaTime.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchClaTime.java
similarity index 57%
rename from ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqSearchClaTime.java
rename to ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchClaTime.java
index 5c4b74e..d844a98 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ReqSearchClaTime.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchClaTime.java
@@ -1,19 +1,24 @@
-package com.ruoyi.course.domain;
+package com.ruoyi.course.domain.req;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.ruoyi.course.domain.page.ReqPageBase;
import lombok.Data;
+import org.joda.time.DateTime;
import java.io.Serializable;
+import java.util.HashSet;
/**
* @author :zhangbaoyu
* @date :Created in 2020/9/18 14:45
*/
@Data
-public class ReqSearchClaTime extends ReqPageBase implements Serializable {
+public class ReqSearchClaTime implements Serializable {
// 排课 编号
+ @JsonSerialize(using = ToStringSerializer.class)
private Long courseTimeId;
// 课程
@@ -58,12 +63,13 @@ public class ReqSearchClaTime extends ReqPageBase implements Serializable {
*/
private String orderByType;
-// public void setDiffNowDay(Integer diffNowDay) {
-// this.diffNowDay = diffNowDay;
-// if(null != diffNowDay) {
-// DateTime now = DateTime.now();
-// this.beginDate = now.minusDays(diffNowDay).toString("yyyy-MM-dd");
-// this.endDate = now.plusDays(diffNowDay).toString("yyyy-MM-dd");
-// }
-// }
+
+ public void setDiffNowDay(Integer diffNowDay) {
+ this.diffNowDay = diffNowDay;
+ if(null != diffNowDay) {
+ DateTime now = DateTime.now();
+ this.beginDate = now.minusDays(diffNowDay).toString("yyyy-MM-dd");
+ this.endDate = now.plusDays(diffNowDay).toString("yyyy-MM-dd");
+ }
+ }
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStuCourseSignUp.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStuCourseSignUp.java
new file mode 100644
index 0000000..0922968
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStuCourseSignUp.java
@@ -0,0 +1,28 @@
+package com.ruoyi.course.domain.req;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 报读列表 请求参数
+ * @author :zhangbaoyu
+ * @date :Created in 2020/12/21 20:28
+ */
+@Data
+public class ReqSearchStuCourseSignUp implements Serializable {
+
+ private Long claId;
+
+ // 所属校区
+ private Long departId;
+
+ // 所属课程
+ private Long courseId;
+
+ // 剩余最大天数
+ private Integer minBalanceDay;
+
+ // 剩余最大课时
+ private Integer minBalanceHour;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourse.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourse.java
new file mode 100644
index 0000000..74102e8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourse.java
@@ -0,0 +1,15 @@
+package com.ruoyi.course.domain.req;
+
+import lombok.Data;
+
+/**
+ * 查询学生报读的课程信息
+ * @author :zhangbaoyu
+ * @date :Created in 2020/10/8 22:03
+ */
+@Data
+public class ReqSearchStudentCourse {
+
+ private Long studentId;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourseCla.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourseCla.java
new file mode 100644
index 0000000..ae634ae
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/req/ReqSearchStudentCourseCla.java
@@ -0,0 +1,27 @@
+package com.ruoyi.course.domain.req;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 查询学生课程、班级
+ * @author :zhangbaoyu
+ * @date :Created in 2020-06-20 12:30
+ */
+@Data
+public class ReqSearchStudentCourseCla implements Serializable {
+
+ private Long claId;
+
+ // 所属校区
+ private Long departId;
+
+ // 所属课程
+ private Long courseId;
+
+ private Boolean unChooseCla;
+
+ // 是否生效
+ private Boolean effect;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespBook.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespBook.java
new file mode 100644
index 0000000..9933cb5
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespBook.java
@@ -0,0 +1,41 @@
+package com.ruoyi.course.domain.res;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 预约学员信息
+ */
+@Data
+public class RespBook {
+
+ private Long bookId;
+ private String courseName;
+ private String claName;
+ private String roomName;
+ private String teacherName;
+ private String claDate;
+ private String startTime;
+ /**
+ * 状态 1:待上课 2:已上课
+ */
+ private String status;
+ // 预约
+ private Integer bookAttendCnt;
+ //最多
+ private Integer atClassCnt;
+ //最少
+ private Integer lessCnt;
+ private int bookStatus;
+
+ private Date createTime;
+
+ private Long studentId;
+ private String studentName;
+
+// 性别:0->未知;1->女;2->男
+ private String sex;
+ private String phone;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTime.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTime.java
similarity index 72%
rename from ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTime.java
rename to ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTime.java
index d856ca4..a72c01e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTime.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTime.java
@@ -1,5 +1,8 @@
-package com.ruoyi.course.domain;
+package com.ruoyi.course.domain.res;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.math.BigDecimal;
@@ -13,6 +16,7 @@ import java.util.Date;
@Data
public class RespClaTime {
+ @JsonSerialize(using = ToStringSerializer.class)
private Long courseTimeId;
private Long claId;
@@ -44,13 +48,12 @@ public class RespClaTime {
private String realEndTime;
- // 应到
- private Integer needAttendCnt;
+ // 预约
+ private Integer bookAttendCnt;
// 实到
private Integer realAttendCnt;
- private Integer leaveCnt;
private Integer outCnt;
@@ -67,6 +70,7 @@ public class RespClaTime {
private String memo;
// 最后变更时间 记录上课时间
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date lastUpdateTime;
// 记录人
private String lastUpdateUserName;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTimeCalendar.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java
similarity index 77%
rename from ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTimeCalendar.java
rename to ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java
index c6ea51e..e4b7b4c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/RespClaTimeCalendar.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java
@@ -1,5 +1,6 @@
-package com.ruoyi.course.domain;
+package com.ruoyi.course.domain.res;
+import com.ruoyi.course.domain.ScClaTime;
import lombok.Data;
/**
@@ -11,6 +12,7 @@ import lombok.Data;
public class RespClaTimeCalendar extends ScClaTime {
private String claColor;
+ private String pic;
private String staffName;
@@ -20,7 +22,7 @@ public class RespClaTimeCalendar extends ScClaTime {
// 上课 开始小时
private Integer startHour;
- private Integer studentCount;
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespCourseClaStudent.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespCourseClaStudent.java
new file mode 100644
index 0000000..fa694e3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespCourseClaStudent.java
@@ -0,0 +1,115 @@
+package com.ruoyi.course.domain.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.course.domain.enums.CourseChargeTypeEnum;
+import lombok.Data;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+import org.joda.time.PeriodType;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 班级学员
+ * 用于 班级下学生列表
+ * @author :zhangbaoyu
+ * @date :Created in 2020/9/28 16:51
+ */
+@Data
+public class RespCourseClaStudent {
+
+ private Long studentCourseId;
+
+ private Long claId;
+
+ private Long courseId;
+
+ // 报读校区
+ private String deptName;
+
+ private Long studentId;
+
+ private String studentName;
+
+ private String sex;
+
+ private String phone;
+
+ // 联系人信息
+ private String contactInfo;
+
+ private String chargeType;
+
+ private BigDecimal totalDay;
+ private BigDecimal totalHour;
+ private BigDecimal balanceHour;
+ // 过期课时
+ private BigDecimal expireHour;
+
+ // 即将生效的 总天数
+ private BigDecimal comingEffectDay;
+
+ /**
+ * 按时间收费 当期 到期时间
+ * 当前生效周期到期时间
+ */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date endDate;
+
+ // 状态
+ private String status;
+
+ // 首次报名时间
+ private Date firstSignTime;
+
+ // 最后一次续费时间
+ private Date lastSignTime;
+
+ /**
+ * 获取剩余天数
+ * @return
+ */
+ public BigDecimal getBalanceDays() {
+ try {
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 无生效周期
+ return comingEffectDay;
+ } else {
+ // 有生效周期
+ Period period = new Period(DateTime.now(), new DateTime(this.endDate), PeriodType.days());
+ return new BigDecimal(period.getDays() + 1).add(comingEffectDay);
+ }
+ } else {
+ return BigDecimal.ZERO;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return BigDecimal.ZERO;
+ }
+ }
+
+ /**
+ * 按时间收费 当前时间 是否在缴费周期内(是否有效)
+ * @return
+ */
+ public boolean isEffect() {
+ try{
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 未生效
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespMemberTypeCourses.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespMemberTypeCourses.java
new file mode 100644
index 0000000..238890e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespMemberTypeCourses.java
@@ -0,0 +1,76 @@
+package com.ruoyi.course.domain.res;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Date;
+
+/**
+ * 会员卡项-课程 内容信息
+ */
+@Data
+public class RespMemberTypeCourses {
+
+
+
+ private Long memberCardId;
+
+ private String cardNo;
+
+ private BigDecimal remainingTotalFee;
+
+ private LocalDate expiryDate;
+
+ private BigDecimal remainingCount;
+
+ private String chargeType;
+
+ /**
+ * 卡类型ID
+ */
+ private Long cardTypeId;
+
+ /**
+ * 卡类型名称
+ */
+ private String cardName;
+
+ /**
+ * 课程类型ID
+ */
+ private Long courseTypeId;
+
+ /**
+ * 课程类型名称
+ */
+ private String courseType;
+
+ /**
+ * 课程ID
+ */
+ private Long courseId;
+
+ /**
+ * 课程名称
+ */
+ private String courseName;
+
+
+ /**
+ * 划扣次数
+ */
+ private BigDecimal deductCnt;
+
+ /**
+ * 划扣金额
+ */
+ private BigDecimal deductFee;
+ private BigDecimal tuitionFee;
+
+ //限制约课次数 1不限次数 2限制约课次数
+ private String restrictedNum;
+ private String bookTime;//限制约课时间范围 每天 每周 每月
+ private Integer bookNum;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespOrderForApp.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespOrderForApp.java
new file mode 100644
index 0000000..1a51a3f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespOrderForApp.java
@@ -0,0 +1,29 @@
+package com.ruoyi.course.domain.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ *
+ */
+@Data
+public class RespOrderForApp {
+
+ private String saleStaffName;
+ private String studentName;
+ private BigDecimal receiptFee;//实际支付
+ private Long commissionPlansId;//佣金方案
+ private String courseName;
+ private String detailTag;//类型 1新报 2续报
+ private String dateUnit;//时间周期 天/月/季/年
+ private BigDecimal buyCount;//购买数量
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java
new file mode 100644
index 0000000..bff138b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java
@@ -0,0 +1,29 @@
+package com.ruoyi.course.domain.res;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 预约学员信息
+ */
+@Data
+public class RespStuBook {
+
+ private Long studentId;
+ private Long bookId;
+
+ private String studentName;
+
+// 性别:0->未知;1->女;2->男
+ private String sex;
+ private String phone;
+ private int bookStatus;
+ private Date createTime;
+ private int checkIn;
+ private Date checkInTime;
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuCourseSignUpStudent.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuCourseSignUpStudent.java
new file mode 100644
index 0000000..2460166
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuCourseSignUpStudent.java
@@ -0,0 +1,122 @@
+package com.ruoyi.course.domain.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.course.domain.enums.CourseChargeTypeEnum;
+import lombok.Data;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+import org.joda.time.PeriodType;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 学员报读列表
+ * @author :zhangbaoyu
+ * @date :Created in 2020/12/21 20:28
+ */
+@Data
+public class RespStuCourseSignUpStudent {
+
+ private Long studentCourseId;
+
+ private Long claId;
+
+ private String claName;
+
+ private Long courseId;
+
+ private String courseName;
+
+ // 报读校区
+ private String deptName;
+
+ private Long studentId;
+
+ private String studentName;
+
+ private String sex;
+
+ private String phone;
+
+ // 联系人信息
+ private String contactInfo;
+
+ private String chargeType;
+
+ private BigDecimal totalHour;
+ private BigDecimal balanceHour;
+ // 过期课时
+ private BigDecimal expireHour;
+
+ // 总学费
+ private BigDecimal totalFee;
+ // 剩余学费
+ private BigDecimal balanceFee;
+ // 过期学费
+ private BigDecimal expireFee;
+
+ private BigDecimal totalDay;
+
+ private String orderDetail;
+
+ // 即将生效的 总天数
+ private BigDecimal comingEffectDay;
+
+ /**
+ * 按时间收费 当期 到期时间
+ * 当前生效周期到期时间
+ */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date endDate;
+
+ // 状态
+ private String status;
+
+ /**
+ * 获取剩余天数
+ * @return
+ */
+ public BigDecimal getBalanceDays() {
+ try {
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 无生效周期
+ return comingEffectDay;
+ } else {
+ // 有生效周期
+ Period period = new Period(DateTime.now(), new DateTime(this.endDate), PeriodType.days());
+ return new BigDecimal(period.getDays() + 1).add(comingEffectDay);
+ }
+ } else {
+ return BigDecimal.ZERO;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return BigDecimal.ZERO;
+ }
+ }
+
+ /**
+ * 按时间收费 当前时间 是否在缴费周期内(是否有效)
+ * @return
+ */
+ public boolean isEffect() {
+ try{
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 未生效
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStudentCourse.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStudentCourse.java
new file mode 100644
index 0000000..4bdf95c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStudentCourse.java
@@ -0,0 +1,103 @@
+package com.ruoyi.course.domain.res;
+
+import com.ruoyi.course.domain.enums.CourseChargeTypeEnum;
+import lombok.Data;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+import org.joda.time.PeriodType;
+
+import java.math.BigDecimal;
+
+/**
+ * 学生 报读 课程列表
+ * @author :zhangbaoyu
+ * @date :Created in 2020/10/8 22:02
+ */
+@Data
+public class RespStudentCourse {
+
+ private Long studentCourseId;
+
+ private String courseName;
+
+ private String chargeType;
+
+ private BigDecimal totalDay;
+
+ private BigDecimal totalHour;
+
+ private BigDecimal balanceHour;
+
+ // 过期课时
+ private BigDecimal expireHour;
+
+ private BigDecimal totalFee;
+
+ private String status;
+
+ private Long studentId;
+
+ private String studentName;
+
+ private String deptName;
+
+ private String claName;
+
+ private String orderDetail;
+
+ // 即将生效的 总天数
+ private BigDecimal comingEffectDay;
+
+ /**
+ * 按时间收费 当期 到期时间
+ * 当前生效周期到期时间
+ */
+ private String endDate;
+
+ /**
+ * 获取剩余天数
+ * @return
+ */
+ public BigDecimal getBalanceDays() {
+ try {
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 无生效周期
+ return comingEffectDay;
+ } else {
+ // 有生效周期
+ Period period = new Period(DateTime.now(), new DateTime(this.endDate), PeriodType.days());
+ return new BigDecimal(period.getDays() + 1).add(comingEffectDay);
+ }
+ } else {
+ return BigDecimal.ZERO;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return BigDecimal.ZERO;
+ }
+ }
+
+ /**
+ * 按时间收费 当前时间 是否在缴费周期内(是否有效)
+ * @return
+ */
+ public boolean isEffect() {
+ try{
+ if(CourseChargeTypeEnum.DATE.getChargeType().equals(chargeType)) {
+ if(null == this.endDate) {
+ // 未生效
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java
new file mode 100644
index 0000000..b5a9e79
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java
@@ -0,0 +1,71 @@
+package com.ruoyi.course.domain.time;
+
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.course.domain.res.RespClaTimeCalendar;
+import lombok.Data;
+import springfox.documentation.spring.web.json.Json;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 预约排课信息
+ */
+@Data
+public class ClaTimeBookItem {
+
+ @JsonSerialize(using = ToStringSerializer.class)
+ private Long courseTimeId;
+ private Long bookId;
+
+ private String claName;
+
+ private String storeName;
+
+ private String pic;
+
+ // 日期
+ private String claDate;
+
+ // 星期
+ private String weekDay;
+
+ private String startTime;
+
+ private String endTime;
+
+ // 教室
+ private String roomName;
+
+ private String claColor;
+
+ // 上课状态 1:待上课 2:已上课
+ private String claTimeStatus;
+ //预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;
+ private int bookStatus;
+
+ //预约时间
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date createTime;
+
+ private String code;
+ private String qrCode;
+
+ private String courseName;
+
+ //老师信息
+ private Long teacherId;
+ private String teacherName;
+
+ //*0未签到 1签到
+ private int checkIn;
+
+ //{status:1,time:2025-08-05 12:00:00}
+ private List
*
- * @author zhangby
- * @since 2020-09-16
+ *
+ *
*/
public interface ScClaTimeMapper extends BaseMapper {
@@ -25,20 +32,25 @@ public interface ScClaTimeMapper extends BaseMapper {
*/
List selectListForCalendar(ReqSearchClaTime searchClaTime);
- /**
- * 获取上课记录
- *
- * @param searchClaTime
- * @return
- */
- List selectListForAttend(@Param("searchClaTime") ReqSearchClaTime searchClaTime, @Param("page") Page page);
- /**
- * 数量
- *
- * @param reqClaTimeCount
- * @return
- */
- Integer selectClaTimeCount(ReqClaTimeCount reqClaTimeCount);
-}
+ List getCourseList(@Param("date")String date,
+ @Param("courseTimeId")Long courseTimeId,
+ @Param("deptId")Long deptId
+ );
+
+
+ List getCourseBookStudent(Long courseTimeId);
+
+ List getCourseCountByStoreManager(@Param("staffId")Long staffId, @Param("beginTime")String beginTime, @Param("endTime")String endTime);
+ List getStudentsBySaleStaff(Long staffId);
+ List myDealOrder(@Param("staffId")Long staffId, @Param("beginTime")String beginTime, @Param("endTime")String endTime);
+ List getOrdersForStore(@Param("deptId")Long deptId, @Param("beginTime")String beginTime, @Param("endTime")String endTime);
+
+ List getBookListForTeacher(@Param("teacherId")Long teacherId,
+ @Param("beginTime")String beginTime,
+ @Param("endTime")String endTime);
+ List getBookListForManager(@Param("deptId")Long deptId,
+ @Param("beginTime")String beginTime,
+ @Param("endTime")String endTime);
+ }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCommissionPlansMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCommissionPlansMapper.java
new file mode 100644
index 0000000..782a58f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCommissionPlansMapper.java
@@ -0,0 +1,17 @@
+package com.ruoyi.course.mapper;
+
+import com.ruoyi.course.domain.ScCommissionPlans;
+import com.ruoyi.course.domain.ScStudent;
+
+/**
+ *
+ * 佣金方案 Mapper 接口
+ *
+ *
+ *
+ * @since 2020-04-27 07:13:40
+ */
+public interface ScCommissionPlansMapper extends com.baomidou.mybatisplus.core.mapper.BaseMapper {
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseClaMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseClaMapper.java
new file mode 100644
index 0000000..8f4b1d1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseClaMapper.java
@@ -0,0 +1,56 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.course.domain.ScCourseCla;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 课程班级信息 Mapper 接口
+ *
+ *
+ *
+ * @since 2020-03-17 01:11:06
+ */
+public interface ScCourseClaMapper extends BaseMapper {
+
+// /**
+// * 班级列表
+// *
+// * @param reqSearchScCourseCla
+// * @param page
+// * @return
+// */
+// List selectClaList(@Param("reqSearchScCourseCla")ReqSearchScCourseCla reqSearchScCourseCla, @Param("page")RespPage page);
+//
+// /**
+// * 班级select
+// * @param courseClaSelect
+// * @return
+// */
+// List selectForSelect(ReqCourseClaSelect courseClaSelect);
+//
+// /**
+// * 班级数量
+// * @param reqClaCount
+// * @return
+// */
+// Integer selectClaCount(ReqClaCount reqClaCount);
+//
+// /**
+// * 班级数量
+// * @param tenantId
+// * @return
+// */
+// @SqlParser(filter = true)
+// Integer selectTenantClaCount(String tenantId);
+//
+// /**
+// * 班级在读学员数量
+// * @param claId
+// * @return
+// */
+// Integer selectStudentCnt(Long claId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseMapper.java
new file mode 100644
index 0000000..0bad02a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScCourseMapper.java
@@ -0,0 +1,57 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.course.domain.ScCourse;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 课程信息 Mapper 接口
+ *
+ *
+
+ */
+public interface ScCourseMapper extends BaseMapper {
+
+// /**
+// * 获取课程列表
+// * @param reqSearchScCourse
+// * @param page
+// * @return
+// */
+// List selectCourseList(@Param("reqSearchScCourse") ReqSearchScCourse reqSearchScCourse, @Param("page") RespPage page);
+//
+// /**
+// * 获取课程列表
+// * 包含学生当前课程状态
+// * @param reqSearchScCourse
+// * @param page
+// * @return
+// */
+// List selectCourseListWithStudentCourse(@Param("reqSearchScCourse") ReqSearchScCourse reqSearchScCourse, @Param("page") RespPage page);
+//
+// /**
+// * 导出课程
+// * @param reqSearchScCourse
+// * @return
+// */
+// List selectCourseForExport(@Param("reqSearchScCourse") ReqSearchScCourse reqSearchScCourse);
+//
+// /**
+// * 课程数量
+// * @param reqDeptCondition
+// * @return
+// */
+// Integer selectCourseCount(ReqDeptCondition reqDeptCondition);
+//
+// /**
+// * 租户下课程数量
+// * @param tenantId
+// * @return
+// */
+// @SqlParser(filter = true)
+// Integer selectTenantCourseCount(String tenantId);
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScMemberCardsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScMemberCardsMapper.java
new file mode 100644
index 0000000..d710313
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScMemberCardsMapper.java
@@ -0,0 +1,26 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.course.domain.ScMemberCard;
+import com.ruoyi.course.domain.res.RespMemberTypeCourses;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 排课信息 Mapper 接口
+ *
+ *
+ *
+ *
+ */
+public interface ScMemberCardsMapper extends BaseMapper {
+
+ List getByMemberId(@Param("memberId") Long memberId, @Param("tenantId") String tenantId,@Param("claDate") String claDate);
+ List getCourseDetail(@Param("courseId") Long courseId,@Param("teacherId") Long teacherId, @Param("cards") List cards);
+ RespMemberTypeCourses getMemberTypeById(@Param("typeId") Long typeId);
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScRoomMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScRoomMapper.java
new file mode 100644
index 0000000..95bc599
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScRoomMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.course.mapper;
+
+import com.ruoyi.course.domain.ScRoom;
+import com.ruoyi.course.domain.ScStudent;
+
+/**
+ *
+ * 教室信息 Mapper 接口
+ *
+ *
+ */
+public interface ScRoomMapper extends com.baomidou.mybatisplus.core.mapper.BaseMapper {
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseLogMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseLogMapper.java
new file mode 100644
index 0000000..835957f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseLogMapper.java
@@ -0,0 +1,20 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.course.domain.ScStudentCourseLog;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 课程缴费扣费记录 Mapper 接口
+ *
+ *
+ *
+ * @since 2020-12-17
+ */
+public interface ScStudentCourseLogMapper extends BaseMapper {
+
+ }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java
new file mode 100644
index 0000000..46730f9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java
@@ -0,0 +1,101 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.course.domain.ScStudentCourse;
+import com.ruoyi.course.domain.req.ReqSearchStuCourseSignUp;
+import com.ruoyi.course.domain.req.ReqSearchStudentCourse;
+import com.ruoyi.course.domain.req.ReqSearchStudentCourseCla;
+import com.ruoyi.course.domain.res.RespCourseClaStudent;
+import com.ruoyi.course.domain.res.RespStuCourseSignUpStudent;
+import com.ruoyi.course.domain.res.RespStudentCourse;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 学生课程 Mapper 接口
+ *
+ *
+ *
+ *
+ */
+public interface ScStudentCourseMapper extends BaseMapper {
+
+ /**
+ * 学生在读课程名称
+ * @param studentId
+ * @return
+ */
+ List selectStudentCourseNameList(Long studentId);
+
+ /**
+ * 学生报读校区
+ * @param studentId
+ * @return
+ */
+ List selectStudentDeptNameList(Long studentId);
+
+ /**
+ * 课程、班级 学生列表
+ *
+ * @param reqSearchStudentCourseCla
+ * @param page
+ * @return
+ */
+ List selectStudentList(@Param("reqSearchStudentCourseCla") ReqSearchStudentCourseCla reqSearchStudentCourseCla, @Param("page")Page page);
+
+ /**
+ * 应到人数
+ * @param claId
+ * @return
+ */
+ int selectClaNeedAttendCnt(Long claId);
+
+ /**
+ * 学生报读课程列表
+ * @param searchStudentCourse
+ * @return
+ */
+ List selectStudentCourseList(ReqSearchStudentCourse searchStudentCourse);
+
+ /**
+ * 当报读课程总课时、总费用 为0时,删除报读
+ * @param studentCourseId
+ * @return
+ */
+ int deleteWhenTotalHourZeroForInvalid(Long studentCourseId);
+
+ /**
+ * 当报读课程总天数、总费用 为0时,删除报读
+ * @param studentCourseId
+ * @return
+ */
+ int deleteWhenTotalDayZeroForInvalid(Long studentCourseId);
+
+ /**
+ * 在读学生 剩余天数 小于 minBalanceDay 的数量
+ * 未生效天数 + 生效剩余天数 < minBalanceDay
+ * @param minBalanceDay 最小剩余天数
+ * @return
+ */
+ Integer selectWillExpireDateCount(Integer minBalanceDay);
+
+ /**
+ * 在读学生 剩余课时 小于 minBalanceHour 的数量
+ * 剩余课时 - 过期课时 < minBalanceHour
+ * @param minBalanceHour 最小剩余课时数
+ * @return
+ */
+ Integer selectWillExpireHourCount(Integer minBalanceHour);
+
+ /**
+ * 学生报读列表
+ *
+ * @param reqSearchStuCourseSignUp
+ * @param page
+ * @return
+ */
+ List selectStudentSignUpList(@Param("reqSearchStuCourseSignUp") ReqSearchStuCourseSignUp reqSearchStuCourseSignUp, @Param("page")Page page);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseOrderMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseOrderMapper.java
new file mode 100644
index 0000000..df349ab
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseOrderMapper.java
@@ -0,0 +1,72 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.course.domain.ScStudentCourseOrder;
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ *
+ * 学生课程关联订单 Mapper 接口
+ *
+ *
+ *
+ *
+ */
+public interface ScStudentCourseOrderMapper extends BaseMapper {
+
+
+
+ /**
+ * 校验按时间收费 收费日期是否存在覆盖
+ *
+ * @param studentId
+ * @param courseId
+ * @param beginDate
+ * @param endDate
+ * @return
+ */
+ int checkDateCover(@Param("studentId") Long studentId, @Param("courseId") Long courseId,
+ @Param("beginDate") String beginDate, @Param("endDate") String endDate);
+
+ /**
+ * 获取需扣减课时的订单
+ * @param studentCourseId
+ * @return
+ */
+ ScStudentCourseOrder selectSubtractHourOrder(Long studentCourseId);
+
+ /**
+ * 当前生效 按时间 缴费订单
+ * @param studentCourseId
+ * @return
+ */
+ ScStudentCourseOrder selectNowValidDateOrder(Long studentCourseId);
+
+ /**
+ * 获取可扣减课时的订单列表
+ * @param studentCourseId
+ * @return
+ */
+ List selectSubtractHourOrderList(Long studentCourseId);
+
+ /**
+ * 按课时收费 订单列表,按时间倒叙
+ * @param studentCourseId
+ * @return
+ */
+ List selectRecoverHourOrderList(Long studentCourseId);
+
+ /**
+ * 扣减课时
+ * @param courseOrderId
+ * @param newHour
+ * @param oldHour
+ * @return
+ */
+ int updateSubtractHour(@Param("courseOrderId") Long courseOrderId,
+ @Param("newHour") BigDecimal newHour,
+ @Param("oldHour") BigDecimal oldHour);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentMapper.java
new file mode 100644
index 0000000..efd290a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentMapper.java
@@ -0,0 +1,20 @@
+package com.ruoyi.course.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.course.domain.ScStudent;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * 学生基本信息 Mapper 接口
+ *
+ *
+ *
+ * @since 2020-04-27 07:13:40
+ */
+public interface ScStudentMapper extends com.baomidou.mybatisplus.core.mapper.BaseMapper {
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseClaService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseClaService.java
new file mode 100644
index 0000000..30eac8a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseClaService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.course.domain.ScCourseCla;
+
+/**
+ *
+ * 课程班级信息 服务类
+ *
+ *
+ *
+ * @since 2020-03-17 01:11:06
+ */
+public interface IScCourseClaService extends IService {
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseService.java
new file mode 100644
index 0000000..939537c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScCourseService.java
@@ -0,0 +1,15 @@
+package com.ruoyi.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.course.domain.ScCourse;
+
+/**
+ *
+ * 课程信息 服务类
+ *
+ *
+
+ */
+public interface IScCourseService extends IService {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentCourseOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentCourseOrderService.java
new file mode 100644
index 0000000..00e6238
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentCourseOrderService.java
@@ -0,0 +1,68 @@
+package com.ruoyi.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.course.domain.ScStudentCourseOrder;
+
+import java.math.BigDecimal;
+
+/**
+ *
+ * 学生课程关联订单 服务类
+ *
+ *
+ */
+public interface IScStudentCourseOrderService extends IService {
+ /**
+ * 校验按时间收费 收费日期是否存在覆盖
+ *
+ * @param studentId
+ * @param courseId
+ * @param beginDate
+ * @param endDate
+ * @return
+ */
+ boolean checkDateCover(Long studentId, Long courseId,
+ String beginDate, String endDate);
+
+ /**
+ * 获取应扣课时订单信息
+ * @param studentCourseId
+ * @return
+ */
+ ScStudentCourseOrder getSubtractHourOrder(Long studentCourseId);
+
+ /**
+ * 当前生效 按时间 缴费订单
+ * @param studentCourseId
+ * @return
+ */
+ ScStudentCourseOrder getNowValidDateOrder(Long studentCourseId);
+
+
+ /**
+ * 课程订单扣减课时
+ * @param studentCourseId
+ * @param loseHour
+ * @return 扣减总课时费用
+ */
+ BigDecimal subtractCourseOrderBalanceHour(Long studentCourseId, BigDecimal loseHour);
+
+ /**
+ * 课程订单 恢复课时
+ * 当删除上课记录时调用
+ * @param studentCourseId
+ * @param recoverHour 恢复课时数量
+ * @return
+ */
+ void recoverOrderLoseHour(Long studentCourseId, BigDecimal recoverHour);
+
+ /**
+ * 更新订单 剩余课时
+ * @param courseOrderId
+ * @param newBalanceHour
+ * @param oldBalanceHour
+ */
+ void updateBalanceHour(Long courseOrderId, BigDecimal newBalanceHour, BigDecimal oldBalanceHour);
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentService.java
new file mode 100644
index 0000000..46c3301
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/IScStudentService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.course.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.course.domain.ScStudent;
+
+import java.util.List;
+
+/**
+ *
+ * 学生基本信息 服务类
+ *
+ *
+ *
+ * @since 2020-04-27 07:13:40
+ */
+public interface IScStudentService extends IService {
+
+ Long getStudentByAppUserId(Long appUserId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeAttendService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeAttendService.java
new file mode 100644
index 0000000..7dfea12
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeAttendService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.course.service;
+
+
+import com.ruoyi.course.domain.ScClaTimeAttend;
+import com.ruoyi.course.domain.req.ReqClaTimeCount;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ *
+ * 上课出勤表 服务类
+ *
+ *
+ *
+ * @since 2020-09-30 02:33:26
+ */
+public interface ScClaTimeAttendService extends com.baomidou.mybatisplus.extension.service.IService {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java
index 95efed5..a973c84 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java
@@ -1,11 +1,44 @@
package com.ruoyi.course.service;
import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.course.domain.ReqSearchClaTime;
+import com.ruoyi.RestResponse;
+import com.ruoyi.course.domain.req.ReqSearchClaTime;
import com.ruoyi.course.domain.ScClaTime;
+import com.ruoyi.course.domain.time.ClaTimeBookItem;
+import com.ruoyi.course.domain.time.ClaTimeCalendarItem;
import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar;
-import com.ruoyi.mall.domain.ProductCategory;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
public interface ScClaTimeService extends IService {
RespBusinessClaTimeCalendar searchListForCalendar(ReqSearchClaTime reqSearchClaTime);
+
+ RestResponse getCourseListByDate(String date);
+
+ RestResponse bookCourse(@RequestBody ReqSearchClaTime searchClaTime);
+
+ Map> bookCourseList();
+
+ RestResponse bookCourseDetail(Long bookId);
+
+ RestResponse cancelCourse(Long courseTimeId);
+
+ RestResponse courseTimeDetail(Long courseTimeId);
+ RestResponse appointmentListForTeacher();
+ RestResponse appointmentListForManager();
+ RestResponse checkAppointment(Long courseTimeId,int bookStatus);
+
+ RestResponse confirmClass(Long courseTimeId,String startTime,String endTime);
+
+ RestResponse checkIn(Map map);
+
+ RestResponse teacherClaTotal(String time);
+ RestResponse teacherFeeTotal(String time);
+ RestResponse commissionTotal(String time);
+ RestResponse salesInformation(String time);
+ RestResponse claRoomFee(String time);
+ RestResponse myClient();
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScStudentCourseService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScStudentCourseService.java
new file mode 100644
index 0000000..16bf4e2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScStudentCourseService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.RestResponse;
+import com.ruoyi.course.domain.ScClaTime;
+import com.ruoyi.course.domain.ScStudentCourse;
+import com.ruoyi.course.domain.req.ReqClaTimeAttend;
+import com.ruoyi.course.domain.req.ReqSearchClaTime;
+import com.ruoyi.course.domain.time.ClaTimeBookItem;
+import com.ruoyi.course.domain.time.ClaTimeCalendarItem;
+import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public interface ScStudentCourseService extends IService {
+ RestResponse claTimeAttend(ReqClaTimeAttend reqClaTimeAttend);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ContextServicelmpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ContextServicelmpl.java
deleted file mode 100644
index 7b0248e..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ContextServicelmpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.course.service.impl;
-
-import cn.hutool.core.date.DateField;
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.course.domain.Context;
-import com.ruoyi.course.domain.ReqSearchClaTime;
-import com.ruoyi.course.domain.RespClaTimeCalendar;
-import com.ruoyi.course.domain.time.ClaTimeCalendarItem;
-import com.ruoyi.course.domain.time.ClaTimeColumnTitle;
-import com.ruoyi.course.domain.time.ClaTimeContainer;
-import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar;
-import com.ruoyi.course.mapper.ContextMapper;
-import com.ruoyi.course.mapper.ScClaTimeMapper;
-import org.apache.commons.compress.utils.Lists;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Service
-public class ContextServicelmpl extends ServiceImpl {
-
-
-
- public List getList(Map map){
- List list = baseMapper.findList(map);
- return list;
- }
-
- public Context getOne(Map map){
- Context context = baseMapper.getOne(map);
- return context;
- }
-
-
-
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseClaServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseClaServiceImpl.java
new file mode 100644
index 0000000..ee0249f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseClaServiceImpl.java
@@ -0,0 +1,17 @@
+package com.ruoyi.course.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.course.domain.ScClaTimeAttend;
+import com.ruoyi.course.domain.ScCourseCla;
+import com.ruoyi.course.mapper.ScClaTimeAttendMapper;
+import com.ruoyi.course.mapper.ScCourseClaMapper;
+import com.ruoyi.course.service.IScCourseClaService;
+import com.ruoyi.course.service.ScClaTimeAttendService;
+import org.springframework.stereotype.Service;
+
+
+@Service
+public class IScCourseClaServiceImpl extends ServiceImpl implements IScCourseClaService {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseServiceImpl.java
new file mode 100644
index 0000000..3cc440e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/IScCourseServiceImpl.java
@@ -0,0 +1,17 @@
+package com.ruoyi.course.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.course.domain.ScCourse;
+import com.ruoyi.course.domain.ScCourseCla;
+import com.ruoyi.course.mapper.ScCourseClaMapper;
+import com.ruoyi.course.mapper.ScCourseMapper;
+import com.ruoyi.course.service.IScCourseClaService;
+import com.ruoyi.course.service.IScCourseService;
+import org.springframework.stereotype.Service;
+
+
+@Service
+public class IScCourseServiceImpl extends ServiceImpl implements IScCourseService {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeAttendServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeAttendServiceImpl.java
new file mode 100644
index 0000000..d899277
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeAttendServiceImpl.java
@@ -0,0 +1,24 @@
+package com.ruoyi.course.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.course.domain.ScClaTime;
+import com.ruoyi.course.domain.ScClaTimeAttend;
+import com.ruoyi.course.mapper.ScClaTimeAttendMapper;
+import com.ruoyi.course.mapper.ScClaTimeMapper;
+import com.ruoyi.course.service.ScClaTimeAttendService;
+import com.ruoyi.course.service.ScClaTimeService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 上课出勤表 服务类
+ *
+ *
+ *
+ * @since 2020-09-30 02:33:26
+ */
+@Service
+public class ScClaTimeAttendServiceImpl extends ServiceImpl implements ScClaTimeAttendService {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java
index de1668b..e13c677 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java
@@ -2,25 +2,49 @@ package com.ruoyi.course.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.RestResponse;
+import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.constant.Constants;
-import com.ruoyi.course.domain.ReqSearchClaTime;
-import com.ruoyi.course.domain.RespClaTimeCalendar;
-import com.ruoyi.course.domain.ScClaTime;
-import com.ruoyi.course.domain.time.ClaTimeCalendarItem;
-import com.ruoyi.course.domain.time.ClaTimeColumnTitle;
-import com.ruoyi.course.domain.time.ClaTimeContainer;
-import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar;
-import com.ruoyi.course.mapper.ScClaTimeMapper;
+import com.ruoyi.common.core.domain.entity.AppUser;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.AppLoginUser;
+import com.ruoyi.common.utils.*;
+import com.ruoyi.common.utils.sign.Base64;
+import com.ruoyi.course.domain.*;
+import com.ruoyi.course.domain.enums.ClaTimeAttendStatusEnums;
+import com.ruoyi.course.domain.enums.ClaTimeStatusEnums;
+import com.ruoyi.course.domain.enums.CourseChargeTypeEnum;
+import com.ruoyi.course.domain.enums.LogTypeEnum;
+import com.ruoyi.course.domain.req.ReqSearchClaTime;
+import com.ruoyi.course.domain.res.*;
+import com.ruoyi.course.domain.time.*;
+import com.ruoyi.course.mapper.*;
+import com.ruoyi.course.service.IScStudentCourseOrderService;
+import com.ruoyi.course.service.ScClaTimeAttendService;
import com.ruoyi.course.service.ScClaTimeService;
-import com.ruoyi.mall.domain.ProductCategory;
-import com.ruoyi.mall.mapper.ProductCategoryMapper;
-import com.ruoyi.mall.service.ProductCategoryService;
+import com.ruoyi.im.domain.Friend;
+import com.ruoyi.system.domain.SysTeacher;
+import com.ruoyi.system.service.ISysDeptService;
+import com.ruoyi.system.service.SysTeacherService;
+import com.ruoyi.system.service.impl.SysUserServiceImpl;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -28,6 +52,51 @@ public class ScClaTimeServiceImpl extends ServiceImpl dateList=DateUtil.rangeToList(cycleBegin
, cycleEnd
, DateField.DAY_OF_YEAR);
- //todo 表頭list
- // time 07-17l
// // 日历数据 格式为:时间->星期->课程
Map>> claTimeCalendarMap = new HashMap();
Constants.CLA_TIME_MAP.forEach((claTimeKey, claTimeValue) -> {
- Map> weekDayMap = new HashMap();
+ Map> halfMonthDayMap = new HashMap();
for (int i = 0; i < dateList.size(); i++) {
List claTimeArrayList = Lists.newArrayList();
- weekDayMap.put(i+1, claTimeArrayList);
+ halfMonthDayMap.put(i+1, claTimeArrayList);
}
- claTimeCalendarMap.put(claTimeKey, weekDayMap);
+ claTimeCalendarMap.put(claTimeKey, halfMonthDayMap);
});
-
+ reqSearchClaTime.setBeginDate(DateUtil.format(cycleBegin,"yyyy-MM-dd"));
+ reqSearchClaTime.setEndDate(DateUtil.format(cycleEnd,"yyyy-MM-dd"));
// 获取排课信息
List respClaTimeList = claTimeMapper.selectListForCalendar(reqSearchClaTime);
// 将排课信息 入到 claTimeCalendarMap
respClaTimeList.forEach(item -> {
- Integer weekDay = item.getWeekDay();
+ DateTime day=new DateTime(item.getClaDate());
+ Integer halfMonthDay=dateList.indexOf(day)+1;
Integer startHour = item.getStartHour();
if (claTimeCalendarMap.containsKey(startHour)) {
- claTimeCalendarMap.get(startHour).get(weekDay).add(item);
+ claTimeCalendarMap.get(startHour).get(halfMonthDay).add(item);
} else if (claTimeCalendarMap.containsKey(startHour - 1)) {
// 每两个小时 一个上课时段,所以-1
- claTimeCalendarMap.get(startHour - 1).get(weekDay).add(item);
+ claTimeCalendarMap.get(startHour - 1).get(halfMonthDay).add(item);
}
});
@@ -87,7 +163,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl> claTimeWeekDayMap = new HashMap();
claTimeMap.forEach((weekDayKey, list) -> {
- // 排课数量
+
if (columnTitleTimeCountMap.containsKey(weekDayKey)) {
columnTitleTimeCountMap.put(weekDayKey, columnTitleTimeCountMap.get(weekDayKey) + list.size());
} else {
@@ -120,13 +196,17 @@ public class ScClaTimeServiceImpl extends ServiceImpl columnTitles = Lists.newArrayList();
+ int i=1;
while (cycleBegin.before(cycleEnd)) {
int dayOfWeek = DateUtil.dayOfWeek(cycleBegin);
+// Date new DateTime(DateUtil.format(cycleBegin,"yyyy-MM-dd"));
+ int dayOfcycle = dateList.indexOf(cycleBegin)+1;
+
ClaTimeColumnTitle claTimeColumnTitle = new ClaTimeColumnTitle();
claTimeColumnTitle.setWeekName(Constants.WEEK_DAY_MAP.get(dayOfWeek));
- claTimeColumnTitle.setDay(DateUtil.format(cycleBegin,"MM-dd"));
- claTimeColumnTitle.setCount(columnTitleTimeCountMap.get(dayOfWeek));
+ claTimeColumnTitle.setDay(DateUtil.format(cycleBegin,"yyyy-MM-dd"));
+ claTimeColumnTitle.setCount(columnTitleTimeCountMap.get(dayOfcycle));
columnTitles.add(claTimeColumnTitle);
cycleBegin = DateUtil.offsetDay(cycleBegin,1);
@@ -135,4 +215,956 @@ public class ScClaTimeServiceImpl extends ServiceImpl list=claTimeMapper.getCourseList(date,null,appUser.getVisitStore());
+ return new RestResponse().setData(list);
+ }
+
+ /**
+ * 预约课程
+ * @param searchClaTime
+ * @return
+ */
+ @Override
+ @Transactional
+ public RestResponse bookCourse(@RequestBody ReqSearchClaTime searchClaTime){
+ Long studentId=SecurityUtils.getAppLoginUser().getStudentId();
+ Long courseTimeId=searchClaTime.getCourseTimeId();//某节课的编号
+ ScClaTime claTim=claTimeMapper.selectById(courseTimeId);
+
+ if (ObjectUtil.isEmpty(claTim)){
+ return new RestResponse().setSuccess(false).setMessage("课程编号有误,无法预约");
+ }
+
+ if (claTim.getBookAttendCnt().equals(claTim.getAtClassCnt())){
+ return new RestResponse().setSuccess(false).setMessage("课程预约已满,无法预约");
+ }
+
+ //状态 1:待上课 2:已上课
+ if (claTim.getStatus().equals(2)){
+ return new RestResponse().setSuccess(false).setMessage("课程已开始上课,无法预约!");
+ }
+
+ ScCourseCla courseCla= claMapper.selectById(claTim.getClaId());
+
+ //获取当前用户 在租户所拥有的会员卡
+ List cardList=memberCardsMapper.getByMemberId(studentId,courseCla.getTenantId(),claTim.getClaDate());
+
+
+ if (cardList.size()==0){
+ return new RestResponse().setSuccess(false).setMessage("会员卡失效 或 未在本机构开通会员卡,请联系教练预约!");
+ }
+
+
+ List cardIds=cardList.stream().map(it -> it.getId()).collect(Collectors.toList());
+ List course= memberCardsMapper.getCourseDetail(courseCla.getCourseId(),claTim.getTeacherId(),cardIds);
+
+ //改:
+ // 1.会员卡排序 按天 -> 按课时 -> 按储值
+ // 2.判断是否含有本课程类型+教练 sql
+ // 3.判断约课次数
+ // 4.限制课程 sql
+
+
+
+
+
+ if (course.size()==0){
+ return new RestResponse().setSuccess(false).setMessage("会员卡不包含本次课程,请联系教练预约!");
+ }
+
+ // 校验预约次数 预约教师
+
+ //消费优先级 : 时间卡 > 次数卡 > 储值卡
+ Map> courseMap = course.stream().collect(Collectors.groupingBy(RespMemberTypeCourses::getChargeType));
+ int flag=0;//1次数卡次数不够用 2储值卡余额不够 3 两个卡都不够
+ RespMemberTypeCourses selected=new RespMemberTypeCourses();
+
+ if (ObjectUtil.isNotEmpty(courseMap.get("days"))
+ && courseMap.get("days").size()>0
+ && checkBookNum(courseMap.get("days").get(0).getCardTypeId(),courseMap.get("days").get(0).getCardNo())
+ ){
+ selected= courseMap.get("days").get(0);
+
+ }else {
+ if (ObjectUtil.isNotEmpty(courseMap.get("count"))
+ && courseMap.get("count").size()>0
+ && checkBookNum(courseMap.get("count").get(0).getCardTypeId(),courseMap.get("count").get(0).getCardNo())
+ ){
+ RespMemberTypeCourses chargeCount= courseMap.get("count").get(0);
+ if (chargeCount.getRemainingCount().compareTo(chargeCount.getDeductCnt())>-1){
+ selected=chargeCount;
+ }else {
+ flag=1;
+ //储值卡
+ if (ObjectUtil.isNotEmpty(courseMap.get("total_fee"))
+ && courseMap.get("total_fee").size()>0
+ && checkBookNum(courseMap.get("total_fee").get(0).getCardTypeId(),courseMap.get("total_fee").get(0).getCardNo())
+ ){
+ RespMemberTypeCourses chargeFee= courseMap.get("total_fee").get(0);
+ //划扣费用,如果未设置,则使用课程 价值
+ BigDecimal deductFee=chargeFee.getRemainingTotalFee().equals(BigDecimal.ZERO)?chargeFee.getTuitionFee():chargeFee.getRemainingTotalFee();
+ if (chargeFee.getRemainingTotalFee().compareTo(deductFee)>-1){
+ selected=chargeFee;
+ }else {
+ flag=3;
+ }
+ }
+ }
+ }else {
+ //储值卡
+ if (ObjectUtil.isNotEmpty(courseMap.get("total_fee"))
+ && courseMap.get("total_fee").size()>0
+ && checkBookNum(courseMap.get("total_fee").get(0).getCardTypeId(),courseMap.get("total_fee").get(0).getCardNo())
+ ){
+ RespMemberTypeCourses chargeFee= courseMap.get("total_fee").get(0);
+ //划扣费用,如果未设置,则使用课程 价值
+ BigDecimal deductFee=chargeFee.getRemainingTotalFee().equals(BigDecimal.ZERO)?chargeFee.getTuitionFee():chargeFee.getRemainingTotalFee();
+ if (chargeFee.getRemainingTotalFee().compareTo(deductFee)>-1){
+ selected=chargeFee;
+
+ }else {
+ flag=2;
+ }
+ }
+ }
+ }
+
+ if (ObjectUtil.isEmpty(selected)){
+
+ if (flag==0){
+ return new RestResponse().setSuccess(false).setMessage("没有满足预约条件的会员卡,请联系教练预约!");
+ }
+
+ if (flag==1){
+ return new RestResponse().setSuccess(false).setMessage("会员卡剩余次数不足,请联系教练预约!");
+ }
+
+ if (flag==2){
+ return new RestResponse().setSuccess(false).setMessage("会员卡剩余金额不足,请联系教练预约!");
+ }
+
+ if (flag==3){
+ return new RestResponse().setSuccess(false).setMessage("会员卡额度不足,请联系教练预约!");
+ }
+ }
+
+ //预约
+ ScBookCourse bookCourse= bookCourseMapper.selectOne(new QueryWrapper()
+ .eq("course_time_id",courseTimeId)
+ .eq("student_id",studentId)
+ .eq("card_no",selected.getCardNo())
+ );
+
+
+
+ if (ObjectUtil.isNotEmpty(bookCourse)){
+ //预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;5- >预约失败;
+ int[] a= {0,1,2,4};
+ if (ArrayUtil.contains(a,bookCourse.getBookStatus())){
+ return new RestResponse().setSuccess(false).setMessage("课程预约中,请勿重复预约!");
+ }
+
+ if (bookCourse.getBookStatus()==3){
+ bookCourse.setBookStatus(0);
+ bookCourseMapper.updateById(bookCourse);
+ addBookLogFromApp(0,bookCourse.getId());
+ }
+ }else {
+ //预约表
+ ScBookCourse book=new ScBookCourse();
+ book.setBookStatus(0);
+ book.setCourseTimeId(courseTimeId);
+ book.setCreateTime(new Date());
+ book.setStudentId(studentId);
+ book.setCardNo(selected.getCardNo());
+ book.setChargeType(selected.getChargeType());
+ book.setDeductCnt(selected.getDeductCnt());
+ book.setDeductFee(selected.getDeductFee());
+ book.setTenantId(courseCla.getTenantId());
+ book.setCourseId(courseCla.getCourseId());
+ book.setClaId(courseCla.getClaId());
+ book.setDepartId(courseCla.getDepartId());
+ //生成一个code 用于消课
+ Long code = IDGenerator.generateId();
+ bookCourseMapper.insert(book);
+ try {
+ byte[] qrCode= CodeUtil.generateQrCodeBytes(book.getId().toString());
+ book.setQrCode(Base64.encode(qrCode));
+ }catch (Exception e){
+
+ }
+ book.setCode(book.getId());
+ bookCourseMapper.updateById(book);
+ //预约记录
+ addBookLogFromApp(0,book.getId());
+
+ //预约成功 后 首次预约激活
+ Map> cardMap =cardList.stream().collect(Collectors.groupingBy(ScMemberCard::getCardNo));
+ ScMemberCard card=cardMap.get(selected.getCardNo()).get(0);
+ if (card.getHaveActivationDate().equals("2")
+ && card.getStatus().equals("INACTIVE")){
+ ScMemberCard edtiCard=new ScMemberCard();
+ edtiCard.setActivationDate(LocalDate.now());
+ edtiCard.setStatus("ACTIVE");
+ edtiCard.setId(card.getId());
+ memberCardsMapper.updateById(edtiCard);
+ }
+ }
+
+ //本节课
+ claTim.setBookAttendCnt(claTim.getBookAttendCnt()+1);
+ claTimeMapper.updateById(claTim);
+ return new RestResponse().setSuccess(true).setMessage("预约成功");
+ }
+
+ //约课次数
+ public Boolean checkBookNum(Long cardTypeId,String cardNo){
+ RespMemberTypeCourses type= memberCardsMapper.getMemberTypeById(cardTypeId);
+ if(type.getRestrictedNum().equals("2")&&StrUtil.isNotEmpty(type.getBookTime())){
+ //限制约课时间范围 每天、每周、半月、每月
+ TimeCycleUtil.TimeRange range= TimeCycleUtil.getCycleTimeRange(type.getBookTime());
+ String startTime=range.getStartTime();
+ String endTime=range.getEndTime();
+
+ Long count= bookCourseMapper.selectCount(new QueryWrapper()
+ .eq("card_no",cardNo)
+ .between("create_time",startTime,endTime)
+ .in("book_status","0,1,2,4")
+ );
+ if (count.intValue()>type.getBookNum().intValue()){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 我的预约列表
+ * @return
+ */
+ @Override
+ public Map> bookCourseList(){
+ Long studentId=SecurityUtils.getAppLoginUser().getStudentId();
+ List list=bookCourseMapper.getListByStudent(studentId);
+
+ Map> map=new HashMap<>();
+ map.put("all",list);
+
+ List booking=new ArrayList<>();
+ List waitingForClass=new ArrayList<>();
+ List canceled=new ArrayList<>();
+ List completed=new ArrayList<>();
+ //预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;
+ for (ClaTimeBookItem b : list) {
+ if (b.getBookStatus()==0){
+ booking.add(b);
+ }
+ if (b.getBookStatus()==2){
+ waitingForClass.add(b);
+ }
+ if (b.getBookStatus()==3){
+ canceled.add(b);
+ }
+ if (b.getBookStatus()==4){
+ completed.add(b);
+ }
+ }
+ map.put("booking",booking);//预约中
+ map.put("waitingForClass",waitingForClass);//待上课
+ map.put("canceled",canceled);//已取消
+ map.put("completed",completed);//已完成
+ return map;
+ }
+
+ /**
+ * 预约详情
+ * @return
+ */
+ @Override
+ public RestResponse bookCourseDetail(Long bookId){
+ ClaTimeBookItem bookItem=bookCourseMapper.getDetail(bookId);
+ List logs=bookCourseLogMapper.selectList(new QueryWrapper()
+ .eq("book_id",bookId).orderByAsc("update_time"));
+
+ List list=new ArrayList<>();
+ for (ScBookCourseLog l : logs) {
+ Map map=new HashMap<>();
+ map.put("status",l.getBookStatus());
+ map.put("time",DateUtil.format(l.getUpdateTime(),"yyyy-MM-dd HH:mm:ss"));
+ list.add(map);
+ }
+
+ bookItem.setStatusTime(list);
+
+ return new RestResponse().setData(bookItem);
+ }
+
+ /**
+ * 取消预约
+ * @return
+ */
+ @Override
+ @Transactional
+ public RestResponse cancelCourse(Long courseTimeId){
+ Long studentId=SecurityUtils.getAppLoginUser().getStudentId();
+ ScClaTime claTim=claTimeMapper.selectById(courseTimeId);
+
+ //状态 1:待上课 2:已上课
+ if (claTim.getStatus().equals(2)){
+ return new RestResponse().setSuccess(false).setMessage("课程已开始上课,无法取消!");
+ }
+
+ //预约
+ ScBookCourse bookCourse= bookCourseMapper.selectOne(new QueryWrapper()
+ .eq("course_time_id",courseTimeId)
+ .eq("student_id",studentId)
+ );
+ if (bookCourse.getCheckIn()==1){
+ return new RestResponse().setSuccess(false).setMessage("已签到,无法取消!");
+ }
+
+ if (StrUtil.containsAny("0,1,2",bookCourse.getBookStatus()+"")){
+ bookCourse.setBookStatus(3);
+ bookCourseMapper.updateById(bookCourse);
+ addBookLogFromApp(3,bookCourse.getId());
+ return new RestResponse().setSuccess(true).setMessage("取消成功");
+
+ }else {
+ return new RestResponse().setSuccess(false).setMessage("取消失败");
+ }
+
+ }
+
+ /**
+ * 预约详情
+ * @param courseTimeId
+ * @return
+ */
+ @Override
+ public RestResponse courseTimeDetail(Long courseTimeId){
+ //课程信息
+ ClaTimeCalendarItem claTimeCalendarItem=claTimeMapper.getCourseList(null,courseTimeId,null).get(0);
+ //预约学员信息 姓名 性别 电话
+ List students=claTimeMapper.getCourseBookStudent(courseTimeId);
+
+ Map map=new HashMap();
+ map.put("courseDetail",claTimeCalendarItem);
+ map.put("studentList",students);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+ @Override
+ public RestResponse appointmentListForTeacher(){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,104L)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ Long userId= SecurityUtils.getAppLoginUser().getManageAccountId();
+ Date beginTime = new Date();//开始时间
+ Date endTime = DateUtil.offsetDay(beginTime,14);//结束时间
+ //按教师id 查 近15日课程 (sc_cla_time) 预约(sc_book_course)
+ List listForTeacher=claTimeMapper.getBookListForTeacher(userId,beginTime.toString(),endTime.toString());
+
+
+ return new RestResponse().setData(listForTeacher);
+ }
+ @Override
+ public RestResponse appointmentListForManager(){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,105L)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+
+ Long userId= SecurityUtils.getAppLoginUser().getManageAccountId();
+ SysDept dept=new SysDept();
+ dept.setLeaderId(userId);
+ List list=deptService.selectDeptList(dept);
+ Long deptId= list .get(0).getDeptId();
+
+ Date beginTime = new Date();//开始时间
+ Date endTime = DateUtil.offsetDay(beginTime,14);//结束时间
+ List listForManager=claTimeMapper.getBookListForManager(deptId,beginTime.toString(),endTime.toString());
+
+ return new RestResponse().setData(listForManager);
+ }
+
+
+ //确认预约or拒接预约(教师/店长)
+ @Override
+ @Transactional
+ public RestResponse checkAppointment(Long bookId,int bookStatus){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,105L, 104L)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ //0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;5- >预约失败;
+ //当前课程状态
+ ScBookCourse bookCourse= bookCourseMapper.selectById(bookId);
+ Integer dbBookStatus= new Integer(bookCourse.getBookStatus());
+ Integer[] status={3,4,5};
+
+ if (ArrayUtil.containsAny(status,dbBookStatus)){
+ return new RestResponse().setSuccess(false).setMessage("请刷新预约状态!");
+ }
+
+
+ ScBookCourse updateBook=new ScBookCourse();
+ updateBook.setId(bookId);
+ int f=0;
+ if (bookStatus==5){
+ updateBook.setBookStatus(5);
+ f=bookCourseMapper.updateById(updateBook);
+ addBookLogFromApp(5,bookId);
+ }
+
+ if (ArrayUtil.containsAny(roleId, 104L)&& dbBookStatus==0){
+ updateBook.setBookStatus(1);
+ f=bookCourseMapper.updateById(updateBook);
+ addBookLogFromApp(1,bookId);
+ }
+
+ if (ArrayUtil.containsAny(roleId, 105L)&& dbBookStatus==1){
+ updateBook.setBookStatus(2);
+ f=bookCourseMapper.updateById(updateBook);
+ addBookLogFromApp(2,bookId);
+ }
+
+ if (f>0){
+ return new RestResponse().setSuccess(true).setMessage("成功!");
+ }else {
+ return new RestResponse().setSuccess(false).setMessage("请刷新预约状态!");
+ }
+
+ }
+
+ void addBookLogFromApp(int bookStatus,Long bookId){
+ ScBookCourseLog log=new ScBookCourseLog();
+ log.setBookStatus(bookStatus);
+ log.setUpdateTime(new Date());
+ log.setUpdateUser(SecurityUtils.getAppLoginUser().getManageAccountId());//后台sys_user id
+ log.setBookId(bookId);
+ bookCourseLogMapper.insert(log);
+ }
+
+ /**
+ * 确认上课
+ * @param courseTimeId
+ * @return
+ */
+ @Override
+ @Transactional
+ public RestResponse confirmClass(Long courseTimeId,String startTime,String endTime){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,104l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ AppLoginUser loginUser=SecurityUtils.getAppLoginUser();
+ //本节课的预约
+ List bookCourses=bookCourseMapper.selectList(new QueryWrapper()
+ .in("book_status",0,1,2)
+ .eq("course_time_id",courseTimeId)
+ );
+ if (bookCourses.size()<1)throw new RuntimeException("无学员预约!");
+ //判断预约状态(未确认)
+// Long needCheck= bookCourses.stream()
+// .filter(l-> StrUtil.containsAny("0,1",l.getBookStatus()+"")).count();
+// if (needCheck>0){
+// return new RestResponse().setSuccess(false).setMessage("请检查学员预约状态!");
+// }
+
+ //判断是否有学员未签到
+ Long notCheckIn=bookCourses.stream().filter(l->l.getCheckIn()==0).count();
+ if (notCheckIn>0){
+ return new RestResponse().setSuccess(false).setMessage("请确认学员签到情况,如无法到课请联系学员取消预约!");
+ }
+ //签到学员
+ List checkIn=bookCourses.stream().filter(l->l.getCheckIn()==1).collect(Collectors.toList());
+
+ ScClaTime claTime=claTimeMapper.selectById(courseTimeId);
+ //签到数量是否少于开课人数
+ if (claTime.getLessCnt()>checkIn.size()){
+ return new RestResponse().setSuccess(false).setMessage("学员数量到不到开课标准!");
+ }
+
+ //教室使用时间及费用
+ Date startTimeDate= DateUtil.parseTime(startTime);
+ Date endTimeDate= DateUtil.parseTime(endTime);
+
+ BigDecimal venueFee=new BigDecimal( 0);
+ double roomUsageTime=0.0;
+
+ if (ObjectUtil.isNotEmpty(claTime.getRoomId())){
+ ScRoom room= roomMapper.selectById(claTime.getRoomId());
+ //上课时间段 >0.5小时,按1小时计
+ roomUsageTime=DateUtil.between(startTimeDate, endTimeDate, DateUnit.MINUTE)/ 60.0;
+ int c=(int)roomUsageTime;
+ double d=roomUsageTime-c;
+ if (d > 0.5) {
+ roomUsageTime= c + 1.0;
+ } else if (d > 0) {
+ roomUsageTime= c + 0.5;
+ }
+ venueFee= room.getVenueFee().add(new BigDecimal(roomUsageTime));
+ }
+
+ //更改预约状态
+ bookCourseMapper.update(null,new UpdateWrapper()
+ .eq("course_time_id",courseTimeId)
+ .eq("check_in","1")
+ .eq("book_status",2)
+ .set("book_status","4"));
+ //添加预约状态记录
+ for (ScBookCourse bookCours : checkIn) {
+ addBookLogFromApp(4,bookCours.getId());
+ }
+ claTime.setRealClaDate(DateUtil.format(new Date(),"yyyy-MM-dd"));
+ claTime.setRealStartTime(startTime);
+ claTime.setRealEndTime(endTime);
+ claTime.setVenueFee(venueFee);
+ claTime.setRoomUsageTime(roomUsageTime);
+ claTime.setStatus("2");
+ claTime.setLastUpdateTime(new Date());
+ claTimeMapper.updateById(claTime);
+
+ return new RestResponse().setSuccess(true).setMessage("开始上课!");
+ }
+
+
+ /**
+ * 签到
+ *
+ * @param
+ * @return
+ */
+ @Override
+ @Transactional
+ public RestResponse checkIn(Map map) {
+
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,104l,105l,103l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ //预约id/code
+ String code= map.get("code").toString();
+ Long bookId=Long.parseLong(map.get("bookId").toString());
+ //预约
+ ScBookCourse bookCourse= bookCourseMapper.selectOne(new QueryWrapper()
+ .eq("code",code));
+
+ //判断预约状态
+ //预约状态:0->预约中;1->教练确认;2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;5- >预约失败;
+// if (StrUtil.containsAny("3,4,5",bookCourse.getBookStatus()+"")){
+ if (bookCourse.getBookStatus()!=2){
+ return new RestResponse().setSuccess(false).setMessage("请检查学员预约状态!");
+ }
+
+ AppLoginUser loginUser = SecurityUtils.getAppLoginUser();
+ Long courseTimeId = bookCourse.getCourseTimeId();
+
+ ScMemberCard memberCard=memberCardsMapper.selectOne(new QueryWrapper()
+ .eq("card_no",bookCourse.getCardNo())
+ .eq("charge_type",bookCourse.getChargeType())
+ .eq("is_deleted",0)
+ .last(" and expiry_date > CURDATE() ")
+
+ );
+ if (ObjectUtil.isEmpty(memberCard)){
+ return new RestResponse().setSuccess(false).setMessage("会员卡状态异常,请与教练核实!");
+ }
+
+ // 排课信息
+ ScClaTime claTime= claTimeMapper.selectById(courseTimeId);
+ Long teacherId = claTime.getTeacherId();
+ if (!ClaTimeStatusEnums.WAIT_CLASS.getStatus().equals(claTime.getStatus())) {
+ return new RestResponse().setSuccess(false).setMessage("非待上课状态,无法重复上课!");
+ }
+ //班级信息
+ Long claId = claTime.getClaId();
+ ScCourseCla dbCla = claMapper.selectById(claId);
+ if (null == dbCla) {
+ return new RestResponse().setSuccess(false).setMessage("无法获取班级信息,请稍后重试");
+ }
+ //课程信息
+ Long courseId = dbCla.getCourseId();
+ ScCourse scCourse = courseMapper.selectById(courseId);
+ if (null == scCourse) {
+ return new RestResponse().setSuccess(false).setMessage("无法获取课程信息,请稍后重试");
+ }
+ Long departId = dbCla.getDepartId();
+ SysDept sysDept = deptService.getById(departId);
+ if (null == sysDept) {
+ return new RestResponse().setSuccess(false).setMessage("无法获取校区信息,请稍后重试");
+ }
+ String chargeType=memberCard.getChargeType();
+
+ // 上课记出勤表
+ ScClaTimeAttend addClaTimeAttend = new ScClaTimeAttend();
+
+ if (chargeType.equals("count")){
+ if (memberCard.getRemainingCount().compareTo(bookCourse.getDeductCnt())>-1){
+ addClaTimeAttend.setPayHour(bookCourse.getDeductCnt());
+ addClaTimeAttend.setCountBefore(memberCard.getRemainingCount());
+ addClaTimeAttend.setPayFee(memberCard.getCountFee().multiply(bookCourse.getDeductCnt()));
+
+ BigDecimal countAfter= memberCard.getRemainingCount().subtract(bookCourse.getDeductCnt());
+ addClaTimeAttend.setCountAfter(countAfter);
+ memberCard.setRemainingCount(countAfter);
+ }else {
+ return new RestResponse().setSuccess(false).setMessage("会员卡剩余次数不足,请充值后重新预约!");
+ }
+ }
+
+ if (chargeType.equals("total_fee")){
+ if (memberCard.getRemainingTotalFee().compareTo(bookCourse.getDeductFee())>-1){
+ addClaTimeAttend.setPayFee(bookCourse.getDeductFee());
+ addClaTimeAttend.setFeeBefore(memberCard.getRemainingTotalFee());
+
+ BigDecimal feeAfter=memberCard.getRemainingTotalFee().subtract(bookCourse.getDeductFee());
+ addClaTimeAttend.setFeeAfter(feeAfter);
+ memberCard.setRemainingTotalFee(feeAfter);
+ }else {
+ return new RestResponse().setSuccess(false).setMessage("会员卡剩余金额不足,请充值后重新预约!");
+ }
+ }
+ bookCourse.setUserId(SecurityUtils.getAppLoginUser().getManageAccountId());
+ bookCourse.setCheckIn(1);
+ bookCourse.setCheckInTime(new Date());
+ bookCourseMapper.updateById(bookCourse);
+ //会员卡余额变更
+ memberCardsMapper.updateById(memberCard);
+
+ //本节课 到课人数变更
+ claTime.setRealAttendCnt(claTime.getRealAttendCnt()+1);
+ claTimeMapper.updateById(claTime);
+
+ SysTeacher sysStaff=staffService.getById(teacherId);
+
+ addClaTimeAttend.setBookId(bookCourse.getId());
+ addClaTimeAttend.setMemberCardId(memberCard.getId());
+ addClaTimeAttend.setCourseTimeId(courseTimeId);
+ addClaTimeAttend.setStudentId(bookCourse.getStudentId());
+ addClaTimeAttend.setClaId(claTime.getClaId());
+ addClaTimeAttend.setCourseId(scCourse.getCourseId());
+ addClaTimeAttend.setTeacherId(teacherId);
+ addClaTimeAttend.setTeacherName(sysStaff.getUserName());
+ addClaTimeAttend.setChargeType(chargeType);
+ addClaTimeAttend.setTenantId(claTime.getTenantId());
+ addClaTimeAttend.setAttendStatus("1");
+ addClaTimeAttend.setCreateUser(loginUser.getManageAccountId());
+
+ // 保存上课记录
+ attendService.save(addClaTimeAttend);
+
+ // 上课日志
+// StringBuffer sb = new StringBuffer("");
+// sb.append("上课[").append(ClaTimeAttendStatusEnums.getNameByStatus("1")).append("],上课时间")
+// .append(DateUtil.now()).append(",");
+// ScStudentCourseLog studentCourseLog = ScStudentCourseLog.builder()
+// .studentId(bookCourse.getStudentId())
+// .logType(LogTypeEnum.ATTEND_CLA.getLogType())
+// .courseId(scCourse.getCourseId())
+// .courseName(scCourse.getCourseName())
+// .claId(dbCla.getClaId())
+// .claName(dbCla.getClaName())
+// .deptName(sysDept.getDeptName())
+// .createUser(loginUser.getAppUserId())
+// .createUserType("app")
+// .createUserName(loginUser.getAppUser().getUserName())
+// .createTime(new Date())
+// .build();
+// //count:课时 days:时间 total_fee:储值
+// if (chargeType.equals("count")) {
+// studentCourseLog.setChangeHour(addClaTimeAttend.getPayHour());
+// studentCourseLog.setAfterBalanceHour(addClaTimeAttend.getCountAfter());
+// sb.append("扣减").append(addClaTimeAttend.getPayHour()).append("课时;");
+// }
+// if (chargeType.equals("total_fee")) {
+// studentCourseLog.setChangeFee(addClaTimeAttend.getPayFee());
+// studentCourseLog.setAfterBalanceHour(addClaTimeAttend.getFeeAfter());
+// sb.append("扣减").append(addClaTimeAttend.getPayHour()).append("元;");
+// }
+// studentCourseLog.setMemo(sb.toString());
+// }
+
+ // 保存学生日志
+// studentCourseLogMapper.insert(studentCourseLog);
+
+ return new RestResponse().setSuccess(true).setMessage("签到成功!");
+ }
+
+ /**
+ * 教练课时统计
+ * @return
+ */
+ @Override
+ public RestResponse teacherClaTotal(String time) {
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长
+ if (!ArrayUtil.containsAny(roleId,104l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+
+ Long teacherId= SecurityUtils.getAppLoginUser().getManageAccountId();
+
+ QueryWrapper queryWrapper= new QueryWrapper();
+ queryWrapper.eq("teacher_id",teacherId);
+
+ switch (time) {
+ case "today" :
+ queryWrapper.eq("real_cla_date",DateUtil.format(DateUtil.date(),"yyyy-MM-dd"));
+ break;
+ case "yesterday" :
+ queryWrapper.eq("real_cla_date",DateUtil.format(DateUtil.yesterday(),"yyyy-MM-dd"));
+ break;
+ case "thisMonth" :
+ queryWrapper.eq("substr(real_cla_date,1,7)",
+ DateUtil.format(DateUtil.date(),"yyyy-MM")
+ );
+ break;
+ case "lastMonth" :
+ queryWrapper.eq("substr(real_cla_date,1,7)",
+ DateUtil.format(DateUtil.lastMonth(),"yyyy-MM")
+ );
+ break;
+ }
+
+ List claTimeList=claTimeMapper.selectList(queryWrapper);
+
+ //上课节数
+ int claCount=claTimeList.size();
+
+ BigDecimal totalFee = claTimeList.stream()
+ // 将user对象的age取出来map为Bigdecimal
+ .map(ScClaTime::getTeacherFee)
+ // 使用reduce()聚合函数,实现累加器
+ .reduce(BigDecimal.ZERO,BigDecimal::add);
+ claTimeList.forEach(l->{
+ String courseName= claTimeMapper.getCourseList(null,l.getCourseTimeId(),null).get(0).getCourseName();
+ l.setCourseName(courseName);
+ });
+ Map map=new HashMap<>();
+ map.put("claCount",claCount);
+ map.put("totalFee",totalFee);
+ map.put("claTimeList",claTimeList);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+ private String beginTime;
+ private String endTime;
+
+
+ /**
+ * 教练费用统计(店长)
+ * @return
+ */
+ @Override
+ public RestResponse teacherFeeTotal(String time) {
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长
+ if (!ArrayUtil.containsAny(roleId,105l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+
+ Long staffId= SecurityUtils.getAppLoginUser().getManageAccountId();
+
+ getTime(time);
+
+ List claTimeList=claTimeMapper.getCourseCountByStoreManager(staffId,this.beginTime,this.endTime);
+
+ //上课节数
+ int claCount=claTimeList.size();
+ //课时费
+ BigDecimal totalFee = claTimeList.stream()
+ // 将user对象的age取出来map为Bigdecimal
+ .map(ClaTimeItem::getTeacherFee)
+ // 使用reduce()聚合函数,实现累加器
+ .reduce(BigDecimal.ZERO,BigDecimal::add);
+
+ Map map=new HashMap<>();
+ map.put("claCount",claCount);
+ map.put("totalFee",totalFee);
+ map.put("claTimeList",claTimeList);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+
+ /**
+ * 我的客户
+ * @return
+ */
+ @Override
+ public RestResponse myClient(){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,103l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ Long staffId= SecurityUtils.getAppLoginUser().getManageAccountId();
+ List students= claTimeMapper.getStudentsBySaleStaff(staffId);
+ return new RestResponse().setSuccess(true).setData(students);
+ }
+
+ /**
+ * 我的提成
+ * @param time
+ * @return
+ */
+ @Override
+ public RestResponse commissionTotal(String time){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,103l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ Long staffId= SecurityUtils.getAppLoginUser().getManageAccountId();
+ getTime(time);
+ //获取成交的订单信息
+ List orderLost=claTimeMapper.myDealOrder(staffId,beginTime,endTime);
+ //佣金方案
+ Map> orderMap =
+ orderLost.stream().collect(Collectors.groupingBy(RespOrderForApp::getCommissionPlansId));
+
+ BigDecimal totalFee=new BigDecimal(0);
+ //佣金策略(多个)
+ for (Long aLong : orderMap.keySet()) {
+ ScCommissionPlans plans= commissionMapper.selectById(aLong);
+ BigDecimal commissionFee = orderMap.get(aLong).stream()
+ // 将user对象的age取出来map为Bigdecimal
+ .map(RespOrderForApp::getReceiptFee)
+ // 使用reduce()聚合函数,实现累加器
+ .reduce(BigDecimal.ZERO,BigDecimal::add);
+
+ BigDecimal fee=new BigDecimal(0);
+ //小于 第一阶梯阈值
+ if (plans.getTier1Threshold().compareTo(totalFee)>0){
+ fee=commissionFee.multiply(plans.getTier1Rate());
+ }
+ //第二阶梯
+ if (totalFee.compareTo(plans.getTier1Threshold())>0
+ &&plans.getTier2Threshold().compareTo(totalFee)>0){
+ fee=commissionFee.multiply(plans.getTier2Rate());
+ }
+ //第三阶梯
+ if (totalFee.compareTo(plans.getTier2Threshold())>0
+ &&plans.getTier3Threshold().compareTo(totalFee)>0){
+ fee=commissionFee.multiply(plans.getTier3Rate());
+ }
+ //第4阶梯
+ if (totalFee.compareTo(plans.getTier3Threshold())>0){
+ fee=commissionFee.multiply(plans.getTier4Rate());
+ }
+
+ totalFee=totalFee.add(fee);
+ }
+ //todo 转介绍佣金...
+
+ Map map=new HashMap();
+ map.put("commission",totalFee);
+ map.put("orderCount",orderLost.size());
+ map.put("orderList",orderLost);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+ //销售信息(店长)
+ @Override
+ public RestResponse salesInformation(String time){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,105l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ Long staffId= SecurityUtils.getAppLoginUser().getManageAccountId();
+ SysUser sysUser=sysUserService.selectUserById(staffId);
+ getTime(time);
+ //获取成交的订单信息
+ List orderLost=claTimeMapper.getOrdersForStore(sysUser.getDeptId(),beginTime,endTime);
+ BigDecimal totalAmount = orderLost.stream()
+ // 将user对象的age取出来map为Bigdecimal
+ .map(RespOrderForApp::getReceiptFee)
+ // 使用reduce()聚合函数,实现累加器
+ .reduce(BigDecimal.ZERO,BigDecimal::add);
+
+ Map map=new HashMap();
+ map.put("totalAmount",totalAmount);
+ map.put("orderCount",orderLost.size());
+ map.put("orderList",orderLost);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+ //教室费用
+ @Override
+ public RestResponse claRoomFee(String time){
+ Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
+ //104 教师 105店长 103 会籍顾问
+ if (!ArrayUtil.containsAny(roleId,105l)){
+ return new RestResponse().setSuccess(false).setMessage("当前登录人无权限!");
+ }
+ Long staffId= SecurityUtils.getAppLoginUser().getManageAccountId();
+
+ getTime(time);
+ //获取门店上课信息
+ List claTimeList=claTimeMapper.getCourseCountByStoreManager(staffId,beginTime,endTime);
+ //教室使用费用
+ BigDecimal venueFee = claTimeList.stream()
+ // 将user对象的age取出来map为Bigdecimal
+ .map(ClaTimeItem::getVenueFee)
+ // 使用reduce()聚合函数,实现累加器
+ .reduce(BigDecimal.ZERO,BigDecimal::add);
+
+ Map map=new HashMap<>();
+ map.put("venueFee",venueFee);
+ map.put("claTimeList",claTimeList);
+
+ return new RestResponse().setSuccess(true).setData(map);
+ }
+
+ private void getTime( String time){
+// String beginTime,String endTime,
+ switch (time) {
+ case "today" :
+ beginTime=DateUtil.format(DateUtil.date(),"yyyy-MM-dd 00:00:00");
+ endTime=DateUtil.format(DateUtil.date(),"yyyy-MM-dd 23:59:59");;
+ break;
+ case "yesterday" :
+ beginTime=DateUtil.format(DateUtil.yesterday(),"yyyy-MM-dd 00:00:00");
+ endTime=DateUtil.format(DateUtil.yesterday(),"yyyy-MM-dd 23:59:59");
+ break;
+ case "thisMonth" :
+ beginTime=DateUtil.format(DateUtil.date(),"yyyy-MM-01 00:00:00");
+ endTime=DateUtil.format(DateUtil.date(),"yyyy-MM-dd 23:59:59");
+ break;
+ case "lastMonth" :
+ DateTime lastMonth=DateUtil.lastMonth();
+ beginTime=DateUtil.format(lastMonth,"yyyy-MM-01 00:00:00");
+ endTime=DateUtil.format(DateUtil.endOfMonth(lastMonth),"yyyy-MM-dd 23:59:59");
+ break;
+ default:
+ throw new RuntimeException("请选择查询时间范围");
+ }
+ }
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentCourseOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentCourseOrderServiceImpl.java
new file mode 100644
index 0000000..f553b8f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentCourseOrderServiceImpl.java
@@ -0,0 +1,153 @@
+package com.ruoyi.course.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.course.domain.ScStudent;
+import com.ruoyi.course.domain.ScStudentCourse;
+import com.ruoyi.course.domain.ScStudentCourseOrder;
+import com.ruoyi.course.mapper.ScStudentCourseMapper;
+import com.ruoyi.course.mapper.ScStudentCourseOrderMapper;
+import com.ruoyi.course.mapper.ScStudentMapper;
+import com.ruoyi.course.service.IScStudentCourseOrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ *
+ * 学生课程关联订单 服务实现类
+ *
+ *
+ */
+@Service
+public class ScStudentCourseOrderServiceImpl extends ServiceImpl implements IScStudentCourseOrderService {
+
+
+ @Autowired
+ private ScStudentCourseMapper studentCourseMapper;
+ @Autowired
+ private ScStudentMapper studentMapper;
+
+ @Override
+ public boolean checkDateCover(Long studentId, Long courseId, String beginDate, String endDate) {
+ int checkDateCover = baseMapper.checkDateCover(studentId, courseId, beginDate, endDate);
+ if (checkDateCover == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public ScStudentCourseOrder getSubtractHourOrder(Long studentCourseId) {
+ return baseMapper.selectSubtractHourOrder(studentCourseId);
+ }
+
+ @Override
+ public ScStudentCourseOrder getNowValidDateOrder(Long studentCourseId) {
+ return baseMapper.selectNowValidDateOrder(studentCourseId);
+ }
+
+ @Override
+ public BigDecimal subtractCourseOrderBalanceHour(Long studentCourseId, BigDecimal loseHour) {
+ List studentCourseOrderList = baseMapper.selectSubtractHourOrderList(studentCourseId);
+ BigDecimal payFee = BigDecimal.ZERO;
+ for (ScStudentCourseOrder courseOrder : studentCourseOrderList) {
+ if (loseHour.compareTo(BigDecimal.ZERO) == 0) {
+ break;
+ }
+ BigDecimal balanceHour = courseOrder.getBalanceHour();
+
+ // 订单剩余课时不足扣减
+ if (balanceHour.compareTo(loseHour) < 0) {
+ payFee = payFee.add(balanceHour.multiply(courseOrder.getUnitFee()));
+
+ // 剩余课时不足扣减, 将剩余课时扣减完毕
+ int updateSubtractHour = baseMapper.updateSubtractHour(courseOrder.getCourseOrderId(), BigDecimal.ZERO, balanceHour);
+ if (updateSubtractHour == 0) {
+ throw new RuntimeException("订单扣减课时失败,请重试!");
+ }
+
+ loseHour = loseHour.subtract(balanceHour);
+
+ } else {
+ payFee = payFee.add(loseHour.multiply(courseOrder.getUnitFee()));
+
+ // 直接扣减课时
+ BigDecimal newHour = balanceHour.subtract(loseHour);
+ int updateSubtractHour = baseMapper.updateSubtractHour(courseOrder.getCourseOrderId(), newHour, balanceHour);
+ if (updateSubtractHour == 0) {
+ throw new RuntimeException("订单扣减课时失败,请重试!");
+ }
+ }
+ }
+ return payFee;
+ }
+
+ @Override
+ public void recoverOrderLoseHour(Long studentCourseId, BigDecimal recoverHour) {
+ if(recoverHour.compareTo(BigDecimal.ZERO) == 0) {
+ return;
+ }
+ List recoverHourOrderList = baseMapper.selectRecoverHourOrderList(studentCourseId);
+ if (recoverHourOrderList.size() == 0) {
+ ScStudentCourse studentCourse = studentCourseMapper.selectById(studentCourseId);
+ ScStudent student = studentMapper.selectById(studentCourse.getStudentId());
+ throw new RuntimeException("学员:" + student.getStudentName() + ",无生效订单,无法恢复课时!");
+ }
+
+ for (int i = 0; i < recoverHourOrderList.size(); i++) {
+
+ if(recoverHour.compareTo(BigDecimal.ZERO) == 0) {
+ return;
+ }
+
+ // 是否为最后一条记录
+ boolean lastRecord = (i == (recoverHourOrderList.size() - 1));
+ ScStudentCourseOrder studentCourseOrder = recoverHourOrderList.get(i);
+ BigDecimal balanceHour = studentCourseOrder.getBalanceHour();
+ BigDecimal totalHour = studentCourseOrder.getTotalHour();
+ if(lastRecord) {
+ BigDecimal newBalanceHour = studentCourseOrder.getBalanceHour().add(recoverHour);
+ this.updateBalanceHour(studentCourseOrder.getCourseOrderId(), newBalanceHour, balanceHour);
+ break;
+ } else {
+ if(balanceHour.compareTo(totalHour) < 0) {
+ // 可恢复课时数量
+ BigDecimal canRecoverHour = totalHour.subtract(balanceHour);
+
+ if(canRecoverHour.compareTo(recoverHour) > 0) {
+ // 订单可恢复课时数量canRecoverHour > 需要恢复的课时数量recoverHour,直接全部恢复
+
+ BigDecimal newBalanceHour = studentCourseOrder.getBalanceHour().add(recoverHour);
+ this.updateBalanceHour(studentCourseOrder.getCourseOrderId(), newBalanceHour, balanceHour);
+ recoverHour = BigDecimal.ZERO;
+ } else {
+ // 订单可恢复课时数量canRecoverHour <= 需要恢复的课时数量recoverHour
+
+ BigDecimal newBalanceHour = studentCourseOrder.getBalanceHour().add(canRecoverHour);
+ this.updateBalanceHour(studentCourseOrder.getCourseOrderId(), newBalanceHour, balanceHour);
+
+ // 剩余需恢复课时
+ recoverHour = recoverHour.subtract(canRecoverHour);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void updateBalanceHour(Long courseOrderId, BigDecimal newBalanceHour, BigDecimal oldBalanceHour) {
+ UpdateWrapper uw = new UpdateWrapper<>();
+ uw.eq("course_order_id", courseOrderId);
+ uw.eq("balance_hour", oldBalanceHour);
+ uw.set("balance_hour", newBalanceHour);
+ boolean update = this.update(uw);
+ if (!update) {
+ throw new RuntimeException("订单恢复课时失败,请重试!");
+ }
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentServiceImpl.java
new file mode 100644
index 0000000..43ecb78
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScStudentServiceImpl.java
@@ -0,0 +1,32 @@
+package com.ruoyi.course.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.course.domain.ScStudent;
+import com.ruoyi.course.mapper.ScStudentMapper;
+import com.ruoyi.course.service.IScStudentService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 学生基本信息 服务实现类
+ *
+ *
+ *
+ * @since 2020-04-27 07:13:40
+ */
+@Service
+public class ScStudentServiceImpl extends ServiceImpl implements IScStudentService {
+
+
+ @Override
+ public Long getStudentByAppUserId(Long appUserId){
+ QueryWrapper qw = new QueryWrapper<>();
+ qw.eq("app_user_id", appUserId);
+ ScStudent student = this.getOne(qw);
+ if (null != student) {
+ return student.getStudentId();
+ }
+ return null;
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/StudentCourseServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/StudentCourseServiceImpl.java
new file mode 100644
index 0000000..edc632e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/StudentCourseServiceImpl.java
@@ -0,0 +1,327 @@
+package com.ruoyi.course.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.RestResponse;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.model.AppLoginUser;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.course.domain.*;
+import com.ruoyi.course.domain.enums.ClaTimeAttendStatusEnums;
+import com.ruoyi.course.domain.enums.ClaTimeStatusEnums;
+import com.ruoyi.course.domain.enums.CourseChargeTypeEnum;
+import com.ruoyi.course.domain.enums.LogTypeEnum;
+import com.ruoyi.course.domain.req.ReqClaTimeAttend;
+import com.ruoyi.course.domain.req.ReqClaTimeAttendItem;
+import com.ruoyi.course.mapper.ScClaTimeMapper;
+import com.ruoyi.course.mapper.ScStudentCourseMapper;
+import com.ruoyi.course.service.IScCourseClaService;
+import com.ruoyi.course.service.IScCourseService;
+import com.ruoyi.course.service.ScClaTimeService;
+import com.ruoyi.course.service.ScStudentCourseService;
+import com.ruoyi.system.service.ISysDeptService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class StudentCourseServiceImpl extends ServiceImpl implements ScStudentCourseService {
+
+
+
+
+ @Autowired
+ private IScCourseClaService claService;
+
+ @Autowired
+ private ISysDeptService deptService;
+
+ @Autowired
+ private IScCourseService courseService;
+
+ @Autowired
+ private ScStudentCourseMapper studentCourseMapper;
+
+ @Autowired
+ private ScClaTimeService claTimeService;
+
+ /**
+ * 记上课
+ *
+ * @param reqClaTimeAttend
+ * @return
+ */
+ @Override
+ public RestResponse claTimeAttend(ReqClaTimeAttend reqClaTimeAttend) {
+// APIResponse checkParam = reqClaTimeAttend.checkParam();
+// if (!checkParam.isSuccess()) {
+// return checkParam;
+// }
+// AppLoginUser loginUser = SecurityUtils.getAppLoginUser();
+// String attendType = reqClaTimeAttend.getAttendType();
+// String startTime = reqClaTimeAttend.getStartTime();
+// String endTime = reqClaTimeAttend.getEndTime();
+// Long teacherId = reqClaTimeAttend.getTeacherId();
+// Long courseTimeId = reqClaTimeAttend.getCourseTimeId();
+// Long claId = reqClaTimeAttend.getClaId();
+// ScCourseCla dbCla = claService.getById(claId);
+// if (null == dbCla) {
+// return new RestResponse().setSuccess(false).setMessage("无法获取班级信息,请稍后重试");
+// }
+// Long courseId = dbCla.getCourseId();
+// ScCourse scCourse = courseService.getById(courseId);
+// if (null == scCourse) {
+// return new RestResponse().setSuccess(false).setMessage("无法获取班级信息,请稍后重试");
+// }
+//
+// Long departId = dbCla.getDepartId();
+// SysDept sysDept = deptService.getById(departId);
+// if (null == sysDept) {
+// return new RestResponse().setSuccess(false).setMessage("无法获取校区信息,请稍后重试");
+// }
+//
+// List studentAttendList = reqClaTimeAttend.getStudentAttendList();
+//
+// // 总消耗课时金额
+// BigDecimal totalPayFee = BigDecimal.ZERO;
+// // 可课时消耗
+// BigDecimal totalPayHour = BigDecimal.ZERO;
+// // 实到人数
+// Long realAttendCnt = studentAttendList.stream().filter(item -> item.getAttendStatus().equals(ClaTimeAttendStatusEnums.AT_CLASS.getAttendStatus())).count();
+// // 请假人数
+// Long leaveCnt = studentAttendList.stream().filter(item -> item.getAttendStatus().equals(ClaTimeAttendStatusEnums.LEAVE_CLASS.getAttendStatus())).count();
+// // 旷课人数
+// Long outCnt = studentAttendList.stream().filter(item -> item.getAttendStatus().equals(ClaTimeAttendStatusEnums.OUT_CLASS.getAttendStatus())).count();
+// // 应到人数
+// int needAttendCnt = studentCourseMapper.selectClaNeedAttendCnt(dbCla.getClaId());
+//
+//
+// if ("rule".equals(attendType)) {
+// // 排课记上课
+//
+// ScClaTime claTime = claTimeService.getById(courseTimeId);
+// if (!ClaTimeStatusEnums.WAIT_CLASS.getStatus().equals(claTime.getStatus())) {
+// return new RestResponse().setSuccess(false).setMessage("选择计划上课日期,非待上课状态,无法重复上课!");
+// }
+// teacherId = claTime.getTeacherId();
+// // 变更状态为已上课
+// ScClaTime updateClaTime = new ScClaTime();
+// updateClaTime.setCourseTimeId(courseTimeId);
+// updateClaTime.setRealClaDate(claTime.getClaDate());
+// updateClaTime.setRealStartTime(startTime);
+// updateClaTime.setRealEndTime(endTime);
+// updateClaTime.setStatus(ClaTimeStatusEnums.HAD_CLASS.getStatus());
+//// updateClaTime.setNeedAttendCnt(needAttendCnt);
+// updateClaTime.setRealAttendCnt(realAttendCnt.intValue());
+// updateClaTime.setMemo(reqClaTimeAttend.getMemo());
+// updateClaTime.setLastUpdateUser(loginUser.getAppUserId());
+// updateClaTime.setLastUpdateTime(new Date());
+// claTimeService.updateById(updateClaTime);
+// } else if ("change".equals(attendType)) {
+// // 变更上课记录
+//
+// ScClaTime claTime = claTimeService.getById(courseTimeId);
+// if (!ClaTimeStatusEnums.WAIT_CLASS.getStatus().equals(claTime.getStatus())) {
+// return APIResponse.toExceptionResponse("选择计划上课日期,非待上课状态,无法重复上课!");
+// }
+// // 变更状态为已上课
+// ScClaTime updateClaTime = new ScClaTime();
+// updateClaTime.setCourseTimeId(courseTimeId);
+// updateClaTime.setRealClaDate(reqClaTimeAttend.getClaDate());
+// updateClaTime.setTeacherId(reqClaTimeAttend.getTeacherId());
+// updateClaTime.setClassTheme(reqClaTimeAttend.getClassTheme());
+// updateClaTime.setRealStartTime(startTime);
+// updateClaTime.setRealEndTime(endTime);
+// updateClaTime.setStatus(ClaTimeStatusEnums.HAD_CLASS.getStatus());
+//// updateClaTime.setNeedAttendCnt(needAttendCnt);
+// updateClaTime.setRealAttendCnt(realAttendCnt.intValue());
+// updateClaTime.setMemo(reqClaTimeAttend.getMemo());
+// updateClaTime.setLastUpdateUser(loginUser.getAppUserId());
+// updateClaTime.setLastUpdateTime(new Date());
+// claTimeService.updateById(updateClaTime);
+// } else if ("custom".equals(attendType)) {
+// // 记录自定义上课信息
+//
+// ScClaTime addClaTime = new ScClaTime();
+// addClaTime.setClaId(reqClaTimeAttend.getClaId());
+// addClaTime.setClaDate(reqClaTimeAttend.getClaDate());
+// addClaTime.setTeacherId(reqClaTimeAttend.getTeacherId());
+// addClaTime.setClassTheme(reqClaTimeAttend.getClassTheme());
+// addClaTime.setStartTime(reqClaTimeAttend.getStartTime());
+// addClaTime.setEndTime(reqClaTimeAttend.getEndTime());
+// addClaTime.setRealClaDate(reqClaTimeAttend.getClaDate());
+// addClaTime.setRealStartTime(reqClaTimeAttend.getStartTime());
+// addClaTime.setRealEndTime(reqClaTimeAttend.getEndTime());
+// addClaTime.setSource(ClaTimeSourceEnums.UN_PLAN_CLA_TIME.getSource());
+// addClaTime.setStatus(ClaTimeStatusEnums.HAD_CLASS.getStatus());
+// addClaTime.setPayHour(dbCla.getEveryStuLoseHour());
+// addClaTime.setNeedAttendCnt(needAttendCnt);
+// addClaTime.setRealAttendCnt(realAttendCnt.intValue());
+// addClaTime.setMemo(reqClaTimeAttend.getMemo());
+// addClaTime.setCreateUser(loginUser.getUserId());
+// addClaTime.setCreateTime(new Date());
+// addClaTime.setLastUpdateUser(loginUser.getUserId());
+// addClaTime.setLastUpdateTime(new Date());
+//
+// // 教室不为空 设置教室
+// if (null != reqClaTimeAttend.getRoomId()) {
+// ScRoom room = roomService.getById(reqClaTimeAttend.getRoomId());
+// addClaTime.setRoomId(reqClaTimeAttend.getRoomId());
+// addClaTime.setRoomName(room.getRoomName());
+// }
+//
+// claTimeService.save(addClaTime);
+// courseTimeId = addClaTime.getCourseTimeId();
+// }
+//
+// // 教师信息
+// SysStaff sysStaff = staffService.getById(teacherId);
+//
+// // 保存上课记录
+// List saveAttendList = com.google.common.collect.Lists.newArrayList();
+// // 保存学生日志
+// List studentCourseLogList = com.google.common.collect.Lists.newArrayList();
+//
+// for (ReqClaTimeAttendItem attendItem : studentAttendList) {
+// Long studentCourseId = attendItem.getStudentCourseId();
+// String attendStatus = attendItem.getAttendStatus();
+// String memo = attendItem.getMemo();
+// BigDecimal stuLoseHour = attendItem.getStuLoseHour();
+//
+// // 如果是请假,消耗课时0
+// if (ClaTimeAttendStatusEnums.LEAVE_CLASS.getAttendStatus().equals(attendStatus)) {
+// stuLoseHour = BigDecimal.ZERO;
+// }
+//
+// // 获取学生报读班级信息
+// ScStudentCourse studentCourse = studentCourseService.getById(studentCourseId);
+// String studentDbChargeType = studentCourse.getChargeType();
+//
+// // 消耗金额
+// BigDecimal payFee;
+// // 上课后剩余课时
+// BigDecimal changeAfterBalanceHour = null;
+// // 本次上课对应的订单
+// Long courseOrderId = null;
+//
+// if (CourseChargeTypeEnum.DATE.getChargeType().equals(studentDbChargeType)) {
+// // 按时间上课,不扣减课时
+//
+// // 获取 消耗金额
+// ScStudentCourseOrder courseOrder = courseOrderService.getNowValidDateOrder(studentCourseId);
+// payFee = courseOrder.getUnitFee();
+// courseOrderId = courseOrder.getCourseOrderId();
+//
+// } else {
+// // 本次上课对应的订单
+// ScStudentCourseOrder courseOrder = courseOrderService.getSubtractHourOrder(studentCourseId);
+// if (null == courseOrder) {
+// throw new BusinessException("无法获取对应课时订单,无法扣减课时,id=" + studentCourseId);
+// }
+// courseOrderId = courseOrder.getCourseOrderId();
+//
+// BigDecimal balanceHour = studentCourse.getBalanceHour();
+// balanceHour = balanceHour.subtract(stuLoseHour);
+//
+// changeAfterBalanceHour = balanceHour;
+//
+// // 课时不足 不允许上课
+// if (balanceHour.compareTo(BigDecimal.ZERO) < 0) {
+// throw new BusinessException("学员课时不足,不允许上课!");
+// }
+//
+// // 更新剩余课时 cas
+// UpdateWrapper uwStudentCourse = new UpdateWrapper<>();
+// uwStudentCourse
+// .eq("student_course_id", studentCourseId)
+// .eq("balance_hour", studentCourse.getBalanceHour())
+// .set("balance_hour", balanceHour)
+// .set("last_update_user", loginUser.getUserId())
+// .set("last_update_time", new Date());
+// boolean update = studentCourseService.update(uwStudentCourse);
+// if (!update) {
+// throw new BusinessException("学员课时余额扣减失败,请重试!");
+// }
+//
+// // 订单扣减课时,获取 消耗金额
+// payFee = courseOrderService.subtractCourseOrderBalanceHour(studentCourseId, stuLoseHour);
+// }
+//
+// // 消耗总金额
+// totalPayFee = totalPayFee.add(payFee);
+//
+// // 每个上课记录
+// ScClaTimeAttend addClaTimeAttend = new ScClaTimeAttend();
+// addClaTimeAttend.setStudentCourseId(studentCourseId);
+// addClaTimeAttend.setCourseOrderId(courseOrderId);
+// addClaTimeAttend.setCourseTimeId(courseTimeId);
+// addClaTimeAttend.setStudentId(studentCourse.getStudentId());
+// addClaTimeAttend.setClaId(studentCourse.getClaId());
+// addClaTimeAttend.setCourseId(studentCourse.getCourseId());
+// addClaTimeAttend.setTeacherId(teacherId);
+// addClaTimeAttend.setTeacherName(sysStaff.getStaffName());
+// addClaTimeAttend.setChargeType(studentDbChargeType);
+// if (CourseChargeTypeEnum.DATE.getChargeType().equals(studentDbChargeType)) {
+// addClaTimeAttend.setTeacherGetHour(null);
+// addClaTimeAttend.setPayHour(null);
+// } else {
+// addClaTimeAttend.setTeacherGetHour(stuLoseHour);
+// addClaTimeAttend.setPayHour(stuLoseHour);
+// totalPayHour = totalPayHour.add(stuLoseHour);
+// }
+// addClaTimeAttend.setAttendStatus(attendStatus);
+// addClaTimeAttend.setMemo(memo);
+// addClaTimeAttend.setCreateUser(loginUser.getUserId());
+// addClaTimeAttend.setPayFee(payFee);
+// saveAttendList.add(addClaTimeAttend);
+//
+// // 上课日志
+// StringBuffer sb = new StringBuffer("");
+// sb.append("上课[").append(ClaTimeAttendStatusEnums.getNameByStatus(attendStatus)).append("],上课时间").append(reqClaTimeAttend.getClaDate()).append(" ")
+// .append(reqClaTimeAttend.getStartTime()).append("~").append(reqClaTimeAttend.getEndTime()).append(",");
+// ScStudentCourseLog studentCourseLog = ScStudentCourseLog.builder()
+// .studentId(studentCourse.getStudentId())
+// .logType(LogTypeEnum.ATTEND_CLA.getLogType())
+// .courseId(scCourse.getCourseId())
+// .courseName(scCourse.getCourseName())
+// .claId(dbCla.getClaId())
+// .claName(dbCla.getClaName())
+// .deptName(sysDept.getDeptName())
+// .changeFee(payFee.negate())
+// .createUser(loginUser.getUserId())
+// .createUserName(loginUser.getName())
+// .createTime(new Date())
+// .build();
+// if (!CourseChargeTypeEnum.DATE.getChargeType().equals(studentDbChargeType)) {
+// studentCourseLog.setChangeHour(stuLoseHour.negate());
+// studentCourseLog.setAfterBalanceHour(changeAfterBalanceHour);
+// sb.append("扣减").append(stuLoseHour.toString()).append("课时,");
+// sb.append("消耗").append(payFee).append("元.");
+// }
+// studentCourseLog.setMemo(sb.toString());
+// studentCourseLogList.add(studentCourseLog);
+// }
+// // 保存上课记录
+// attendService.saveBatch(saveAttendList);
+// // 保存学生日志
+// scStudentCourseLogService.saveBatch(studentCourseLogList);
+//
+// // 更新上课总课时 人数信息
+// ScClaTime updateClaTime = new ScClaTime();
+// updateClaTime.setCourseTimeId(courseTimeId);
+// updateClaTime.setPayTotalHour(totalPayHour);
+// updateClaTime.setPayTotalFee(totalPayFee);
+// updateClaTime.setAtClassCnt(realAttendCnt.intValue());
+// updateClaTime.setLeaveCnt(leaveCnt.intValue());
+// updateClaTime.setOutCnt(outCnt.intValue());
+// claTimeService.updateById(updateClaTime);
+//
+// return APIResponse.toOkResponse();
+ return new RestResponse();
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java
index 2ab6d56..7f939b4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java
@@ -1,5 +1,6 @@
package com.ruoyi.im.domain;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -43,7 +44,12 @@ public class Friend {
/**
* 用户头像
*/
+ @TableField(exist = false)
private String friendHeadImage;
+ @TableField(exist = false)
+ private Long roleId;
+ @TableField(exist = false)
+ private Long storeId;
/**
* 是否已删除
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/Group.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Group.java
new file mode 100644
index 0000000..1882aa2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Group.java
@@ -0,0 +1,74 @@
+package com.ruoyi.im.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 群
+ *
+ * @author blue
+ * @since 2022-10-31
+ */
+@Data
+@TableName("im_group")
+public class Group implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+
+ /**
+ * 群名字
+ */
+ private String name;
+
+ /**
+ * 群主id
+ */
+ private Long ownerId;
+
+ /**
+ * 群头像
+ */
+ private String headImage;
+
+ /**
+ * 群头像缩略图
+ */
+ private String headImageThumb;
+
+ /**
+ * 群公告
+ */
+ private String notice;
+
+ /**
+ * 是否被封禁
+ */
+ private Boolean isBanned;
+
+ /**
+ * 被封禁原因
+ */
+ private String reason;
+
+ /**
+ * 创建时间
+ */
+ private Date createdTime;
+
+ /**
+ * 是否已删除
+ */
+ private Boolean dissolve;
+
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMember.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMember.java
new file mode 100644
index 0000000..9ab00b3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMember.java
@@ -0,0 +1,80 @@
+package com.ruoyi.im.domain;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ *
+ * 群成员
+ *
+ *
+ * @author blue
+ * @since 2022-10-31
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("im_group_member")
+public class GroupMember extends Model {
+
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+
+ /**
+ * 群id
+ */
+ private Long groupId;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 用户昵称
+ */
+ private String userNickName;
+
+ /**
+ * 显示昵称备注
+ */
+ private String remarkNickName;
+
+ /**
+ * 用户头像
+ */
+ private String headImage;
+
+ /**
+ * 显示群名备注
+ */
+ private String remarkGroupName;
+
+ /**
+ * 是否已退出
+ */
+ private Boolean quit;
+
+ /**
+ * 创建时间
+ */
+ private Date createdTime;
+
+ /**
+ * 退出时间
+ */
+ private Date quitTime;
+
+ public String getShowNickName() {
+ return StrUtil.blankToDefault(remarkNickName, userNickName);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java
new file mode 100644
index 0000000..43d4385
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java
@@ -0,0 +1,82 @@
+package com.ruoyi.im.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ *
+ * 群消息
+ *
+ *
+ * @author blue
+ * @since 2022-10-31
+ */
+@Data
+
+@TableName("im_group_message")
+public class GroupMessage {
+
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+
+ /**
+ * 群id
+ */
+ private Long groupId;
+
+ /**
+ * 发送用户id
+ */
+ private Long sendId;
+
+ /**
+ * 发送用户昵称
+ */
+ private String sendNickName;
+
+ /**
+ * 接受用户id,为空表示全体发送
+ */
+ private String recvIds;
+
+ /**
+ * @用户列表
+ */
+ private String atUserIds;
+ /**
+ * 发送内容
+ */
+ private String content;
+
+ /**
+ * 消息类型 MessageType
+ */
+ private Integer type;
+
+ /**
+ * 是否回执消息
+ */
+ private Boolean receipt;
+
+ /**
+ * 回执消息是否完成
+ */
+ private Boolean receiptOk;
+
+ /**
+ * 状态 MessageStatus
+ */
+ private Integer status;
+
+ /**
+ * 发送时间
+ */
+ private Date sendTime;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupInviteDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupInviteDTO.java
new file mode 100644
index 0000000..88e0250
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupInviteDTO.java
@@ -0,0 +1,23 @@
+package com.ruoyi.im.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+@Data
+@Schema(description = "邀请好友进群请求DTO")
+public class GroupInviteDTO {
+
+ @NotNull(message = "群id不可为空")
+ @Schema(description = "群id")
+ private Long groupId;
+
+ @Size(max = 50, message = "一次最多只能邀请50位用户")
+ @NotEmpty(message = "群id不可为空")
+ @Schema(description = "好友id列表不可为空")
+ private List friendIds;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMemberRemoveDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMemberRemoveDTO.java
new file mode 100644
index 0000000..079c33d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMemberRemoveDTO.java
@@ -0,0 +1,28 @@
+package com.ruoyi.im.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+/**
+ * @author Blue
+ * @version 1.0
+ * @date 2025-02-23
+ */
+@Data
+@Schema(description = "移除群聊成员")
+public class GroupMemberRemoveDTO {
+
+ @NotNull(message = "群id不可为空")
+ @Schema(description = "群组id")
+ private Long groupId;
+
+ @Size(max = 50, message = "一次最多只能选择50位用户")
+ @NotEmpty(message = "成员用户id不可为空")
+ @Schema(description = "成员用户id")
+ private List userIds;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java
new file mode 100644
index 0000000..a2bd8e8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java
@@ -0,0 +1,35 @@
+package com.ruoyi.im.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+@Data
+@Schema(description = "群聊消息DTO")
+public class GroupMessageDTO {
+
+ @NotNull(message = "群聊id不可为空")
+ @Schema(description = "群聊id")
+ private Long groupId;
+
+ @Length(max = 1024, message = "发送内容长度不得大于1024")
+ @NotEmpty(message = "发送内容不可为空")
+ @Schema(description = "发送内容")
+ private String content;
+
+ @NotNull(message = "消息类型不可为空")
+ @Schema(description = "消息类型 0:文字 1:图片 2:文件 3:语音 4:视频")
+ private Integer type;
+
+ @Schema(description = "是否回执消息")
+ private Boolean receipt = false;
+
+ @Size(max = 20, message = "一次最多只能@20个小伙伴哦")
+ @Schema(description = "被@用户列表")
+ private List atUserIds;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMemberVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMemberVO.java
new file mode 100644
index 0000000..d7edf6d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMemberVO.java
@@ -0,0 +1,34 @@
+package com.ruoyi.im.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "群成员信息VO")
+public class GroupMemberVO {
+
+ @Schema(description = "用户id")
+ private Long userId;
+
+ @Schema(description = "群内显示名称")
+ private String showNickName;
+
+ @Schema(description = "群内昵称备注")
+ private String remarkNickName;
+
+ @Schema(description = "头像")
+ private String headImage;
+
+ @Schema(description = "是否已退出")
+ private Boolean quit;
+
+ @Schema(description = "是否在线")
+ private Boolean online;
+
+ @Schema(description = "群名显示名称")
+ private String showGroupName;
+
+ @Schema(description = "群名备注")
+ private String remarkGroupName;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java
new file mode 100644
index 0000000..11ece7d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java
@@ -0,0 +1,50 @@
+package com.ruoyi.im.domain.vo;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.ruoyi.common.serializer.DateToLongSerializer;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class GroupMessageVO {
+
+ @Schema(description = "消息id")
+ private Long id;
+
+ @Schema(description = "群聊id")
+ private Long groupId;
+
+ @Schema(description = " 发送者id")
+ private Long sendId;
+
+ @Schema(description = " 发送者昵称")
+ private String sendNickName;
+
+ @Schema(description = "消息内容")
+ private String content;
+
+ @Schema(description = "消息内容类型 具体枚举值由应用层定义")
+ private Integer type;
+
+ @Schema(description = "是否回执消息")
+ private Boolean receipt;
+
+ @Schema(description = "回执消息是否完成")
+ private Boolean receiptOk;
+
+ @Schema(description = "已读消息数量")
+ private Integer readedCount = 0;
+
+ @Schema(description = "@用户列表")
+ private List atUserIds;
+
+ @Schema(description = " 状态")
+ private Integer status;
+
+ @Schema(description = "发送时间")
+ @JsonSerialize(using = DateToLongSerializer.class)
+ private Date sendTime;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupVO.java
new file mode 100644
index 0000000..a1b8e28
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupVO.java
@@ -0,0 +1,69 @@
+package com.ruoyi.im.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+@Data
+@Schema(description = "群信息VO")
+public class GroupVO {
+
+ @Schema(description = "群id")
+ private Long id;
+
+ @Length(max = 20, message = "群名称长度不能大于20")
+ @Schema(description = "群名称")
+ private String name;
+
+ @Schema(description = "群主id")
+ private Long ownerId;
+
+ @Schema(description = "头像")
+ private String headImage;
+
+ @Schema(description = "头像缩略图")
+ private String headImageThumb;
+
+ @Length(max = 1024, message = "群聊显示长度不能大于1024")
+ @Schema(description = "群公告")
+ private String notice;
+
+ @Length(max = 20, message = "显示昵称长度不能大于20")
+ @Schema(description = "用户在群显示昵称")
+ private String remarkNickName;
+
+ @Schema(description = "群内显示名称")
+ private String showNickName;
+
+ @Schema(description = "群名显示名称")
+ private String showGroupName;
+
+ @Length(max = 20, message = "群备注长度不能大于20")
+ @Schema(description = "群名备注")
+ private String remarkGroupName;
+
+ @Schema(description = "是否已解散")
+ private Boolean dissolve;
+
+ @Schema(description = "是否已退出")
+ private Boolean quit;
+
+ @Schema(description = "账号是否被封禁")
+ private Boolean isBanned;
+
+ @Schema(description = "被封禁原因")
+ private String reason;
+
+ /**
+ * 客服id
+ */
+ private Long customerService;
+ /**
+ * 教练id
+ */
+ private Long instructor;
+ private Long productId;
+
+ private String productName;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/listener/PrivateMessageListener.java b/ruoyi-system/src/main/java/com/ruoyi/im/listener/PrivateMessageListener.java
new file mode 100644
index 0000000..655f72c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/listener/PrivateMessageListener.java
@@ -0,0 +1,49 @@
+package com.ruoyi.im.listener;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.ruoyi.common.im.enums.IMListenerType;
+import com.ruoyi.common.im.enums.IMSendCode;
+import com.ruoyi.common.im.enums.MessageStatus;
+import com.ruoyi.common.im.model.IMSendResult;
+import com.ruoyi.im.domain.PrivateMessage;
+import com.ruoyi.im.domain.vo.PrivateMessageVO;
+import com.ruoyi.im.service.PrivateMessageService;
+import com.ruoyi.imclient.annotation.IMListener;
+import com.ruoyi.imclient.listener.MessageListener;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+@Slf4j
+@IMListener(type = IMListenerType.PRIVATE_MESSAGE)
+public class PrivateMessageListener implements MessageListener {
+ @Lazy
+ @Autowired
+ private PrivateMessageService privateMessageService;
+ @Override
+ public void process(List> results) {
+ Set messageIds = new HashSet<>();
+ for(IMSendResult result : results){
+ PrivateMessageVO messageInfo = result.getData();
+ // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态
+ if (result.getCode().equals(IMSendCode.SUCCESS.code()) && !Objects.isNull(messageInfo.getId())) {
+ messageIds.add(messageInfo.getId());
+ log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal());
+ }
+ }
+ // 批量修改状态
+ if(CollUtil.isNotEmpty(messageIds)){
+ UpdateWrapper updateWrapper = new UpdateWrapper<>();
+ updateWrapper.lambda().in(PrivateMessage::getId, messageIds)
+ .eq(PrivateMessage::getStatus, MessageStatus.UNSEND.code())
+ .set(PrivateMessage::getStatus, MessageStatus.SENDED.code());
+ privateMessageService.update(updateWrapper);
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java
index ebef85e..2ba5c6b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java
@@ -3,6 +3,11 @@ package com.ruoyi.im.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.im.domain.Friend;
+import java.util.List;
+
public interface FriendMapper extends BaseMapper {
+ List getFriendListForConsumer(Long userId);
+ List getFriendListForManage(Long userId);
+
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMapper.java
new file mode 100644
index 0000000..8951e0c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMapper.java
@@ -0,0 +1,14 @@
+package com.ruoyi.im.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.im.domain.Group;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface GroupMapper extends BaseMapper {
+
+ Long groupExist(@Param("userId") Long userId,
+ @Param("customer") Long customer,
+ @Param("instructor") Long instructor);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMemberMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMemberMapper.java
new file mode 100644
index 0000000..cfd9af2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMemberMapper.java
@@ -0,0 +1,8 @@
+package com.ruoyi.im.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.im.domain.GroupMember;
+
+public interface GroupMemberMapper extends BaseMapper {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMessageMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMessageMapper.java
new file mode 100644
index 0000000..93531e8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/GroupMessageMapper.java
@@ -0,0 +1,8 @@
+package com.ruoyi.im.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.im.domain.GroupMessage;
+
+public interface GroupMessageMapper extends BaseMapper {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/minioConfig/MinIoClientConfig.java b/ruoyi-system/src/main/java/com/ruoyi/im/minioConfig/MinIoClientConfig.java
index 7d82a4e..b23024d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/minioConfig/MinIoClientConfig.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/minioConfig/MinIoClientConfig.java
@@ -19,4 +19,4 @@ public class MinIoClientConfig {
.credentials(minioProps.getAccessKey(), minioProps.getSecretKey())
.build();
}
-}
\ No newline at end of file
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/FileService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/FileService.java
index 1e24562..516d95e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/service/FileService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/FileService.java
@@ -10,7 +10,7 @@ public interface FileService extends IService {
String uploadFile(MultipartFile file);
- UploadImageVO uploadImage(MultipartFile file, Boolean isPermanent);
+ UploadImageVO uploadImage(MultipartFile file,String tip, Boolean isPermanent);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java
index e1fb77b..4f9802e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java
@@ -3,8 +3,10 @@ package com.ruoyi.im.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.im.domain.Friend;
import com.ruoyi.im.domain.vo.FriendVO;
+import com.sun.javafx.collections.MappingChange;
import java.util.List;
+import java.util.Map;
public interface FriendService extends IService {
@@ -18,11 +20,11 @@ public interface FriendService extends IService {
Boolean isFriend(Long userId1, Long userId2);
/**
- * 查询用户的所有好友,包括已删除的
+ * 查询用户的所有好友
*
* @return 好友列表
*/
- List findAllFriends();
+ Map findAllFriends();
/**
* 查询用户的所有好友
@@ -32,12 +34,7 @@ public interface FriendService extends IService {
*/
List findByFriendIds(List friendIds);
- /**
- * 查询当前用户的所有好友
- *
- * @return 好友列表
- */
- List findFriends();
+
/**
* 添加好友,互相建立好友关系
@@ -71,4 +68,4 @@ public interface FriendService extends IService {
void bindFriend(Long userId, Long friendId);
-}
\ No newline at end of file
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMemberService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMemberService.java
new file mode 100644
index 0000000..fae9a11
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMemberService.java
@@ -0,0 +1,93 @@
+package com.ruoyi.im.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.im.domain.GroupMember;
+
+import java.util.List;
+
+public interface GroupMemberService extends IService {
+
+ /**
+ * 根据群聊id和用户id查询群聊成员
+ *
+ * @param groupId 群聊id
+ * @param userId 用户id
+ * @return 群聊成员信息
+ */
+ GroupMember findByGroupAndUserId(Long groupId, Long userId);
+
+
+ /**
+ * 根据用户id查询群聊成员
+ *
+ * @param userId 用户id
+ * @return 成员列表
+ */
+ List findByUserId(Long userId);
+
+ /**
+ * 根据用户id查询一个月内退的群
+ *
+ * @param userId 用户id
+ * @return 成员列表
+ */
+ List findQuitInMonth(Long userId);
+
+ /**
+ * 根据群聊id查询群聊成员(包括已退出)
+ *
+ * @param groupId 群聊id
+ * @return 群聊成员列表
+ */
+ List findByGroupId(Long groupId);
+
+
+
+ /**
+ * 根据群聊id查询没有退出的群聊成员id
+ *
+ * @param groupId 群聊id
+ * @return 群聊成员id列表
+ */
+ List findUserIdsByGroupId(Long groupId);
+
+ /**
+ * 批量添加成员
+ *
+ * @param groupId 群聊id
+ * @param members 成员列表
+ * @return 成功或失败
+ */
+ boolean saveOrUpdateBatch(Long groupId, List members);
+
+ /**
+ * 根据群聊id删除移除成员
+ *
+ * @param groupId 群聊id
+ */
+ void removeByGroupId(Long groupId);
+
+ /**
+ * 根据群聊id和用户id移除成员
+ *
+ * @param groupId 群聊id
+ * @param userId 用户id
+ */
+ void removeByGroupAndUserId(Long groupId, Long userId);
+
+ /**
+ * 根据群聊id和用户id移除成员
+ *
+ * @param groupId 群聊id
+ * @param userIds 用户id
+ */
+ void removeByGroupAndUserIds(Long groupId, List userIds);
+
+ /**
+ * 用户用户是否在群中
+ *
+ * @param groupId 群聊id
+ * @param userIds 用户id
+ */
+ Boolean isInGroup(Long groupId,List userIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java
new file mode 100644
index 0000000..b1f3333
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java
@@ -0,0 +1,64 @@
+package com.ruoyi.im.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.im.domain.GroupMessage;
+import com.ruoyi.im.domain.dto.GroupMessageDTO;
+import com.ruoyi.im.domain.vo.GroupMessageVO;
+
+import java.util.List;
+
+public interface GroupMessageService extends IService {
+
+ /**
+ * 发送群聊消息(高并发接口,查询mysql接口都要进行缓存)
+ *
+ * @param dto 群聊消息
+ * @return 群聊id
+ */
+ GroupMessageVO sendMessage(GroupMessageDTO dto);
+
+ /**
+ * 撤回消息
+ *
+ * @param id 消息id
+ */
+ GroupMessageVO recallMessage(Long id);
+
+ /**
+ * 拉取离线消息,只能拉取最近1个月的消息,最多拉取1000条
+ *
+ * @param minId 消息起始id
+ */
+ void pullOfflineMessage(Long minId);
+
+ /**
+ * 消息已读,同步其他终端,清空未读数量
+ *
+ * @param groupId 群聊
+ */
+ void readedMessage(Long groupId);
+
+ /**
+ * 查询群里消息已读用户id列表
+ * @param groupId 群里id
+ * @param messageId 消息id
+ * @return 已读用户id集合
+ */
+ List findReadedUsers(Long groupId,Long messageId);
+ /**
+ * 拉取历史聊天记录
+ *
+ * @param groupId 群聊id
+ * @param page 页码
+ * @param size 页码大小
+ * @return 聊天记录列表
+ */
+ List findHistoryMessage(Long groupId, Long page, Long size);
+
+ /**
+ * 获取某个会话中已读消息的最大id
+ *
+ * @param groupId 群id
+ */
+ String getMaxReadedId(Long groupId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java
new file mode 100644
index 0000000..7cbb487
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java
@@ -0,0 +1,46 @@
+package com.ruoyi.im.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.im.domain.Group;
+import com.ruoyi.im.domain.dto.GroupInviteDTO;
+import com.ruoyi.im.domain.vo.GroupVO;
+
+import java.util.List;
+
+public interface GroupService extends IService {
+
+ /**
+ * 创建新群聊
+ *
+ * @param vo 群聊信息
+ * @return 群聊信息
+ **/
+ GroupVO createGroup(GroupVO vo);
+
+
+ /**
+ * 根据id查找群聊
+ *
+ * @param groupId 群聊id
+ * @return 群聊vo
+ */
+ GroupVO findById(Long groupId);
+
+
+ /**
+ * 查询当前用户的所有群聊
+ *
+ * @return 群聊信息列表
+ **/
+ List findGroups();
+
+ /**
+ * 根据id查找群聊,并进行缓存
+ *
+ * @param groupId 群聊id
+ * @return 群聊实体
+ */
+ Group getAndCheckById(Long groupId);
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java
index 0397a84..39f155d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java
@@ -7,6 +7,7 @@ import com.ruoyi.im.domain.dto.PrivateMessageDTO;
import com.ruoyi.im.domain.vo.PrivateMessageVO;
import java.util.List;
+import java.util.Map;
public interface PrivateMessageService extends IService {
@@ -59,4 +60,5 @@ public interface PrivateMessageService extends IService {
*/
Long getMaxReadedId(Long friendId);
+ Map getConsultProduct(Long storeId);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FileServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FileServiceImpl.java
index 1fe0543..e0a002a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FileServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FileServiceImpl.java
@@ -57,7 +57,7 @@ public class FileServiceImpl extends ServiceImpl imple
@Override
public String uploadFile(MultipartFile file) {
try {
- Long userId = SecurityUtils.getUserId();
+ Long userId = SecurityUtils.getAppLoginUser().getAppUserId();
// 大小校验
if (file.getSize() > Constant_im.MAX_FILE_SIZE) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "文件大小不能超过20M");
@@ -77,7 +77,7 @@ public class FileServiceImpl extends ServiceImpl imple
if (StringUtils.isEmpty(fileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "文件上传失败");
}
- String url = generUrl(FileType.FILE, fileName);
+ String url = generUrl(FileType.FILE, fileName,"im");
// 保存文件
saveFileInfo(file, md5, url);
log.info("文件文件成功,用户id:{},url:{}", userId, url);
@@ -88,11 +88,18 @@ public class FileServiceImpl extends ServiceImpl imple
}
}
+ /**
+ *
+ * @param file
+ * @param tip "im"
+ * @param isPermanent
+ * @return
+ */
@Transactional
@Override
- public UploadImageVO uploadImage(MultipartFile file, Boolean isPermanent) {
+ public UploadImageVO uploadImage(MultipartFile file,String tip, Boolean isPermanent) {
try {
- Long userId = SecurityUtils.getUserId();
+ Long userId = SecurityUtils.getAppLoginUser().getAppUserId();
// 大小校验
if (file.getSize() > Constant_im.MAX_IMAGE_SIZE) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片大小不能超过20M");
@@ -116,25 +123,41 @@ public class FileServiceImpl extends ServiceImpl imple
return vo;
}
// 上传原图
- String fileName = minioSerivce.upload(minioProps.getBucketName(), minioProps.getImagePath(), file);
+ String fileName ="";
+ if (tip.equals("im")){
+ fileName=minioSerivce.upload(minioProps.getBucketName(), minioProps.getImagePath(), file);
+ }
+ if (tip.equals("app_avatar")){
+ fileName=minioSerivce.upload("yoga-im", "app-avatar", file);
+ }
+
+
if (StringUtils.isEmpty(fileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片上传失败");
}
- vo.setOriginUrl(generUrl(FileType.IMAGE, fileName));
+ vo.setOriginUrl(generUrl(FileType.IMAGE, fileName,tip));
if (file.getSize() > 50 * 1024) {
// 大于50K的文件需上传缩略图
byte[] imageByte = ImageUtil.compressForScale(file.getBytes(), 30);
- String thumbFileName = minioSerivce.upload(minioProps.getBucketName(), minioProps.getImagePath(),
- file.getOriginalFilename(), imageByte, file.getContentType());
+ String thumbFileName ="";
+ if (tip.equals("im")){
+ thumbFileName= minioSerivce.upload(minioProps.getBucketName(), minioProps.getImagePath(),
+ file.getOriginalFilename(), imageByte, file.getContentType());
+ }
+ if (tip.equals("app_avatar")){
+ thumbFileName= minioSerivce.upload("yoga-im", "app-avatar",
+ file.getOriginalFilename(), imageByte, file.getContentType());
+ }
+
if (StringUtils.isEmpty(thumbFileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片上传失败");
}
- vo.setThumbUrl(generUrl(FileType.IMAGE, thumbFileName));
+ vo.setThumbUrl(generUrl(FileType.IMAGE, thumbFileName,tip));
// 保存文件信息
saveImageFileInfo(file, md5, vo.getOriginUrl(), vo.getThumbUrl(), isPermanent);
}else{
// 小于50k,用原图充当缩略图
- vo.setThumbUrl(generUrl(FileType.IMAGE, fileName));
+ vo.setThumbUrl(generUrl(FileType.IMAGE, fileName,tip));
// 保存文件信息,由于缩略图不允许删除,此时原图也不允许删除
saveImageFileInfo(file, md5, vo.getOriginUrl(), vo.getThumbUrl(), true);
}
@@ -146,8 +169,15 @@ public class FileServiceImpl extends ServiceImpl imple
}
}
- private String generUrl(FileType fileType, String fileName) {
- return StrUtil.join("/", minioProps.getDomain(), minioProps.getBucketName(), getBucketPath(fileType), fileName);
+ private String generUrl(FileType fileType, String fileName,String tip) {
+// return StrUtil.join("/", minioProps.getDomain(), minioProps.getBucketName(), getBucketPath(fileType), fileName);
+ if (tip.equals("im")){
+ return StrUtil.join("/",minioProps.getEndpoint(), minioProps.getBucketName(), getBucketPath(fileType), fileName);
+ }
+ if (tip.equals("app_avatar")){
+ return StrUtil.join("/",minioProps.getEndpoint(), "yoga-im", "app-avatar", fileName);
+ }
+ return "";
}
private String getBucketPath(FileType fileType) {
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java
index 3d1659f..2696176 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.im.service.impl;
+import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -11,9 +12,7 @@ import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.im.domain.Friend;
import com.ruoyi.im.domain.vo.FriendVO;
import com.ruoyi.im.service.FriendService;
-import com.ruoyi.im.mapper.PrivateMessageMapper;
import com.ruoyi.im.mapper.FriendMapper;
-import com.ruoyi.imclient.IMClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
@@ -23,7 +22,9 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -32,18 +33,32 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
@CacheConfig(cacheNames = RedisKey.IM_CACHE_FRIEND)
public class FriendServiceImpl extends ServiceImpl implements FriendService {
- private final PrivateMessageMapper privateMessageMapper;
-// private final UserMapper userMapper;
- private final IMClient imClient;
+
@Override
- public List findAllFriends() {
+ public Map findAllFriends() {
Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId();
- LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
- wrapper.eq(Friend::getUserId, userId);
- return this.list(wrapper);
+ Map> map=new HashMap<>();
+ Long manageId= SecurityUtils.getAppLoginUser().getAppUser().getManageAccountId();
+ if (ObjectUtil.isNotEmpty(manageId)){
+ List list=baseMapper.getFriendListForManage(userId);
+ map.put("consumer",list);
+ return map;
+ }
+
+ List list=baseMapper.getFriendListForConsumer(userId);
+ Map> friendMap = list.stream().collect(Collectors.groupingBy(Friend::getRoleId));
+
+ map.put("storeManager",friendMap.get(105l));
+ map.put("coach",friendMap.get(104l));
+ map.put("adviser",friendMap.get(103l));
+ map.put("customerService",friendMap.get(108l));
+
+ return map;
+
}
+
@Override
public List findByFriendIds(List friendIds) {
Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId();
@@ -54,11 +69,7 @@ public class FriendServiceImpl extends ServiceImpl impleme
return this.list(wrapper);
}
- @Override
- public List findFriends() {
- List friends = this.findAllFriends();
- return friends.stream().map(this::conver).collect(Collectors.toList());
- }
+
@Transactional(rollbackFor = Exception.class)
@Override
@@ -151,7 +162,8 @@ public class FriendServiceImpl extends ServiceImpl impleme
wrapper.eq(Friend::getFriendId, friendId);
Friend friend = this.getOne(wrapper);
if (Objects.isNull(friend)) {
- throw new GlobalException("对方不是您的好友");
+ addFriend(friendId);
+// throw new GlobalException("对方不是您的好友");
}
return conver(friend);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMemberServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMemberServiceImpl.java
new file mode 100644
index 0000000..3156c3d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMemberServiceImpl.java
@@ -0,0 +1,123 @@
+package com.ruoyi.im.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.im.constant.RedisKey;
+import com.ruoyi.im.domain.GroupMember;
+import com.ruoyi.im.mapper.GroupMemberMapper;
+import com.ruoyi.im.service.GroupMemberService;
+import com.ruoyi.im.util.DateTimeUtils;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER_ID)
+public class GroupMemberServiceImpl extends ServiceImpl implements GroupMemberService {
+ @CacheEvict(key = "#member.getGroupId()")
+ @Override
+ public boolean save(GroupMember member) {
+ return super.save(member);
+ }
+
+ @CacheEvict(key = "#groupId")
+ @Override
+ public boolean saveOrUpdateBatch(Long groupId, List members) {
+ return super.saveOrUpdateBatch(members);
+ }
+
+ @Override
+ public GroupMember findByGroupAndUserId(Long groupId, Long userId) {
+ LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
+ wrapper.eq(GroupMember::getGroupId, groupId);
+ wrapper.eq(GroupMember::getUserId, userId);
+ return this.getOne(wrapper);
+ }
+
+
+ @Override
+ public List findByUserId(Long userId) {
+ LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery();
+ memberWrapper.eq(GroupMember::getUserId, userId).eq(GroupMember::getQuit, false);
+ return this.list(memberWrapper);
+ }
+
+ @Override
+ public List findQuitInMonth(Long userId) {
+ Date monthTime = DateTimeUtils.addMonths(new Date(), -1);
+ LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery();
+ memberWrapper.eq(GroupMember::getUserId, userId).eq(GroupMember::getQuit, true)
+ .ge(GroupMember::getQuitTime, monthTime);
+ return this.list(memberWrapper);
+ }
+
+ @Override
+ public List findByGroupId(Long groupId) {
+ LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery();
+ memberWrapper.eq(GroupMember::getGroupId, groupId);
+ return this.list(memberWrapper);
+ }
+
+ @Cacheable(key = "#groupId")
+ @Override
+ public List findUserIdsByGroupId(Long groupId) {
+ LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery();
+ memberWrapper.eq(GroupMember::getGroupId, groupId).eq(GroupMember::getQuit, false)
+ .select(GroupMember::getUserId);
+ List members = this.list(memberWrapper);
+ return members.stream().map(GroupMember::getUserId).collect(Collectors.toList());
+ }
+
+ @CacheEvict(key = "#groupId")
+ @Override
+ public void removeByGroupId(Long groupId) {
+ LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate();
+ wrapper.eq(GroupMember::getGroupId, groupId).set(GroupMember::getQuit, true)
+ .set(GroupMember::getQuitTime, new Date());
+ this.update(wrapper);
+ }
+
+ @CacheEvict(key = "#groupId")
+ @Override
+ public void removeByGroupAndUserId(Long groupId, Long userId) {
+ LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate();
+ wrapper.eq(GroupMember::getGroupId, groupId);
+ wrapper.eq(GroupMember::getUserId, userId);
+ wrapper.set(GroupMember::getQuit, true);
+ wrapper.set(GroupMember::getQuitTime, new Date());
+ this.update(wrapper);
+ }
+
+ @CacheEvict(key = "#groupId")
+ @Override
+ public void removeByGroupAndUserIds(Long groupId, List userId) {
+ LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate();
+ wrapper.eq(GroupMember::getGroupId, groupId);
+ wrapper.in(GroupMember::getUserId, userId);
+ wrapper.set(GroupMember::getQuit, true);
+ wrapper.set(GroupMember::getQuitTime, new Date());
+ this.update(wrapper);
+ }
+
+
+ @Override
+ public Boolean isInGroup(Long groupId, List userIds) {
+ if (CollectionUtils.isEmpty(userIds)) {
+ return true;
+ }
+ LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
+ wrapper.eq(GroupMember::getGroupId, groupId);
+ wrapper.eq(GroupMember::getQuit, false);
+ wrapper.in(GroupMember::getUserId, userIds);
+ return userIds.size() == this.count(wrapper);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java
new file mode 100644
index 0000000..014ae9d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java
@@ -0,0 +1,394 @@
+package com.ruoyi.im.service.impl;
+
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.domain.entity.AppUser;
+import com.ruoyi.common.exception.GlobalException;
+import com.ruoyi.common.im.constant.IMConstant;
+import com.ruoyi.common.im.constant.RedisKey;
+import com.ruoyi.common.im.enums.IMTerminalType;
+import com.ruoyi.common.im.enums.MessageStatus;
+import com.ruoyi.common.im.enums.MessageType;
+import com.ruoyi.common.im.model.IMGroupMessage;
+import com.ruoyi.common.im.model.IMUserInfo;
+import com.ruoyi.common.im.util.BeanUtils;
+import com.ruoyi.common.im.util.CommaTextUtils;
+import com.ruoyi.common.im.util.ThreadPoolExecutorFactory;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.im.domain.Group;
+import com.ruoyi.im.domain.GroupMember;
+import com.ruoyi.im.domain.GroupMessage;
+import com.ruoyi.im.domain.PrivateMessage;
+import com.ruoyi.im.domain.dto.GroupMessageDTO;
+import com.ruoyi.im.domain.vo.GroupMessageVO;
+import com.ruoyi.im.mapper.GroupMessageMapper;
+import com.ruoyi.im.service.GroupMemberService;
+import com.ruoyi.im.service.GroupMessageService;
+import com.ruoyi.im.service.GroupService;
+import com.ruoyi.im.util.SensitiveFilterUtil;
+import com.ruoyi.imclient.IMClient;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GroupMessageServiceImpl extends ServiceImpl
+ implements GroupMessageService {
+ private final GroupService groupService;
+ private final GroupMemberService groupMemberService;
+ private final RedisTemplate redisTemplate;
+ private final IMClient imClient;
+ private final SensitiveFilterUtil sensitiveFilterUtil;
+ private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor();
+
+ @Override
+ public GroupMessageVO sendMessage(GroupMessageDTO dto) {
+ AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
+ Group group = groupService.getAndCheckById(dto.getGroupId());
+ // 是否在群聊里面
+ GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getId());
+ if (Objects.isNull(member) || member.getQuit()) {
+ throw new GlobalException("您已不在群聊里面,无法发送消息");
+ }
+ // 群聊成员列表
+ List userIds = groupMemberService.findUserIdsByGroupId(group.getId());
+ if (dto.getReceipt() && userIds.size() > 10L) {
+ // 大群的回执消息过于消耗资源,不允许发送
+ throw new GlobalException(
+ String.format("当前群聊大于%s人,不支持发送回执消息", 10L));
+ }
+ // 不用发给自己
+ userIds = userIds.stream().filter(id -> !session.getId().equals(id)).collect(Collectors.toList());
+ // 保存消息
+ GroupMessage msg = BeanUtils.copyProperties(dto, GroupMessage.class);
+ msg.setSendId(session.getId());
+ msg.setSendTime(new Date());
+ msg.setSendNickName(member.getShowNickName());
+ msg.setAtUserIds(CommaTextUtils.asText(dto.getAtUserIds()));
+ // 过滤内容中的敏感词
+ if (MessageType.TEXT.code().equals(dto.getType())) {
+ msg.setContent(sensitiveFilterUtil.filter(dto.getContent()));
+ }
+ this.save(msg);
+ // 群发
+ GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class);
+ msgInfo.setAtUserIds(dto.getAtUserIds());
+ IMGroupMessage sendMessage = new IMGroupMessage<>();
+ sendMessage.setSender(new IMUserInfo(session.getId(), 1));
+ sendMessage.setRecvIds(userIds);
+ sendMessage.setSendResult(false);
+ sendMessage.setData(msgInfo);
+ imClient.sendGroupMessage(sendMessage);
+ log.info("发送群聊消息,发送id:{},群聊id:{},内容:{}", session.getId(), dto.getGroupId(), dto.getContent());
+ return msgInfo;
+ }
+
+ @Transactional
+ @Override
+ public GroupMessageVO recallMessage(Long id) {
+ GroupMessage msg = this.getById(id);
+ if (Objects.isNull(msg)) {
+ throw new GlobalException("消息不存在");
+ }
+ if (!msg.getSendId().equals(SecurityUtils.getAppLoginUser().getAppUserId())) {
+ throw new GlobalException("这条消息不是由您发送,无法撤回");
+ }
+ if (System.currentTimeMillis() - msg.getSendTime().getTime() > IMConstant.ALLOW_RECALL_SECOND * 1000) {
+ throw new GlobalException("消息已发送超过5分钟,无法撤回");
+ }
+ // 判断是否在群里
+ GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), SecurityUtils.getAppLoginUser().getAppUserId());
+ if (Objects.isNull(member) || Boolean.TRUE.equals(member.getQuit())) {
+ throw new GlobalException("您已不在群聊里面,无法撤回消息");
+ }
+ // 修改数据库
+ msg.setStatus(MessageStatus.RECALL.code());
+ this.updateById(msg);
+ // 生成一条撤回消息
+ GroupMessage recallMsg = new GroupMessage();
+ recallMsg.setStatus(MessageStatus.UNSEND.code());
+ recallMsg.setType(MessageType.RECALL.code());
+ recallMsg.setGroupId(msg.getGroupId());
+ recallMsg.setSendId(SecurityUtils.getAppLoginUser().getAppUserId());
+ recallMsg.setSendNickName(member.getShowNickName());
+ recallMsg.setContent(id.toString());
+ recallMsg.setSendTime(new Date());
+ this.save(recallMsg);
+ // 群发
+ List userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId());
+ GroupMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, GroupMessageVO.class);
+ IMGroupMessage sendMessage = new IMGroupMessage<>();
+ sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1));
+ sendMessage.setRecvIds(userIds);
+ sendMessage.setData(msgInfo);
+ imClient.sendGroupMessage(sendMessage);
+ log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}", SecurityUtils.getAppLoginUser().getAppUserId(), msg.getGroupId(), msg.getContent());
+ return msgInfo;
+ }
+
+ @Override
+ public void pullOfflineMessage(Long minId) {
+ if (!imClient.isOnline(SecurityUtils.getAppLoginUser().getAppUserId())) {
+ throw new GlobalException("网络连接失败,无法拉取离线消息");
+ }
+ // 查询用户加入的群组
+ List members = groupMemberService.findByUserId(SecurityUtils.getAppLoginUser().getAppUserId());
+ Map groupMemberMap = CollStreamUtil.toIdentityMap(members, GroupMember::getGroupId);
+ Set groupIds = groupMemberMap.keySet();
+ if (CollectionUtil.isEmpty(groupIds)) {
+ // 关闭加载中标志
+ this.sendLoadingMessage(false);
+ return;
+ }
+
+ // 只能拉取最近3个月的,移动端只拉最近一个月
+ int months = new Integer(1).equals(IMTerminalType.APP.code()) ? 1 : 3;
+ Date minDate = DateUtils.addMonths(new Date(), -months);
+ LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
+ wrapper.gt(GroupMessage::getId, minId)
+ .gt(GroupMessage::getSendTime, minDate)
+ .in(GroupMessage::getGroupId, groupIds)
+ .orderByAsc(GroupMessage::getId);
+ List messages = this.list(wrapper);
+ // 通过群聊对消息进行分组
+ Map> messageGroupMap =
+ messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId));
+ // 退群前的消息
+ List quitMembers = groupMemberService.findQuitInMonth(SecurityUtils.getAppLoginUser().getAppUserId());
+ for (GroupMember quitMember : quitMembers) {
+ wrapper = Wrappers.lambdaQuery();
+ wrapper.gt(GroupMessage::getId, minId).between(GroupMessage::getSendTime, minDate, quitMember.getQuitTime())
+ .eq(GroupMessage::getGroupId, quitMember.getGroupId())
+ .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByAsc(GroupMessage::getId);
+ List groupMessages = this.list(wrapper);
+ messageGroupMap.put(quitMember.getGroupId(), groupMessages);
+ groupMemberMap.put(quitMember.getGroupId(), quitMember);
+ }
+ EXECUTOR.execute(() -> {
+ // 开启加载中标志
+ this.sendLoadingMessage(true);
+ // 推送消息
+ AtomicInteger sendCount = new AtomicInteger();
+ messageGroupMap.forEach((groupId, groupMessages) -> {
+ // 第一次拉取时,一个群最多推送1w条消息,防止前端接收能力溢出导致卡顿
+ List sendMessages = groupMessages;
+ if (minId <= 0 && groupMessages.size() > 10000) {
+ sendMessages = groupMessages.subList(groupMessages.size() - 10000, groupMessages.size());
+ }
+ // 填充消息状态
+ String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId);
+ Object o = redisTemplate.opsForHash().get(key, SecurityUtils.getAppLoginUser().getAppUserId().toString());
+ long readedMaxId = Objects.isNull(o) ? -1 : Long.parseLong(o.toString());
+ Map