Pārlūkot izejas kodu

Merge branch 'saas' of http://git.dayaedu.com/yonge/mec into zouxuan_saas_order_export

 Conflicts:
	mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ExportTypeEnum.java
zouxuan 3 gadi atpakaļ
vecāks
revīzija
eb01e6d3ab
42 mainītis faili ar 2495 papildinājumiem un 46 dzēšanām
  1. 15 0
      audio-analysis/src/main/java/com/yonge/audio/AudioAnalysisServerApplication.java
  2. 8 0
      audio-analysis/src/main/java/com/yonge/netty/server/service/AudioCompareHandler.java
  3. 8 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/IndexBaseMonthDataDao.java
  4. 14 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/StudentBasicInfoDao.java
  5. 59 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/StudentStatisticsDao.java
  6. 64 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentImportDto.java
  7. 16 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsDto.java
  8. 116 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsSumDto.java
  9. 49 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsSumForDateDto.java
  10. 1 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ManagerDownload.java
  11. 184 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentBasicInfo.java
  12. 311 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentStatistics.java
  13. 46 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentVisit.java
  14. 1 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ExportTypeEnum.java
  15. 9 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/FivePlusGradeEnum.java
  16. 5 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/IndexDataType.java
  17. 2 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/OrderTypeEnum.java
  18. 9 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/SixPlusGradeEnum.java
  19. 1 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/TemplateTypeEnum.java
  20. 165 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/page/StudentStatisticsQueryInfo.java
  21. 11 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/page/StudentVisitQueryInfo.java
  22. 1 4
      mec-biz/src/main/java/com/ym/mec/biz/event/listener/CourseEventListener.java
  23. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ExportService.java
  24. 34 0
      mec-biz/src/main/java/com/ym/mec/biz/service/StudentStatisticsService.java
  25. 45 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ExportServiceImpl.java
  26. 11 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/IndexBaseMonthDataServiceImpl.java
  27. 419 31
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/MusicGroupServiceImpl.java
  28. 126 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentStatisticsServiceImpl.java
  29. 7 1
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/SysMusicCompareRecordServiceImpl.java
  30. 52 0
      mec-biz/src/main/resources/config/mybatis/IndexBaseMonthDataMapper.xml
  31. 106 0
      mec-biz/src/main/resources/config/mybatis/StudentBasicInfoMapper.xml
  32. 410 0
      mec-biz/src/main/resources/config/mybatis/StudentStatisticsMapper.xml
  33. 11 3
      mec-biz/src/main/resources/config/mybatis/StudentVisitMapper.xml
  34. 3 3
      mec-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml
  35. 6 0
      mec-client-api/src/main/java/com/ym/mec/task/TaskRemoteService.java
  36. 5 0
      mec-client-api/src/main/java/com/ym/mec/task/fallback/TaskRemoteServiceFallback.java
  37. 19 0
      mec-task/src/main/java/com/ym/mec/task/jobs/StudentSmallClassStatisticsTask.java
  38. 16 0
      mec-util/src/main/java/com/ym/mec/util/validator/CommonValidator.java
  39. 0 1
      mec-web/src/main/java/com/ym/mec/web/controller/CourseScheduleController.java
  40. 119 0
      mec-web/src/main/java/com/ym/mec/web/controller/StudentStatisticsController.java
  41. 8 0
      mec-web/src/main/java/com/ym/mec/web/controller/TaskController.java
  42. BIN
      mec-web/src/main/resources/excelTemplate/外部学生入团导入模板.xls

+ 15 - 0
audio-analysis/src/main/java/com/yonge/audio/AudioAnalysisServerApplication.java

@@ -1,17 +1,23 @@
 package com.yonge.audio;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 
 import com.spring4all.swagger.EnableSwagger2Doc;
+import com.ym.mec.common.config.LocalFastJsonHttpMessageConverter;
 
 @SpringBootApplication
 @EnableDiscoveryClient
@@ -31,4 +37,13 @@ public class AudioAnalysisServerApplication {
 	public RestTemplate restTemplate() {
 		return new RestTemplate();
 	}
+	
+	@Bean
+    public HttpMessageConverters fastJsonHttpMessageConverters(){
+		LocalFastJsonHttpMessageConverter converter = new LocalFastJsonHttpMessageConverter();
+        List<MediaType> fastMediaTypes =  new ArrayList<MediaType>();
+        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
+        converter.setSupportedMediaTypes(fastMediaTypes);
+        return new HttpMessageConverters(converter);
+    }
 }

+ 8 - 0
audio-analysis/src/main/java/com/yonge/netty/server/service/AudioCompareHandler.java

@@ -25,6 +25,8 @@ import org.springframework.stereotype.Component;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONPath;
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.entity.SysMusicCompareRecord;
 import com.ym.mec.biz.dal.enums.DeviceTypeEnum;
 import com.ym.mec.biz.dal.enums.FeatureType;
@@ -57,6 +59,9 @@ public class AudioCompareHandler implements MessageHandler {
 	
 	@Autowired
 	private SysMusicCompareRecordService sysMusicCompareRecordService;
+	
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
 
     @Autowired
     private StoragePluginContext storagePluginContext;
@@ -149,6 +154,9 @@ public class AudioCompareHandler implements MessageHandler {
 				sysMusicCompareRecord.setSpeed(musicXmlBasicInfo.getSpeed());
 				sysMusicCompareRecord.setPartIndex(musicXmlBasicInfo.getPartIndex());
 				
+				SysUser sysUser = sysUserFeignService.queryUserById(sysMusicCompareRecord.getUserId());
+				sysMusicCompareRecord.setTenantId(sysUser.getTenantId());
+				
 				MusicXmlNote musicXmlNote = musicXmlBasicInfo.getMusicXmlInfos().stream().max(Comparator.comparing(MusicXmlNote::getTimeStamp)).get();
 				sysMusicCompareRecord.setSourceTime((float) ((musicXmlNote.getTimeStamp()+musicXmlNote.getDuration())/1000));
 				sysMusicCompareRecordService.insert(sysMusicCompareRecord);

+ 8 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/IndexBaseMonthDataDao.java

@@ -389,4 +389,12 @@ public interface IndexBaseMonthDataDao extends BaseDAO<Long, IndexBaseMonthData>
      */
     List<CloudTeacherActiveTargetDto> countCloudTeacherActive(Map<String, Object> params);
 
+    //获取vip课订单数量
+    List<IndexBaseMonthData> getStudentVipOrderNum(@Param("dayStr") String dayStr,@Param("tenantId") Integer tenantId);
+
+    //获取乐理课订单数量
+    List<IndexBaseMonthData> getStudentTheoryOrderNum(@Param("dayStr") String dayStr,@Param("tenantId") Integer tenantId);
+
+    //获取网管课订单数量
+    List<IndexBaseMonthData> getStudentPracticeOrderNum(@Param("dayStr") String dayStr,@Param("tenantId") Integer tenantId);
 }

+ 14 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/StudentBasicInfoDao.java

@@ -0,0 +1,14 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.biz.dal.entity.StudentBasicInfo;
+import org.apache.ibatis.annotations.Param;
+
+public interface StudentBasicInfoDao extends BaseDAO<Integer, StudentBasicInfo> {
+
+
+    Integer getMaxId();
+
+    //更新声部班老师
+    void updateSubjectTeacher();
+}

+ 59 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/StudentStatisticsDao.java

@@ -0,0 +1,59 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.biz.dal.dto.StudentStatisticsDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumDto;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.biz.dal.entity.StudentStatistics;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+public interface StudentStatisticsDao extends BaseDAO<Integer, StudentStatistics> {
+
+    //更新乐团主管、指导老师
+    void updateTeacherAndEdu();
+
+    //更新总课时数、已完成、剩余课时数、最近30天课耗
+    void updateCourseNum();
+
+    //更新未排课总数
+    void updateNoCourseNum();
+
+    //更新未开始价值
+    void updateNotStartCourseFee();
+
+    //更新未排课课程价值
+    void updateNoCourseFee();
+
+    //更新第一次课的时间\最近一次课时间
+    void updateFirstAndLastCourseTime();
+
+    int countStatistics(Map<String, Object> params);
+
+    List<StudentStatisticsDto> queryStatistics(Map<String, Object> params);
+
+    //更新进行中课程组数量
+    void updateNormalGroupNum();
+
+    //汇总小课数据
+    StudentStatisticsSumDto studentSmallClassStatisticsSum(@Param("groupType") String groupType, @Param("organIdList") List<Integer> organIdList);
+
+    //统计新增人数
+    Integer countAddStudentNum(@Param("groupType") String groupType, @Param("startDate") String startDate, @Param("endDate") String endDate, @Param("organIdList") List<Integer> organIdList);
+
+    //统计续费人数
+    Integer countRenewStudentNum(@Param("groupType") String groupType, @Param("endDate") String endDate, @Param("organIdList") List<Integer> organIdList);
+
+    //统计回访人数
+    Integer countVisitNum(@Param("groupType") String groupType, @Param("startDate") String startDate, @Param("endDate") String endDate, @Param("organIdList") List<Integer> organIdList);
+
+    //统计流失人数
+    Integer countLostStudentNum(@Param("groupType") String groupType, @Param("startDate") String startDate, @Param("endDate") String endDate, @Param("organIdList") List<Integer> organIdList);
+
+    //获取指导老师列表
+    List<Integer> queryTeacherIds(@Param("groupType") String groupType);
+
+    //获取乐团主管
+    List<Integer> queryDirectorList(@Param("groupType") String groupType);
+}

+ 64 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentImportDto.java

@@ -0,0 +1,64 @@
+package com.ym.mec.biz.dal.dto;
+
+public class StudentImportDto {
+
+	private String name;
+	
+	private String mobileNo;
+	
+	private String sex;
+	
+	private String subjectName;
+	
+	private String gradeName;
+	
+	private Integer userId;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getMobileNo() {
+		return mobileNo;
+	}
+
+	public void setMobileNo(String mobileNo) {
+		this.mobileNo = mobileNo;
+	}
+
+	public String getSex() {
+		return sex;
+	}
+
+	public void setSex(String sex) {
+		this.sex = sex;
+	}
+
+	public String getSubjectName() {
+		return subjectName;
+	}
+
+	public void setSubjectName(String subjectName) {
+		this.subjectName = subjectName;
+	}
+
+	public String getGradeName() {
+		return gradeName;
+	}
+
+	public void setGradeName(String gradeName) {
+		this.gradeName = gradeName;
+	}
+
+	public Integer getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+}

+ 16 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsDto.java

@@ -0,0 +1,16 @@
+package com.ym.mec.biz.dal.dto;
+
+import com.ym.mec.biz.dal.entity.StudentBasicInfo;
+import com.ym.mec.biz.dal.entity.StudentStatistics;
+
+public class StudentStatisticsDto extends StudentStatistics {
+    private StudentBasicInfo studentBasicInfo;
+
+    public StudentBasicInfo getStudentBasicInfo() {
+        return studentBasicInfo;
+    }
+
+    public void setStudentBasicInfo(StudentBasicInfo studentBasicInfo) {
+        this.studentBasicInfo = studentBasicInfo;
+    }
+}

+ 116 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsSumDto.java

@@ -0,0 +1,116 @@
+package com.ym.mec.biz.dal.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class StudentStatisticsSumDto {
+
+    @ApiModelProperty(value = "沉睡学员总数:有课耗且有【未开始】课程的学生中,近一年无课耗学生总数",required = false)
+    private Integer sleepStudentNum;
+
+    @ApiModelProperty(value = "有未排课:沉睡学员中,有未排课资格的学数量",required = false)
+    private Integer sleepStudentHasNotSchedule;
+
+    @ApiModelProperty(value = "无未排课:沉睡学员中,无未排课资格的学数量",required = false)
+    private Integer sleepStudentNoNotSchedule;
+
+    @ApiModelProperty(value = "在读学员总数:有【未开始】+【未排课】+ 近一年有课耗学生总数",required = false)
+    private Integer normalStudentNum;
+
+    @ApiModelProperty(value = "进行中:【在读学员总数】中有【进行中】状态课程组的学生数量",required = false)
+    private Integer normalStudentHasNormalGroupNum;
+
+    @ApiModelProperty(value = "暂停:有课程余额且没有剩余课时",required = false)
+    private Integer hasCourseBalanceAndNotSubCourseNum;
+
+    @ApiModelProperty(value = "未排课:【在读学员总数】中有未排课资格的学员数量",required = false)
+    private Integer normalStudentHasNoScheduleNum;
+
+    @ApiModelProperty(value = "待续费人数:【未开始】+【未排课】课时数≤3节",required = false)
+    private Integer waitRenewNum;
+
+    @ApiModelProperty(value = "未开始课时:【未开始】课程总数",required = false)
+    private Integer subCourseNum;
+
+    @ApiModelProperty(value = "未排课课时:活动资格【未排课】课程总数(1v多不去重)",required = false)
+    private Integer noScheduleNum;
+
+    public Integer getSleepStudentNum() {
+        return sleepStudentNum;
+    }
+
+    public void setSleepStudentNum(Integer sleepStudentNum) {
+        this.sleepStudentNum = sleepStudentNum;
+    }
+
+    public Integer getSleepStudentHasNotSchedule() {
+        return sleepStudentHasNotSchedule;
+    }
+
+    public void setSleepStudentHasNotSchedule(Integer sleepStudentHasNotSchedule) {
+        this.sleepStudentHasNotSchedule = sleepStudentHasNotSchedule;
+    }
+
+    public Integer getSleepStudentNoNotSchedule() {
+        return sleepStudentNoNotSchedule;
+    }
+
+    public void setSleepStudentNoNotSchedule(Integer sleepStudentNoNotSchedule) {
+        this.sleepStudentNoNotSchedule = sleepStudentNoNotSchedule;
+    }
+
+    public Integer getNormalStudentNum() {
+        return normalStudentNum;
+    }
+
+    public void setNormalStudentNum(Integer normalStudentNum) {
+        this.normalStudentNum = normalStudentNum;
+    }
+
+    public Integer getNormalStudentHasNormalGroupNum() {
+        return normalStudentHasNormalGroupNum;
+    }
+
+    public void setNormalStudentHasNormalGroupNum(Integer normalStudentHasNormalGroupNum) {
+        this.normalStudentHasNormalGroupNum = normalStudentHasNormalGroupNum;
+    }
+
+    public Integer getHasCourseBalanceAndNotSubCourseNum() {
+        return hasCourseBalanceAndNotSubCourseNum;
+    }
+
+    public void setHasCourseBalanceAndNotSubCourseNum(Integer hasCourseBalanceAndNotSubCourseNum) {
+        this.hasCourseBalanceAndNotSubCourseNum = hasCourseBalanceAndNotSubCourseNum;
+    }
+
+    public Integer getNormalStudentHasNoScheduleNum() {
+        return normalStudentHasNoScheduleNum;
+    }
+
+    public void setNormalStudentHasNoScheduleNum(Integer normalStudentHasNoScheduleNum) {
+        this.normalStudentHasNoScheduleNum = normalStudentHasNoScheduleNum;
+    }
+
+    public Integer getWaitRenewNum() {
+        return waitRenewNum;
+    }
+
+    public void setWaitRenewNum(Integer waitRenewNum) {
+        this.waitRenewNum = waitRenewNum;
+    }
+
+    public Integer getSubCourseNum() {
+        return subCourseNum;
+    }
+
+    public void setSubCourseNum(Integer subCourseNum) {
+        this.subCourseNum = subCourseNum;
+    }
+
+    public Integer getNoScheduleNum() {
+        return noScheduleNum;
+    }
+
+    public void setNoScheduleNum(Integer noScheduleNum) {
+        this.noScheduleNum = noScheduleNum;
+    }
+}

+ 49 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/StudentStatisticsSumForDateDto.java

@@ -0,0 +1,49 @@
+package com.ym.mec.biz.dal.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class StudentStatisticsSumForDateDto {
+    @ApiModelProperty(value = "流失人数",required = false)
+    private Integer lostNum;
+
+    @ApiModelProperty(value = "新增人数:以前没课,所选时间段内新增课程或排课资格的学员",required = false)
+    private Integer addNum;
+
+    @ApiModelProperty(value = "续费人数:所选结束时间之前有多笔大于0元的付费订单(活动赠送不算)",required = false)
+    private Integer renewNum;
+
+    @ApiModelProperty(value = "回访人数",required = false)
+    private Integer visitNum;
+
+    public Integer getLostNum() {
+        return lostNum;
+    }
+
+    public void setLostNum(Integer lostNum) {
+        this.lostNum = lostNum;
+    }
+
+    public Integer getAddNum() {
+        return addNum;
+    }
+
+    public void setAddNum(Integer addNum) {
+        this.addNum = addNum;
+    }
+
+    public Integer getRenewNum() {
+        return renewNum;
+    }
+
+    public void setRenewNum(Integer renewNum) {
+        this.renewNum = renewNum;
+    }
+
+    public Integer getVisitNum() {
+        return visitNum;
+    }
+
+    public void setVisitNum(Integer visitNum) {
+        this.visitNum = visitNum;
+    }
+}

+ 1 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ManagerDownload.java

@@ -40,7 +40,7 @@ public class ManagerDownload extends BaseEntity {
     /**
      * 状态
      */
-    @ApiModelProperty(value = "状态")
+    @ApiModelProperty(value = "状态0下载中、1成功、2失败")
     private Integer status=0;
 
     /**

+ 184 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentBasicInfo.java

@@ -0,0 +1,184 @@
+package com.ym.mec.biz.dal.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+import java.math.BigDecimal;
+
+/**
+ * 对应数据库表(student_basic_info):
+ */
+public class StudentBasicInfo {
+
+	/** 学员编号 */
+	@ApiModelProperty(value = "学员编号",required = false)
+	private Integer userId;
+	
+	/** 学员姓名 */
+	@ApiModelProperty(value = "学员姓名",required = false)
+	private String userName;
+	
+	/** 手机号 */
+	@ApiModelProperty(value = "手机号",required = false)
+	private String phone;
+	
+	/** 声部编号 */
+	@ApiModelProperty(value = "声部编号",required = false)
+	private Integer subjectId;
+	
+	/** 声部 */
+	@ApiModelProperty(value = "声部",required = false)
+	private String subjectName;
+	
+	/** 年级 */
+	@ApiModelProperty(value = "年级",required = false)
+	private String grade;
+	
+	/** 分部编号 */
+	@ApiModelProperty(value = "分部编号",required = false)
+	private Integer organId;
+	
+	/** 分部名称 */
+	@ApiModelProperty(value = "分部名称",required = false)
+	private String organName;
+	
+	/** 学校编号 */
+	@ApiModelProperty(value = "学校编号",required = false)
+	private Integer cooperationOrganId;
+	
+	/** 学校名称 */
+	@ApiModelProperty(value = "学校名称",required = false)
+	private String cooperationOrganName;
+	
+	/** 声部课老师(学员所在乐团声部班老师,如果有多个,取id最大的) */
+	@ApiModelProperty(value = "声部课老师",required = false)
+	private Integer subjectTeacherId;
+	
+	/** 声部课老师(学员所在乐团声部班老师) */
+	@ApiModelProperty(value = "声部课老师",required = false)
+	private String subjectTeacherName;
+
+	@ApiModelProperty(value = "课程余额",required = false)
+	private BigDecimal courseBalance = BigDecimal.ZERO;
+
+	@ApiModelProperty(value = "学员状态",required = false)
+	private String studentStatus;
+
+	public String getStudentStatus() {
+		return studentStatus;
+	}
+
+	public void setStudentStatus(String studentStatus) {
+		this.studentStatus = studentStatus;
+	}
+
+	public BigDecimal getCourseBalance() {
+		return courseBalance;
+	}
+
+	public void setCourseBalance(BigDecimal courseBalance) {
+		this.courseBalance = courseBalance;
+	}
+
+	public void setUserId(Integer userId){
+		this.userId = userId;
+	}
+	
+	public Integer getUserId(){
+		return this.userId;
+	}
+			
+	public void setUserName(String userName){
+		this.userName = userName;
+	}
+	
+	public String getUserName(){
+		return this.userName;
+	}
+			
+	public void setPhone(String phone){
+		this.phone = phone;
+	}
+	
+	public String getPhone(){
+		return this.phone;
+	}
+			
+	public void setSubjectId(Integer subjectId){
+		this.subjectId = subjectId;
+	}
+	
+	public Integer getSubjectId(){
+		return this.subjectId;
+	}
+			
+	public void setSubjectName(String subjectName){
+		this.subjectName = subjectName;
+	}
+	
+	public String getSubjectName(){
+		return this.subjectName;
+	}
+			
+	public void setGrade(String grade){
+		this.grade = grade;
+	}
+	
+	public String getGrade(){
+		return this.grade;
+	}
+			
+	public void setOrganId(Integer organId){
+		this.organId = organId;
+	}
+	
+	public Integer getOrganId(){
+		return this.organId;
+	}
+			
+	public void setOrganName(String organName){
+		this.organName = organName;
+	}
+	
+	public String getOrganName(){
+		return this.organName;
+	}
+			
+	public void setCooperationOrganId(Integer cooperationOrganId){
+		this.cooperationOrganId = cooperationOrganId;
+	}
+	
+	public Integer getCooperationOrganId(){
+		return this.cooperationOrganId;
+	}
+			
+	public void setCooperationOrganName(String cooperationOrganName){
+		this.cooperationOrganName = cooperationOrganName;
+	}
+	
+	public String getCooperationOrganName(){
+		return this.cooperationOrganName;
+	}
+			
+	public void setSubjectTeacherId(Integer subjectTeacherId){
+		this.subjectTeacherId = subjectTeacherId;
+	}
+	
+	public Integer getSubjectTeacherId(){
+		return this.subjectTeacherId;
+	}
+			
+	public void setSubjectTeacherName(String subjectTeacherName){
+		this.subjectTeacherName = subjectTeacherName;
+	}
+	
+	public String getSubjectTeacherName(){
+		return this.subjectTeacherName;
+	}
+			
+	@Override
+	public String toString() {
+		return ToStringBuilder.reflectionToString(this);
+	}
+
+}

+ 311 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentStatistics.java

@@ -0,0 +1,311 @@
+package com.ym.mec.biz.dal.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+import java.math.BigDecimal;
+
+/**
+ * 对应数据库表(student_statistics):
+ */
+public class StudentStatistics {
+
+	@ApiModelProperty(value = "主键",required = false)
+	private Integer id;
+	
+	@ApiModelProperty(value = "学员编号",required = false)
+	private Integer userId;
+	
+	@ApiModelProperty(value = "指导老师编号(最近一节已结束课程上的老师)",required = false)
+	private Integer teacherId;
+	
+	@ApiModelProperty(value = "指导老师",required = false)
+	private String teacherName;
+	
+	/** 乐团主管(最近一节已结束课程的课程组老师) */
+	@ApiModelProperty(value = "乐团主管",required = false)
+	private Integer musicDirectorId;
+
+	@ApiModelProperty(value = "乐团主管",required = false)
+	/** 乐团主管(最近一节已结束课程的课程组老师) */
+	private String musicDirectorName;
+
+	@ApiModelProperty(value = "总课时",required = false)
+	/** 总课时(课时总数) */
+	private Integer totalCourseNum;
+
+	@ApiModelProperty(value = "已完成课时",required = false)
+	/** 已完成课时(已结束课时数) */
+	private Integer overCourseNum;
+
+	@ApiModelProperty(value = "剩余课时",required = false)
+	/** 剩余课时(未开始课时数) */
+	private Integer subCourseNum;
+
+	@ApiModelProperty(value = "未排课时",required = false)
+	/** 未排课时(未排课时总数) */
+	private Integer noScheduleNum;
+
+	@ApiModelProperty(value = "第一次课时间",required = false)
+	/** 第一次课时间 */
+	private String firstCourseTime;
+
+	@ApiModelProperty(value = "最近一次上课时间",required = false)
+	/** 最近一次上课时间 */
+	private String lastCourseTime;
+
+	@ApiModelProperty(value = "最近30天课耗",required = false)
+	/** 最近30天课耗(已结束的课程数量) */
+	private Integer latelyCourseConsumer;
+
+	@ApiModelProperty(value = "最近1年课耗",required = false)
+	/** 最近1年课耗(已结束的课程数量) */
+	private Integer latelyYearCourseConsumer;
+
+	@ApiModelProperty(value = "回访次数",required = false)
+	/** 回访次数 */
+	private Integer visitNum;
+
+	@ApiModelProperty(value = "最近一次回访状态",required = false)
+	/** 最近一次回访状态 */
+	private String lastVisitStatus;
+
+	@ApiModelProperty(value = "最近一次回访原因",required = false)
+	/** 最近一次回访原因 */
+	private String visitReason;
+
+	@ApiModelProperty(value = "最近一次回访时间",required = false)
+	/** 最近一次回访时间 */
+	private String lastVisitTime;
+
+	@ApiModelProperty(value = "预收款(未开始课程价值总和)",required = false)
+	/** 预收款(未开始课程价值总和) */
+	private java.math.BigDecimal notStartCourseFee;
+
+	@ApiModelProperty(value = "预收款(未排课 价值总和)",required = false)
+	/** 预收款(未排课 价值总和) */
+	private java.math.BigDecimal noCourseFee;
+
+	@ApiModelProperty(value = "预收款(总金额)",required = false)
+	/** 预收款(总金额) */
+	private java.math.BigDecimal preCourseFee;
+
+	@ApiModelProperty(value = "首次付费订单时间",required = false)
+	/** 首次付费订单时间 */
+	private String firstOrderTime;
+
+	@ApiModelProperty(value = "最近一次付费订单时间",required = false)
+	private String lastOrderTime;
+
+	@ApiModelProperty(value = "付费订单总数",required = false)
+	private Integer orderNum;
+
+	@ApiModelProperty(value = "课程组类型(VIP,THEORY,PRACTICE)",required = false)
+	private String groupType;
+
+	public BigDecimal getPreCourseFee() {
+		return preCourseFee;
+	}
+
+	public void setPreCourseFee(BigDecimal preCourseFee) {
+		this.preCourseFee = preCourseFee;
+	}
+
+	public Integer getLatelyYearCourseConsumer() {
+		return latelyYearCourseConsumer;
+	}
+
+	public void setLatelyYearCourseConsumer(Integer latelyYearCourseConsumer) {
+		this.latelyYearCourseConsumer = latelyYearCourseConsumer;
+	}
+
+	public void setId(Integer id){
+		this.id = id;
+	}
+	
+	public Integer getId(){
+		return this.id;
+	}
+			
+	public void setUserId(Integer userId){
+		this.userId = userId;
+	}
+	
+	public Integer getUserId(){
+		return this.userId;
+	}
+			
+	public void setTeacherId(Integer teacherId){
+		this.teacherId = teacherId;
+	}
+	
+	public Integer getTeacherId(){
+		return this.teacherId;
+	}
+			
+	public void setTeacherName(String teacherName){
+		this.teacherName = teacherName;
+	}
+	
+	public String getTeacherName(){
+		return this.teacherName;
+	}
+			
+	public void setMusicDirectorId(Integer musicDirectorId){
+		this.musicDirectorId = musicDirectorId;
+	}
+	
+	public Integer getMusicDirectorId(){
+		return this.musicDirectorId;
+	}
+			
+	public void setMusicDirectorName(String musicDirectorName){
+		this.musicDirectorName = musicDirectorName;
+	}
+	
+	public String getMusicDirectorName(){
+		return this.musicDirectorName;
+	}
+			
+	public void setTotalCourseNum(Integer totalCourseNum){
+		this.totalCourseNum = totalCourseNum;
+	}
+	
+	public Integer getTotalCourseNum(){
+		return this.totalCourseNum;
+	}
+			
+	public void setOverCourseNum(Integer overCourseNum){
+		this.overCourseNum = overCourseNum;
+	}
+	
+	public Integer getOverCourseNum(){
+		return this.overCourseNum;
+	}
+			
+	public void setSubCourseNum(Integer subCourseNum){
+		this.subCourseNum = subCourseNum;
+	}
+	
+	public Integer getSubCourseNum(){
+		return this.subCourseNum;
+	}
+			
+	public void setNoScheduleNum(Integer noScheduleNum){
+		this.noScheduleNum = noScheduleNum;
+	}
+	
+	public Integer getNoScheduleNum(){
+		return this.noScheduleNum;
+	}
+			
+	public void setFirstCourseTime(String firstCourseTime){
+		this.firstCourseTime = firstCourseTime;
+	}
+	
+	public String getFirstCourseTime(){
+		return this.firstCourseTime;
+	}
+			
+	public void setLastCourseTime(String lastCourseTime){
+		this.lastCourseTime = lastCourseTime;
+	}
+	
+	public String getLastCourseTime(){
+		return this.lastCourseTime;
+	}
+			
+	public void setLatelyCourseConsumer(Integer latelyCourseConsumer){
+		this.latelyCourseConsumer = latelyCourseConsumer;
+	}
+	
+	public Integer getLatelyCourseConsumer(){
+		return this.latelyCourseConsumer;
+	}
+			
+	public void setVisitNum(Integer visitNum){
+		this.visitNum = visitNum;
+	}
+	
+	public Integer getVisitNum(){
+		return this.visitNum;
+	}
+			
+	public void setLastVisitStatus(String lastVisitStatus){
+		this.lastVisitStatus = lastVisitStatus;
+	}
+	
+	public String getLastVisitStatus(){
+		return this.lastVisitStatus;
+	}
+			
+	public void setVisitReason(String visitReason){
+		this.visitReason = visitReason;
+	}
+	
+	public String getVisitReason(){
+		return this.visitReason;
+	}
+			
+	public void setLastVisitTime(String lastVisitTime){
+		this.lastVisitTime = lastVisitTime;
+	}
+	
+	public String getLastVisitTime(){
+		return this.lastVisitTime;
+	}
+
+	public BigDecimal getNotStartCourseFee() {
+		return notStartCourseFee;
+	}
+
+	public void setNotStartCourseFee(BigDecimal notStartCourseFee) {
+		this.notStartCourseFee = notStartCourseFee;
+	}
+
+	public BigDecimal getNoCourseFee() {
+		return noCourseFee;
+	}
+
+	public void setNoCourseFee(BigDecimal noCourseFee) {
+		this.noCourseFee = noCourseFee;
+	}
+
+	public void setFirstOrderTime(String firstOrderTime){
+		this.firstOrderTime = firstOrderTime;
+	}
+	
+	public String getFirstOrderTime(){
+		return this.firstOrderTime;
+	}
+			
+	public void setLastOrderTime(String lastOrderTime){
+		this.lastOrderTime = lastOrderTime;
+	}
+	
+	public String getLastOrderTime(){
+		return this.lastOrderTime;
+	}
+			
+	public void setOrderNum(Integer orderNum){
+		this.orderNum = orderNum;
+	}
+	
+	public Integer getOrderNum(){
+		return this.orderNum;
+	}
+			
+	public void setGroupType(String groupType){
+		this.groupType = groupType;
+	}
+	
+	public String getGroupType(){
+		return this.groupType;
+	}
+			
+	@Override
+	public String toString() {
+		return ToStringBuilder.reflectionToString(this);
+	}
+
+}

+ 46 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentVisit.java

@@ -43,6 +43,38 @@ public class StudentVisit extends BaseEntity {
         }
     }
 
+    public enum FeedbackTypeEnum implements BaseEnum<String,FeedbackTypeEnum> {
+        THINKING("THINKING", "考虑中"), PENDING_PAYMENT("PENDING_PAYMENT", "确认缴费待缴费"),
+        LOST("LOST", "流失"), PAUSE("PAUSE", "暂停"),
+        OTHER("OTHER", "其他");
+
+        private String code;
+
+        private String msg;
+
+        FeedbackTypeEnum(String code, String msg) {
+            this.code = code;
+            this.msg = msg;
+        }
+
+        public void setCode(String code) {
+            this.code = code;
+        }
+
+        public String getMsg() {
+            return msg;
+        }
+
+        public void setMsg(String msg) {
+            this.msg = msg;
+        }
+
+        @Override
+        public String getCode() {
+            return this.code;
+        }
+    }
+
     private Integer id;
 
     /**
@@ -97,6 +129,12 @@ public class StudentVisit extends BaseEntity {
     private String overview;
 
     /**
+     * 家长反馈类型
+     */
+    @ApiModelProperty(value = "家长反馈", required = true)
+    private FeedbackTypeEnum feedbackType;
+
+    /**
      * 家长反馈
      */
     @ApiModelProperty(value = "家长反馈", required = true)
@@ -116,6 +154,14 @@ public class StudentVisit extends BaseEntity {
 
     private Long objectId;
 
+    public FeedbackTypeEnum getFeedbackType() {
+        return feedbackType;
+    }
+
+    public void setFeedbackType(FeedbackTypeEnum feedbackType) {
+        this.feedbackType = feedbackType;
+    }
+
     public Integer getId() {
         return id;
     }

+ 1 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ExportTypeEnum.java

@@ -10,6 +10,7 @@ public enum ExportTypeEnum implements BaseEnum<Integer, ExportTypeEnum> {
 	STUDENT_MUSIC_THEORY_COURSE_INFO(4, "网管课学员课程信息导出"),
 	STUDENT_VIP_COURSE_INFO(5, "VIP课学员课程信息导出"),
 	VIP_STUDENT_COURSE_MANAGE(6, "vip学员课程管理"),
+	STUDENT_SMALL_CLASS_STATISTICS(7, "学员小课数据统计"),
 	ORDER_LIST_SUM(8, "订单汇总");
 
 	private Integer code;

+ 9 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/FivePlusGradeEnum.java

@@ -33,5 +33,14 @@ public enum FivePlusGradeEnum implements BaseEnum<Integer, FivePlusGradeEnum> {
 	public String getDesc() {
 		return desc;
 	}
+	
+	public static FivePlusGradeEnum get(String desc) {
+		for (FivePlusGradeEnum vpg : FivePlusGradeEnum.values()) {
+			if (vpg.getDesc().equals(desc)) {
+				return vpg;
+			}
+		}
+		return null;
+	}
 
 }

+ 5 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/IndexDataType.java

@@ -1,6 +1,5 @@
 package com.ym.mec.biz.dal.enums;
 
-import com.sun.org.apache.xpath.internal.operations.Bool;
 import com.ym.mec.common.enums.BaseEnum;
 
 /**
@@ -83,6 +82,11 @@ public enum IndexDataType implements BaseEnum<String, IndexDataType> {
 
     CLOUD_STUDY_TRAIN_NUM("CLOUD_STUDY_TRAIN_NUM", "团练宝训练次数", false, false),
     CLOUD_STUDY_TRAIN_TIME("CLOUD_STUDY_TRAIN_TIME", "团练宝训练时长", false, false),
+
+    //小课数据统计
+    STUDENT_VIP_ORDER_NUM("STUDENT_VIP_ORDER_NUM", "学员vip课订单数量", false, false),
+    STUDENT_THEORY_ORDER_NUM("STUDENT_THEORY_ORDER_NUM", "学员乐理课订单数量", false, false),
+    STUDENT_PRACTICE_ORDER_NUM("STUDENT_PRACTICE_ORDER_NUM", "学员网管课订单数量", false, false),
     ;
 
     private String code;

+ 2 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/OrderTypeEnum.java

@@ -15,6 +15,7 @@ public enum OrderTypeEnum implements BaseEnum<String, OrderTypeEnum> {
     PRACTICE_GROUP_BUY("PRACTICE_GROUP_BUY", "网管课报名"),
     PRACTICE_GROUP_RENEW("PRACTICE_GROUP_RENEW", "网管课续费"),
     COURSE_GROUP_BUY("COURSE_GROUP_BUY", "课程购买"),
+    //余额充值活动
     LUCK("LUCK", "福袋活动"),
     DOUBLE_ELEVEN2020("DOUBLE_ELEVEN2020", "2020双十一活动"),
     DOUBLE_ELEVEN2021("DOUBLE_ELEVEN2021", "2021双十一活动"),
@@ -23,6 +24,7 @@ public enum OrderTypeEnum implements BaseEnum<String, OrderTypeEnum> {
     OUTORDER("OUTORDER", "导入订单"),
     REPAIR("REPAIR", "乐器维修"),
     SUBJECT_CHANGE("SUBJECT_CHANGE", "声部更换"),
+    //包含考级费用和乐理课费用,乐理课的费用在detail里面,对于的订单类型是 DEGREE_REGISTRATION
     DEGREE_REGISTRATION("DEGREE_REGISTRATION", "考级报名"),
     MAINTENANCE("MAINTENANCE", "乐器保养"),
     REPLACEMENT("REPLACEMENT", "乐器置换"),

+ 9 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/SixPlusGradeEnum.java

@@ -33,5 +33,14 @@ public enum SixPlusGradeEnum implements BaseEnum<Integer, SixPlusGradeEnum> {
 	public String getDesc() {
 		return desc;
 	}
+	
+	public static SixPlusGradeEnum get(String desc) {
+		for (SixPlusGradeEnum vpg : SixPlusGradeEnum.values()) {
+			if (vpg.getDesc().equals(desc)) {
+				return vpg;
+			}
+		}
+		return null;
+	}
 
 }

+ 1 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/TemplateTypeEnum.java

@@ -8,7 +8,7 @@ public enum TemplateTypeEnum implements BaseEnum<String, TemplateTypeEnum> {
     FINANCIAL_EXPENDITURE("FINANCIAL_EXPENDITURE","财务支出导入模板"),
     REDEMPTIONCODE("REDEMPTION_CODE", "兑换码分配模板表"),
     OA_QUIT_MUSIC_GROUP("OA_QUIT_MUSIC_GROUP", "乐团退费模板"),
-    EXTERNAL_STUDENT_IMPORT_MUSIC_GROUP("EXTERNAL_STUDENT_IMPORT_MUSIC_GROUP", "外部学生导入乐团模板");
+    EXTERNAL_STUDENT_IMPORT_MUSIC_GROUP("EXTERNAL_STUDENT_IMPORT_MUSIC_GROUP", "外部学生入团导入模板");
 
     private String code;
 

+ 165 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/page/StudentStatisticsQueryInfo.java

@@ -0,0 +1,165 @@
+package com.ym.mec.biz.dal.page;
+
+import com.ym.mec.common.page.QueryInfo;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* @author zx
+* @date 2021/9/26 15:52
+*/
+public class StudentStatisticsQueryInfo extends QueryInfo {
+
+    @ApiModelProperty(value = "小课类型 VIP、PRACTICE、THEORY 默认VIP",required = true)
+    private String groupType = "VIP";
+
+    @ApiModelProperty(value = "声部编号",required = false)
+    private Integer subjectId;
+
+    @ApiModelProperty(value = "学员状态,在读(NORMAL)、沉睡(SLEEPY)、流失(LOST), PAUSE(暂停)",required = false)
+    private String studentStatus;
+
+    @ApiModelProperty(value = "回访状态,THINKING(考虑中), PENDING_PAYMENT(确认缴费待缴费),LOST(流失), PAUSE(暂停),OTHER(其他)",required = false)
+    private String feedbackType;
+
+    @ApiModelProperty(value = "30天课耗",required = false)
+    private Integer latelyCourseConsumer;
+
+    @ApiModelProperty(value = "一年课耗",required = false)
+    private Integer latelyYearCourseConsumer;
+
+    @ApiModelProperty(value = "回访次数",required = false)
+    private Integer visitNum;
+
+    @ApiModelProperty(value = "指导老师",required = false)
+    private Integer teacherId;
+
+    @ApiModelProperty(value = "声部课老师",required = false)
+    private Integer subjectTeacherId;
+
+    @ApiModelProperty(value = "乐团主管",required = false)
+    private Integer musicDirectorId;
+
+    @ApiModelProperty(value = "是否查询课耗异常",required = false)
+    private Boolean courseConsumerError;
+
+    @ApiModelProperty(value = "第一次课开始时间(年月日)",required = false)
+    private String firstCourseStartTime;
+
+    @ApiModelProperty(value = "第一次课截止时间(年月日)",required = false)
+    private String firstCourseEndTime;
+
+    @ApiModelProperty(value = "分部编号列表",required = false)
+    private String organId;
+
+    public String getOrganId() {
+        return organId;
+    }
+
+    public void setOrganId(String organId) {
+        this.organId = organId;
+    }
+
+    public String getGroupType() {
+        return groupType;
+    }
+
+    public void setGroupType(String groupType) {
+        this.groupType = groupType;
+    }
+
+    public Integer getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Integer subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getStudentStatus() {
+        return studentStatus;
+    }
+
+    public void setStudentStatus(String studentStatus) {
+        this.studentStatus = studentStatus;
+    }
+
+    public String getFeedbackType() {
+        return feedbackType;
+    }
+
+    public void setFeedbackType(String feedbackType) {
+        this.feedbackType = feedbackType;
+    }
+
+    public Integer getLatelyCourseConsumer() {
+        return latelyCourseConsumer;
+    }
+
+    public void setLatelyCourseConsumer(Integer latelyCourseConsumer) {
+        this.latelyCourseConsumer = latelyCourseConsumer;
+    }
+
+    public Integer getLatelyYearCourseConsumer() {
+        return latelyYearCourseConsumer;
+    }
+
+    public void setLatelyYearCourseConsumer(Integer latelyYearCourseConsumer) {
+        this.latelyYearCourseConsumer = latelyYearCourseConsumer;
+    }
+
+    public Integer getVisitNum() {
+        return visitNum;
+    }
+
+    public void setVisitNum(Integer visitNum) {
+        this.visitNum = visitNum;
+    }
+
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    public Integer getSubjectTeacherId() {
+        return subjectTeacherId;
+    }
+
+    public void setSubjectTeacherId(Integer subjectTeacherId) {
+        this.subjectTeacherId = subjectTeacherId;
+    }
+
+    public Integer getMusicDirectorId() {
+        return musicDirectorId;
+    }
+
+    public void setMusicDirectorId(Integer musicDirectorId) {
+        this.musicDirectorId = musicDirectorId;
+    }
+
+    public Boolean getCourseConsumerError() {
+        return courseConsumerError;
+    }
+
+    public void setCourseConsumerError(Boolean courseConsumerError) {
+        this.courseConsumerError = courseConsumerError;
+    }
+
+    public String getFirstCourseStartTime() {
+        return firstCourseStartTime;
+    }
+
+    public void setFirstCourseStartTime(String firstCourseStartTime) {
+        this.firstCourseStartTime = firstCourseStartTime;
+    }
+
+    public String getFirstCourseEndTime() {
+        return firstCourseEndTime;
+    }
+
+    public void setFirstCourseEndTime(String firstCourseEndTime) {
+        this.firstCourseEndTime = firstCourseEndTime;
+    }
+}

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/page/StudentVisitQueryInfo.java

@@ -36,6 +36,17 @@ public class StudentVisitQueryInfo extends QueryInfo {
     @ApiModelProperty(value = "回访日期结束时间", required = false)
     private Date endTime;
 
+    @ApiModelProperty(value = "家长回访类型(\"THINKING\", \"考虑中\"),(\"PENDING_PAYMENT\", \"确认缴费待缴费\"),(\"LOST\", \"流失\"),(\"PAUSE\", \"暂停\"),(\"OTHER\", \"其他\")", required = false)
+    private String feedbackType;
+
+    public String getFeedbackType() {
+        return feedbackType;
+    }
+
+    public void setFeedbackType(String feedbackType) {
+        this.feedbackType = feedbackType;
+    }
+
     public String getTeacher() {
         return teacher;
     }

+ 1 - 4
mec-biz/src/main/java/com/ym/mec/biz/event/listener/CourseEventListener.java

@@ -34,10 +34,6 @@ public class CourseEventListener {
     private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
     @Autowired
     private RedisCache<String, Object> redisCache;
-    @Autowired
-    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
-    @Autowired
-    private StudentServeService studentServeService;
 
     @Async
     @EventListener
@@ -55,6 +51,7 @@ public class CourseEventListener {
 //
 //        logger.info("课程状态变更(执行开始):{}", courseStatusChangeEvent.getCourseIds());
 
+
         try{
             courseScheduleStudentPaymentService.updateCourseActualPrice(null, null, null);
         } finally {

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ExportService.java

@@ -5,6 +5,7 @@ import com.ym.mec.biz.dal.entity.ManagerDownload;
 import com.ym.mec.biz.dal.enums.ExportEnum;
 import com.ym.mec.biz.dal.enums.ExportTypeEnum;
 import com.ym.mec.biz.dal.page.EndCourseScheduleQueryInfo;
+import com.ym.mec.biz.dal.page.StudentStatisticsQueryInfo;
 import com.ym.mec.common.entity.HttpResponseResult;
 import org.springframework.scheduling.annotation.Async;
 
@@ -286,4 +287,6 @@ public interface ExportService {
     void queryStudentCourseInfo(String organId, Integer tenantId, String vip, ManagerDownload managerDownload, List<String> headColumns,ExportEnum exportEnum) throws FileNotFoundException;
 
     void queryVipStudentCourseManage(String organId, Integer tenantId, ManagerDownload managerDownload, List<String> headColumns, ExportEnum exportEnum) throws FileNotFoundException;
+
+    void exportStudentSmallClassStatisticsSum(StudentStatisticsQueryInfo queryInfo, ManagerDownload managerDownload) throws FileNotFoundException;
 }

+ 34 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/StudentStatisticsService.java

@@ -0,0 +1,34 @@
+package com.ym.mec.biz.service;
+
+import com.ym.mec.biz.dal.dto.StudentStatisticsDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumForDateDto;
+import com.ym.mec.biz.dal.entity.StudentStatistics;
+import com.ym.mec.biz.dal.page.StudentStatisticsQueryInfo;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.page.QueryInfo;
+import com.ym.mec.common.service.BaseService;
+
+import java.util.List;
+import java.util.Map;
+
+public interface StudentStatisticsService extends BaseService<Integer, StudentStatistics> {
+
+    //定时任务
+    void updateStudentStatistics();
+
+    //分页查询学员小课数据
+    PageInfo<StudentStatisticsDto> queryStatisticsPage(StudentStatisticsQueryInfo queryInfo);
+
+    //获取小课数据统计汇总
+    StudentStatisticsSumDto studentSmallClassStatisticsSum(String groupType,String organId);
+
+    //按时间获取统计数据
+    StudentStatisticsSumForDateDto studentSmallClassStatisticsSumForDate(String groupType, String startDate, String endDate,String organId);
+
+    //获取指导老师列表
+    List<Map<Integer, String>> queryTeacherList(String groupType);
+
+    //获取乐团主管列表
+    List<Map<Integer, String>> queryDirectorList(String groupType);
+}

+ 45 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ExportServiceImpl.java

@@ -173,6 +173,8 @@ public class ExportServiceImpl implements ExportService {
     @Autowired
     private SysUserCashAccountLogService sysUserCashAccountLogService;
     @Autowired
+    private StudentStatisticsService studentStatisticsService;
+    @Autowired
     private SysTenantConfigService sysTenantConfigService;
 
     @Value("${spring.profiles.active:dev}")
@@ -2991,4 +2993,47 @@ public class ExportServiceImpl implements ExportService {
             }
         }
     }
+
+    @Override
+    public void exportStudentSmallClassStatisticsSum(StudentStatisticsQueryInfo queryInfo, ManagerDownload managerDownload) throws FileNotFoundException {
+        List<StudentStatisticsDto> rows = studentStatisticsService.queryStatisticsPage(queryInfo).getRows();
+        String basePath = new ApplicationHome(this.getClass()).getSource().getParentFile().getPath();
+        File file = new File(basePath + "/" + managerDownload.getName());
+        FileOutputStream fileOutputStream = new FileOutputStream(file);
+        OutputStream ouputStream = null;
+        try {
+            HSSFWorkbook workbook = POIUtil.exportExcel(new String[]{"分部", "学生姓名", "学员编号","联系电话", "声部", "学校", "年级", "学员状态", "未排课时", "总课时", "已完成课时",
+                    "剩余课时","预收金额","第一次课时间","最近上课时间","指导老师编号","指导老师","乐团主管编号","乐团主管","声部课老师编号","声部课老师","近30天课耗","回访次数",
+                    "回访状态","原因","回访日期"},
+            new String[]{"studentBasicInfo.organName", "studentBasicInfo.userName", "studentBasicInfo.userId",
+                    "studentBasicInfo.phone","studentBasicInfo.subjectName", "studentBasicInfo.cooperationOrganName", "studentBasicInfo.grade",
+                    "studentBasicInfo.studentStatus",
+                    "noScheduleNum","totalCourseNum", "overCourseNum", "subCourseNum","preCourseFee","firstCourseTime","lastCourseTime","teacherId","teacherName","musicDirectorId","musicDirectorName",
+                    "studentBasicInfo.subjectTeacherId","studentBasicInfo.subjectTeacherName","latelyCourseConsumer","visitNum",
+                    "lastVisitStatus == null?'':lastVisitStatus == 'LOST' ? '流失':lastVisitStatus == 'THINKING' ? '考虑中':" +
+                    "lastVisitStatus == 'PENDING_PAYMENT' ? '确认缴费待缴费':lastVisitStatus == 'PAUSE' ? '暂停':lastVisitStatus == 'OTHER' ? '其他':''"
+                    ,"visitReason","lastVisitTime"}, rows);
+
+            workbook.write(fileOutputStream);
+            fileOutputStream.getFD().sync();
+            fileOutputStream.close();
+
+            String folder = "download/" + UploadUtil.getFileFloder();
+            String url = storagePluginContext.uploadFile(KS3StoragePlugin.PLUGIN_NAME, folder, file);
+            //把记录插入下载表
+            managerDownload.setFileUrl(url);
+            managerDownload.setStatus(1);
+            managerDownloadDao.update(managerDownload);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (ouputStream != null) {
+                try {
+                    ouputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
 }

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/IndexBaseMonthDataServiceImpl.java

@@ -458,6 +458,17 @@ public class IndexBaseMonthDataServiceImpl extends BaseServiceImpl<Long, IndexBa
 			saveData(indexBaseMonthDataDao.getGroupCourseDataWithGroup(dayStr, null, null, GroupType.MUSIC, null, null, null,tenantId), dayStr, IndexDataType.MUSIC_GROUP_COURSE, tenantId);
 		}
 
+		//小课数据统计
+		if(CollectionUtils.isEmpty(dataTypes)||dataTypes.contains(STUDENT_VIP_ORDER_NUM)) {
+			saveData(indexBaseMonthDataDao.getStudentVipOrderNum(dayStr,tenantId), dayStr, IndexDataType.STUDENT_VIP_ORDER_NUM, tenantId);
+		}
+		if(CollectionUtils.isEmpty(dataTypes)||dataTypes.contains(STUDENT_THEORY_ORDER_NUM)) {
+			saveData(indexBaseMonthDataDao.getStudentTheoryOrderNum(dayStr,tenantId), dayStr, IndexDataType.STUDENT_THEORY_ORDER_NUM, tenantId);
+		}
+		if(CollectionUtils.isEmpty(dataTypes)||dataTypes.contains(STUDENT_PRACTICE_ORDER_NUM)) {
+			saveData(indexBaseMonthDataDao.getStudentPracticeOrderNum(dayStr,tenantId), dayStr, IndexDataType.STUDENT_PRACTICE_ORDER_NUM, tenantId);
+		}
+
 		if(CollectionUtils.isEmpty(dataTypes)||dataTypes.contains(IndexDataType.VIP_GROUP_COURSE)) {
 			List<IndexBaseMonthData> vipCourseData = indexBaseMonthDataDao.getGroupCourseDataWithGroup(dayStr, null, null, GroupType.VIP, null, null, null,tenantId);
 			List<OrganVipGroupCategoryCourseNumDto> vipGroupCategoryCourseData = indexBaseMonthDataDao.getVipGroupCategoryCourseData(dayStr, null, null, GroupType.VIP, null, null, null,tenantId);

+ 419 - 31
mec-biz/src/main/java/com/ym/mec/biz/service/impl/MusicGroupServiceImpl.java

@@ -1,22 +1,196 @@
 package com.ym.mec.biz.service.impl;
 
+import static com.ym.mec.biz.dal.entity.ApprovalStatus.PROCESSING;
+import static com.ym.mec.biz.dal.entity.MusicGroupStudentFee.PaymentStatus.PAID_COMPLETED;
+import static com.ym.mec.biz.dal.enums.DealStatusEnum.ING;
+import static com.ym.mec.biz.dal.enums.DealStatusEnum.SUCCESS;
+import static com.ym.mec.biz.dal.enums.OrderDetailTypeEnum.ACCESSORIES;
+import static com.ym.mec.biz.dal.enums.OrderDetailTypeEnum.MAINTENANCE;
+import static com.ym.mec.biz.dal.enums.OrderDetailTypeEnum.MUSICAL;
+import static com.ym.mec.biz.dal.enums.OrderDetailTypeEnum.TEACHING;
+import static com.ym.mec.biz.dal.enums.PaymentStatusEnum.YES;
+import static com.ym.mec.biz.dal.enums.SysUserRoleEnum.ORGAN_MANAGER;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
-import com.ym.mec.biz.dal.dao.*;
-import com.ym.mec.biz.dal.dto.*;
-import com.ym.mec.biz.dal.entity.*;
+import com.ym.mec.biz.dal.dao.ChargeTypeDao;
+import com.ym.mec.biz.dal.dao.ClassGroupDao;
+import com.ym.mec.biz.dal.dao.ClassGroupStudentMapperDao;
+import com.ym.mec.biz.dal.dao.ClassGroupTeacherMapperDao;
+import com.ym.mec.biz.dal.dao.CooperationOrganDao;
+import com.ym.mec.biz.dal.dao.CourseScheduleDao;
+import com.ym.mec.biz.dal.dao.CourseScheduleTeacherSalaryDao;
+import com.ym.mec.biz.dal.dao.GoodsDao;
+import com.ym.mec.biz.dal.dao.MusicGroupBuildLogDao;
+import com.ym.mec.biz.dal.dao.MusicGroupDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderCourseSettingsDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderDetailDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderStudentDetailDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentEntitiesDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPaymentStudentCourseDetailDao;
+import com.ym.mec.biz.dal.dao.MusicGroupPurchaseListDao;
+import com.ym.mec.biz.dal.dao.MusicGroupQuitDao;
+import com.ym.mec.biz.dal.dao.MusicGroupSchoolTermCourseDetailDao;
+import com.ym.mec.biz.dal.dao.MusicGroupSchoolTermStudentCourseDetailDao;
+import com.ym.mec.biz.dal.dao.MusicGroupStudentFeeDao;
+import com.ym.mec.biz.dal.dao.MusicGroupSubjectGoodsGroupDao;
+import com.ym.mec.biz.dal.dao.MusicGroupSubjectPlanDao;
+import com.ym.mec.biz.dal.dao.OrganizationDao;
+import com.ym.mec.biz.dal.dao.SchoolDao;
+import com.ym.mec.biz.dal.dao.SporadicChargeInfoDao;
+import com.ym.mec.biz.dal.dao.StudentDao;
+import com.ym.mec.biz.dal.dao.StudentInstrumentDao;
+import com.ym.mec.biz.dal.dao.StudentPaymentOrderDao;
+import com.ym.mec.biz.dal.dao.StudentPaymentOrderDetailDao;
+import com.ym.mec.biz.dal.dao.StudentPreRegistrationDao;
+import com.ym.mec.biz.dal.dao.StudentRegistrationDao;
+import com.ym.mec.biz.dal.dao.StudentVisitDao;
+import com.ym.mec.biz.dal.dao.SubjectChangeDao;
+import com.ym.mec.biz.dal.dao.SubjectDao;
+import com.ym.mec.biz.dal.dao.SysConfigDao;
+import com.ym.mec.biz.dal.dao.SysUserCashAccountDao;
+import com.ym.mec.biz.dal.dao.SysUserCashAccountLogDao;
+import com.ym.mec.biz.dal.dao.TeacherAttendanceDao;
+import com.ym.mec.biz.dal.dao.TeacherDao;
+import com.ym.mec.biz.dal.dto.BasicUserDto;
+import com.ym.mec.biz.dal.dto.CloseMusicGroupDto;
+import com.ym.mec.biz.dal.dto.CourseScheduleTeachersDto;
+import com.ym.mec.biz.dal.dto.HighClassGroupDto;
+import com.ym.mec.biz.dal.dto.MusicCardDto;
+import com.ym.mec.biz.dal.dto.MusicGroupApplyGoodsDto;
+import com.ym.mec.biz.dal.dto.MusicGroupBasicDto;
+import com.ym.mec.biz.dal.dto.RegisterPayDto;
+import com.ym.mec.biz.dal.dto.SporadicPayDto;
+import com.ym.mec.biz.dal.dto.StudentApplyInstrumentDto;
+import com.ym.mec.biz.dal.dto.StudentImportDto;
+import com.ym.mec.biz.dal.dto.SubFeeSettingDto;
+import com.ym.mec.biz.dal.dto.SubjectRegisterDto;
+import com.ym.mec.biz.dal.dto.UpdateExpectedNumDto;
+import com.ym.mec.biz.dal.entity.ApprovalStatus;
+import com.ym.mec.biz.dal.entity.ChargeType;
+import com.ym.mec.biz.dal.entity.ClassGroup;
+import com.ym.mec.biz.dal.entity.CooperationOrgan;
+import com.ym.mec.biz.dal.entity.CouponPayParam;
+import com.ym.mec.biz.dal.entity.CourseSchedule;
+import com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary;
+import com.ym.mec.biz.dal.entity.FinancialExpenditure;
+import com.ym.mec.biz.dal.entity.Goods;
+import com.ym.mec.biz.dal.entity.ImGroup;
+import com.ym.mec.biz.dal.entity.MusicGroup;
+import com.ym.mec.biz.dal.entity.MusicGroupBuildLog;
+import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender;
 import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PayUserType;
 import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentCalenderStatusEnum;
 import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentType;
+import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderCourseSettings;
+import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderDetail;
+import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderStudentDetail;
+import com.ym.mec.biz.dal.entity.MusicGroupPurchaseList;
+import com.ym.mec.biz.dal.entity.MusicGroupQuit;
+import com.ym.mec.biz.dal.entity.MusicGroupReturnFeeDto;
+import com.ym.mec.biz.dal.entity.MusicGroupSchoolTermCourseDetail;
+import com.ym.mec.biz.dal.entity.MusicGroupStudentFee;
 import com.ym.mec.biz.dal.entity.MusicGroupStudentFee.PaymentStatus;
-import com.ym.mec.biz.dal.enums.*;
+import com.ym.mec.biz.dal.entity.MusicGroupPaymentStudentCourseDetail;
+import com.ym.mec.biz.dal.entity.MusicGroupSubjectGoodsGroup;
+import com.ym.mec.biz.dal.entity.MusicGroupSubjectPlan;
+import com.ym.mec.biz.dal.entity.MusicMemberDto;
+import com.ym.mec.biz.dal.entity.Organization;
+import com.ym.mec.biz.dal.entity.School;
+import com.ym.mec.biz.dal.entity.SporadicChargeInfo;
+import com.ym.mec.biz.dal.entity.Student;
+import com.ym.mec.biz.dal.entity.StudentInstrument;
+import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
+import com.ym.mec.biz.dal.entity.StudentPaymentOrderDetail;
+import com.ym.mec.biz.dal.entity.StudentPreRegistration;
+import com.ym.mec.biz.dal.entity.StudentRegistration;
+import com.ym.mec.biz.dal.entity.Subject;
+import com.ym.mec.biz.dal.entity.SubjectChange;
+import com.ym.mec.biz.dal.entity.SysUserCashAccount;
+import com.ym.mec.biz.dal.entity.SysUserCashAccountDetail;
+import com.ym.mec.biz.dal.entity.SysUserCashAccountLog;
+import com.ym.mec.biz.dal.enums.ClassGroupTypeEnum;
+import com.ym.mec.biz.dal.enums.CouponDetailTypeEnum;
+import com.ym.mec.biz.dal.enums.CourseStatusEnum;
+import com.ym.mec.biz.dal.enums.CourseViewTypeEnum;
+import com.ym.mec.biz.dal.enums.DealStatusEnum;
+import com.ym.mec.biz.dal.enums.FivePlusGradeEnum;
+import com.ym.mec.biz.dal.enums.GoodsType;
+import com.ym.mec.biz.dal.enums.GradeTypeEnum;
+import com.ym.mec.biz.dal.enums.GroupType;
+import com.ym.mec.biz.dal.enums.KitGroupPurchaseTypeEnum;
+import com.ym.mec.biz.dal.enums.MessageTypeEnum;
+import com.ym.mec.biz.dal.enums.MusicGroupStatusEnum;
+import com.ym.mec.biz.dal.enums.OrderDetailTypeEnum;
+import com.ym.mec.biz.dal.enums.OrderTypeEnum;
+import com.ym.mec.biz.dal.enums.PaymentStatusEnum;
+import com.ym.mec.biz.dal.enums.PlatformCashAccountDetailTypeEnum;
+import com.ym.mec.biz.dal.enums.ReturnFeeEnum;
+import com.ym.mec.biz.dal.enums.SixPlusGradeEnum;
+import com.ym.mec.biz.dal.enums.SporadicChargeTypeEnum;
+import com.ym.mec.biz.dal.enums.StudentMusicGroupStatusEnum;
+import com.ym.mec.biz.dal.enums.SysUserRoleEnum;
+import com.ym.mec.biz.dal.enums.TeachTypeEnum;
+import com.ym.mec.biz.dal.enums.YesOrNoEnum;
 import com.ym.mec.biz.dal.page.MusicGroupQueryInfo;
 import com.ym.mec.biz.dal.page.MusicMemberQueryInfo;
 import com.ym.mec.biz.event.source.GroupEventSource;
 import com.ym.mec.biz.event.source.SendSeoMessageSource;
-import com.ym.mec.biz.service.*;
+import com.ym.mec.biz.service.ClassGroupService;
+import com.ym.mec.biz.service.ClassGroupStudentMapperService;
+import com.ym.mec.biz.service.ContractService;
+import com.ym.mec.biz.service.CourseScheduleStudentPaymentService;
+import com.ym.mec.biz.service.GoodsService;
+import com.ym.mec.biz.service.ImGroupMemberService;
+import com.ym.mec.biz.service.ImGroupService;
+import com.ym.mec.biz.service.ImUserFriendService;
+import com.ym.mec.biz.service.MusicGroupPaymentCalenderService;
+import com.ym.mec.biz.service.MusicGroupService;
+import com.ym.mec.biz.service.MusicGroupSubjectGoodsGroupService;
+import com.ym.mec.biz.service.MusicGroupSubjectPlanService;
+import com.ym.mec.biz.service.PayService;
+import com.ym.mec.biz.service.StudentPaymentOrderDetailService;
+import com.ym.mec.biz.service.StudentPaymentOrderService;
+import com.ym.mec.biz.service.StudentPaymentRouteOrderService;
+import com.ym.mec.biz.service.StudentRegistrationService;
+import com.ym.mec.biz.service.StudentService;
+import com.ym.mec.biz.service.SysConfigService;
+import com.ym.mec.biz.service.SysCouponCodeService;
+import com.ym.mec.biz.service.SysEmployeePositionService;
+import com.ym.mec.biz.service.SysMessageService;
+import com.ym.mec.biz.service.SysTenantConfigService;
+import com.ym.mec.biz.service.SysUserCashAccountDetailService;
+import com.ym.mec.biz.service.SysUserCashAccountService;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.dal.BaseDAO;
 import com.ym.mec.common.entity.HttpResponseResult;
@@ -32,30 +206,7 @@ import com.ym.mec.util.collection.MapUtil;
 import com.ym.mec.util.date.DateUtil;
 import com.ym.mec.util.http.HttpUtil;
 import com.ym.mec.util.json.JsonUtil;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static com.ym.mec.biz.dal.entity.ApprovalStatus.PROCESSING;
-import static com.ym.mec.biz.dal.enums.DealStatusEnum.ING;
-import static com.ym.mec.biz.dal.enums.DealStatusEnum.SUCCESS;
-import static com.ym.mec.biz.dal.enums.OrderDetailTypeEnum.*;
-import static com.ym.mec.biz.dal.enums.PaymentStatusEnum.YES;
-import static com.ym.mec.biz.dal.enums.SysUserRoleEnum.ORGAN_MANAGER;
+import com.ym.mec.util.validator.CommonValidator;
 
 @Service
 public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> implements MusicGroupService {
@@ -83,6 +234,8 @@ public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> i
     @Autowired
     private MusicGroupSubjectPlanDao musicGroupSubjectPlanDao;
     @Autowired
+    private MusicGroupSubjectPlanService musicGroupSubjectPlanService;
+    @Autowired
     private MusicGroupBuildLogDao musicGroupBuildLogDao;
     @Autowired
     private MusicGroupPurchaseListDao musicGroupPurchaseListDao;
@@ -189,6 +342,10 @@ public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> i
     private SendSeoMessageSource sendSeoMessageSource;
     @Autowired
     private SysEmployeePositionService employeePositionService;
+    @Autowired
+    private SysUserCashAccountDao sysUserCashAccountDao;
+    @Autowired
+    private StudentDao studentDao;
 
     private SimpleDateFormat sdf_ymd = new SimpleDateFormat("yyyy-MM-dd");
 
@@ -204,6 +361,7 @@ public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> i
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
 	public boolean importStudentToMusicGroup(String musicGroupId, Map<String, List<Map<String, Object>>> excelData) {
     	
     	MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
@@ -216,10 +374,240 @@ public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> i
     		throw new BizException("只有[缴费中]状态的乐团才能导入数据");
     	}
     	
-    	//查询缴费金额是否是0
+    	Integer tenantId = musicGroup.getTenantId();
+    	
+    	List<StudentImportDto> studentBasicList = new ArrayList<StudentImportDto>();
+    	List<Map<String, Object>> sheet = null;
+    	StudentImportDto dto = null;
+    	for (String sheetName : excelData.keySet()) {
+    		sheet = excelData.get(sheetName);
+    		for(Map<String,Object> row : sheet){
+        		dto = new StudentImportDto();
+        		if(row.get("学生姓名") == null || StringUtils.isBlank(row.get("学生姓名").toString())){
+        			throw new BizException("学生姓名不能为空");
+        		}
+        		dto.setName(row.get("学生姓名").toString());
+        		if(!CommonValidator.isUserName(dto.getName())){
+        			throw new BizException("学生姓名[{}]填写错误", dto.getName());
+        		}
+        		
+        		if(row.get("性别") == null || StringUtils.isBlank(row.get("性别").toString())){
+        			throw new BizException("性别不能为空");
+        		}
+    			dto.setSex(row.get("性别").toString());
+    			
+        		if(row.get("手机号码") == null || StringUtils.isBlank(row.get("手机号码").toString())){
+        			throw new BizException("手机号码不能为空");
+        		}
+    			dto.setMobileNo(row.get("手机号码").toString());
+        		if(!CommonValidator.isMobileNo(dto.getMobileNo())){
+        			throw new BizException("手机号码[{}]填写错误", dto.getMobileNo());
+        		}
+        		
+        		if(row.get("学习声部") == null || StringUtils.isBlank(row.get("学习声部").toString())){
+        			throw new BizException("学习声部不能为空");
+        		}
+    			dto.setSubjectName(row.get("学习声部").toString());
+    			
+        		if(row.get("所在年级") == null || StringUtils.isBlank(row.get("所在年级").toString())){
+        			throw new BizException("所在年级不能为空");
+        		}
+    			dto.setGradeName(row.get("所在年级").toString());
+    			
+    			studentBasicList.add(dto);
+    		}
+    	}
+    	
+    	Date nowDate = new Date();
+    	
+    	//查询导入的声部是否正确
+    	List<String> subjectNameList = studentBasicList.stream().distinct().map(t->t.getSubjectName()).collect(Collectors.toList());
+    	
+    	List<MusicGroupSubjectPlan> musicGroupSubjectPlanList = musicGroupSubjectPlanDao.getMusicSubjectClassPlan(musicGroupId);
+    	
+    	Map<String,Integer> subjectMap = musicGroupSubjectPlanList.stream().collect(Collectors.toMap(MusicGroupSubjectPlan :: getSubName, MusicGroupSubjectPlan :: getSubjectId));
+    	
+    	List<String> allSubjectNameList = musicGroupSubjectPlanList.stream().map(t -> t.getSubName()).collect(Collectors.toList());
+    	
+    	for(String subName : subjectNameList){
+    		if(!allSubjectNameList.contains(subName)){
+    			throw new BizException("当前乐团不支持[{}]声部", subName);
+    		}
+    	}
+    	
+    	//查询课程费用是否是0
+    	MusicGroupPaymentCalender musicGroupPaymentCalender = musicGroupPaymentCalenderDao.findByMusicGroupRegCalender(musicGroupId);
+    	if(musicGroupPaymentCalender == null){
+    		throw new BizException("请先创建乐团报名缴费");
+    	}
+    	
+    	List<MusicGroupPaymentCalenderCourseSettings> musicGroupPaymentCalenderCourseSettingsList = musicGroupPaymentCalenderCourseSettingsDao.queryCalenderCourseSettings(musicGroupPaymentCalender.getId());
+    	double d = musicGroupPaymentCalenderCourseSettingsList.stream().mapToDouble(t -> t.getCourseCurrentPrice().doubleValue()).sum();
     	
+    	if(d > 0){
+    		throw new BizException("缴费项目中的课程费用为[{}]元,不能导入", d);
+    	}
+    	
+    	//检查用户是否已入团或在其他机构已注册
+    	for(StudentImportDto si : studentBasicList){
+    		SysUser sysUser = studentRegistrationDao.getSysUserByPhone(si.getMobileNo());
+            if (sysUser != null) {
+            	throw new BizException("该手机号[{}]已注册", si.getMobileNo());
+            }
+    	}
+    	
+    	SysUser sysUser = null;
+    	Integer userId = null;
+    	Student student = null;
+    	StudentRegistration studentRegistration = null;
+    	List<StudentRegistration> insertList = new ArrayList<StudentRegistration>();
+		Organization organization = organizationDao.get(musicGroup.getOrganId());
+    	//插入记录
+		for (StudentImportDto si : studentBasicList) {
+			sysUser = new SysUser();
+			sysUser.setPhone(si.getMobileNo());
+			sysUser.setUsername(si.getName());
+			sysUser.setGender(si.getSex().equals("男") ? 1 : 0);
+			sysUser.setUserType("STUDENT");
+			sysUser.setOrganId(musicGroup.getOrganId());
+			sysUser.setCreateTime(nowDate);
+			sysUser.setUpdateTime(nowDate);
+			teacherDao.addSysUser(sysUser);
+			userId = sysUser.getId();
+			
+			si.setUserId(userId);
+			
+			student = new Student(userId, subjectMap.get(si.getSubjectName()) + "");
+	        student.setCurrentGradeNum(SixPlusGradeEnum.get(si.getGradeName()).getCode());
+			studentDao.insert(student);
+			// 添加用户现金账户
+			sysUserCashAccountDao.insert(new SysUserCashAccount(userId, "CNY"));
+			
+			studentRegistration = new StudentRegistration();
+	        String studentGrade = studentService.getStudentGrade(organization.getGradeType(), student.getCurrentGradeNum());
+	        studentRegistration.setCurrentGrade(studentGrade);
+	        studentRegistration.setActualSubjectId(subjectMap.get(si.getSubjectName()));
+	        studentRegistration.setIsAllowAdjust(YesOrNoEnum.YES);
+	        studentRegistration.setSubjectId(subjectMap.get(si.getSubjectName()));
+	        studentRegistration.setUserId(userId);
+	        studentRegistration.setName(si.getName());
+	        studentRegistration.setGender(sysUser.getGender());
+	        studentRegistration.setPaymentStatus(PaymentStatusEnum.YES);
+	        studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);
+	        studentRegistration.setTemporaryCourseFee(BigDecimal.ZERO);
+	        studentRegistration.setMusicGroupPaymentCalenderId(null);
+	        studentRegistration.setTenantId(musicGroup.getTenantId());
+	        studentRegistration.setMusicGroupId(musicGroupId);
+	        studentRegistration.setCreateTime(nowDate);
+	        studentRegistration.setUpdateTime(nowDate);
+	        
+	        insertList.add(studentRegistration);
+		}
+        
+		if (insertList.size() > 0) {
+			studentRegistrationService.batchInsert(insertList);
+
+			Map<Integer, Long> subjectCountMap = insertList.stream().collect(
+					Collectors.groupingBy(StudentRegistration::getActualSubjectId, Collectors.counting()));
+
+			MusicGroupSubjectPlan musicOneSubjectClassPlan = null;
+			int totalStudentNum = 0;
+			for (Entry<Integer, Long> entry : subjectCountMap.entrySet()) {
+
+				musicOneSubjectClassPlan = musicGroupSubjectPlanDao.getMusicOneSubjectClassPlan(musicGroupId, entry.getKey());
+				if (musicOneSubjectClassPlan == null) {
+					throw new BizException("系统数据[乐团声部设置]异常");
+				}
+				int applyNum = musicOneSubjectClassPlan.getApplyStudentNum() == null ? 0 : musicOneSubjectClassPlan.getApplyStudentNum();
+				musicOneSubjectClassPlan.setApplyStudentNum(applyNum + entry.getValue().intValue());
+				musicOneSubjectClassPlan.setPaidStudentNum((musicOneSubjectClassPlan.getPaidStudentNum() == null ? 0 : musicOneSubjectClassPlan
+						.getPaidStudentNum()) + entry.getValue().intValue());
+				musicOneSubjectClassPlan.setPaidZeroNum((musicOneSubjectClassPlan.getPaidZeroNum() == null ? 0 : musicOneSubjectClassPlan.getPaidZeroNum())
+						+ entry.getValue().intValue());
+				musicOneSubjectClassPlan.setUpdateTime(nowDate);
+				musicGroupSubjectPlanDao.update(musicOneSubjectClassPlan);
+
+				totalStudentNum += entry.getValue().intValue();
+			}
+
+			// 缴费相关
+			// 更新实际缴费人数
+			if (musicGroupPaymentCalender.getActualNum() == null) {
+				musicGroupPaymentCalender.setActualNum(totalStudentNum);
+			} else {
+				musicGroupPaymentCalender.setActualNum(musicGroupPaymentCalender.getActualNum() + totalStudentNum);
+			}
+			if (musicGroupPaymentCalender.getPaymentType() == MusicGroupPaymentCalender.PaymentType.MUSIC_APPLY) {
+				if (musicGroupPaymentCalender.getExpectNum() == null) {
+					musicGroupPaymentCalender.setExpectNum(totalStudentNum);
+				} else {
+					musicGroupPaymentCalender.setExpectNum(musicGroupPaymentCalender.getExpectNum() + totalStudentNum);
+				}
+			}
+			musicGroupPaymentCalender.setUpdateTime(nowDate);
+			musicGroupPaymentCalenderDao.update(musicGroupPaymentCalender);
+
+			MusicGroupPaymentCalenderDetail musicGroupPaymentCalenderDetail = null;
+			List<MusicGroupPaymentCalenderDetail> insertMusicGroupPaymentCalenderDetailList = new ArrayList<MusicGroupPaymentCalenderDetail>();
+
+			List<MusicGroupPaymentStudentCourseDetail> musicGroupPaymentStudentCourseDetails = new ArrayList<>();
+
+			List<MusicGroupPaymentCalenderCourseSettings> courseSettingsList = musicGroupPaymentCalenderCourseSettingsDao
+					.getWithPaymentCalender(musicGroupPaymentCalender.getId());
+
+			for (StudentImportDto si : studentBasicList) {
+				musicGroupPaymentCalenderDetail = new MusicGroupPaymentCalenderDetail();
+				musicGroupPaymentCalenderDetail.setTenantId(tenantId);
+				musicGroupPaymentCalenderDetail.setMusicGroupPaymentCalenderId(musicGroupPaymentCalender.getId());
+				musicGroupPaymentCalenderDetail.setUserId(si.getUserId());
+				musicGroupPaymentCalenderDetail.setResponsibleUserId(musicGroupPaymentCalender.getOperator());
+				musicGroupPaymentCalenderDetail.setPaymentStatus(PAID_COMPLETED);
+				musicGroupPaymentCalenderDetail.setPayTime(nowDate);
+				musicGroupPaymentCalenderDetail.setPaymentOrderId(null);
+				musicGroupPaymentCalenderDetail.setUseInCourse(0);
+				musicGroupPaymentCalenderDetail.setOpen(1);
+				musicGroupPaymentCalenderDetail.setUserStatus(null);
+				musicGroupPaymentCalenderDetail.setDeadlinePaymentDate(musicGroupPaymentCalender.getDeadlinePaymentDate());
+				musicGroupPaymentCalenderDetail.setStartPaymentDate(musicGroupPaymentCalender.getStartPaymentDate());
+				musicGroupPaymentCalenderDetail.setCreateTime(nowDate);
+				musicGroupPaymentCalenderDetail.setUpdateTime(nowDate);
+
+				insertMusicGroupPaymentCalenderDetailList.add(musicGroupPaymentCalenderDetail);
+
+				for (MusicGroupPaymentCalenderCourseSettings courseSetting : courseSettingsList) {
+					if (courseSetting.getCourseTotalMinuties() == null || courseSetting.getCourseTotalMinuties() == 0) {
+						continue;
+					}
+					MusicGroupPaymentStudentCourseDetail musicGroupPaymentStudentCourseDetail = new MusicGroupPaymentStudentCourseDetail();
+					musicGroupPaymentStudentCourseDetail.setMusicGroupPaymentCalenderId(musicGroupPaymentCalender.getId());
+					//musicGroupPaymentStudentCourseDetail.setMusicGroupPaymentCalenderDetailId(musicGroupPaymentCalenderDetail.getId());
+					musicGroupPaymentStudentCourseDetail.setUserId(si.getUserId());
+					musicGroupPaymentStudentCourseDetail.setCourseType(courseSetting.getCourseType());
+					musicGroupPaymentStudentCourseDetail.setTotalCourseMinutes(courseSetting.getCourseTotalMinuties());
+					musicGroupPaymentStudentCourseDetail.setCourseOriginalPrice(courseSetting.getCourseOriginalPrice());
+					musicGroupPaymentStudentCourseDetail.setCourseCurrentPrice(courseSetting.getCourseCurrentPrice());
+					musicGroupPaymentStudentCourseDetail.setUsedCourseMinutes(0);
+					musicGroupPaymentStudentCourseDetail.setCreateTime(nowDate);
+					musicGroupPaymentStudentCourseDetail.setUpdateTime(nowDate);
+					musicGroupPaymentStudentCourseDetail.setTenantId(tenantId);
+					musicGroupPaymentStudentCourseDetails.add(musicGroupPaymentStudentCourseDetail);
+				}
+			}
+			if (insertMusicGroupPaymentCalenderDetailList.size() > 0) {
+				musicGroupPaymentCalenderDetailDao.batchInsert(insertMusicGroupPaymentCalenderDetailList);
+				
+				Map<Integer,Long> musicGroupPaymentCalenderDetailIdMap =  insertMusicGroupPaymentCalenderDetailList.stream().collect(Collectors.toMap(MusicGroupPaymentCalenderDetail :: getUserId, MusicGroupPaymentCalenderDetail :: getId));
+				
+				if (musicGroupPaymentStudentCourseDetails.size() > 0) {
+					for(MusicGroupPaymentStudentCourseDetail cd : musicGroupPaymentStudentCourseDetails){
+						cd.setMusicGroupPaymentCalenderDetailId(musicGroupPaymentCalenderDetailIdMap.get(cd.getUserId()));
+					}
+					musicGroupPaymentStudentCourseDetailDao.batchInsert(musicGroupPaymentStudentCourseDetails);
+				}
+			}
+		}
     	
-		return false;
+		return true;
 	}
 
 	@Override

+ 126 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentStatisticsServiceImpl.java

@@ -0,0 +1,126 @@
+package com.ym.mec.biz.service.impl;
+
+import com.ym.mec.biz.dal.dao.StudentBasicInfoDao;
+import com.ym.mec.biz.dal.dao.StudentStatisticsDao;
+import com.ym.mec.biz.dal.dao.TeacherDao;
+import com.ym.mec.biz.dal.dto.StudentStatisticsDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumForDateDto;
+import com.ym.mec.biz.dal.entity.StudentStatistics;
+import com.ym.mec.biz.dal.page.StudentStatisticsQueryInfo;
+import com.ym.mec.biz.service.StudentStatisticsService;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.service.impl.BaseServiceImpl;
+import com.ym.mec.util.collection.MapUtil;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class StudentStatisticsServiceImpl extends BaseServiceImpl<Integer, StudentStatistics>  implements StudentStatisticsService {
+	
+	@Autowired
+	private StudentStatisticsDao studentStatisticsDao;
+	@Autowired
+	private TeacherDao teacherDao;
+	@Autowired
+	private StudentBasicInfoDao studentBasicInfoDao;
+
+	@Override
+	public BaseDAO<Integer, StudentStatistics> getDAO() {
+		return studentStatisticsDao;
+	}
+
+	@Override
+	public void updateStudentStatistics() {
+		//更新声部班老师
+		studentBasicInfoDao.updateSubjectTeacher();
+		//更新乐团主管、指导老师
+		studentStatisticsDao.updateTeacherAndEdu();
+		//更新总课时数、已完成、剩余课时数、最近30天课耗、最近1年课耗
+		studentStatisticsDao.updateCourseNum();
+		//更新未排课总数
+		studentStatisticsDao.updateNoCourseNum();
+		//更新未开始价值总和
+		studentStatisticsDao.updateNotStartCourseFee();
+		//更新未排课价值
+		studentStatisticsDao.updateNoCourseFee();
+		//更新第一次课的时间\最近一次课时间
+		studentStatisticsDao.updateFirstAndLastCourseTime();
+		//更新进行中课程组数量
+		studentStatisticsDao.updateNormalGroupNum();
+	}
+
+	@Override
+	public PageInfo<StudentStatisticsDto> queryStatisticsPage(StudentStatisticsQueryInfo queryInfo) {
+		PageInfo<StudentStatisticsDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
+		Map<String, Object> params = new HashMap<String, Object>();
+		MapUtil.populateMap(params, queryInfo);
+		if(StringUtils.isNotEmpty(queryInfo.getOrganId())){
+			List<Integer> organIdList = Arrays.stream(queryInfo.getOrganId().split(",")).map(id -> Integer.valueOf(id)).collect(Collectors.toList());
+			params.put("organIdList",organIdList);
+		}
+		List<StudentStatisticsDto> dataList = null;
+		int count = studentStatisticsDao.countStatistics(params);
+		if (count > 0) {
+			pageInfo.setTotal(count);
+			params.put("offset", pageInfo.getOffset());
+			dataList = studentStatisticsDao.queryStatistics(params);
+		}
+		if (count == 0) {
+			dataList = new ArrayList<>();
+		}
+		pageInfo.setRows(dataList);
+		return pageInfo;
+	}
+
+    @Override
+    public StudentStatisticsSumDto studentSmallClassStatisticsSum(String groupType,String organId) {
+		List<Integer> organIdList = new ArrayList<>();
+		if(StringUtils.isNotEmpty(organId)){
+			organIdList = Arrays.stream(organId.split(",")).map(id -> Integer.valueOf(id)).collect(Collectors.toList());
+		}
+		return studentStatisticsDao.studentSmallClassStatisticsSum(groupType,organIdList);
+    }
+
+    @Override
+    public StudentStatisticsSumForDateDto studentSmallClassStatisticsSumForDate(String groupType, String startDate, String endDate,String organId) {
+		StudentStatisticsSumForDateDto sumForDateDto = new StudentStatisticsSumForDateDto();
+		List<Integer> organIdList = new ArrayList<>();
+		if(StringUtils.isNotEmpty(organId)){
+			organIdList = Arrays.stream(organId.split(",")).map(id -> Integer.valueOf(id)).collect(Collectors.toList());
+		}
+		//获取流失人数
+		sumForDateDto.setLostNum(studentStatisticsDao.countLostStudentNum(groupType,startDate,endDate,organIdList));
+		//获取新增人数
+		sumForDateDto.setAddNum(studentStatisticsDao.countAddStudentNum(groupType,startDate,endDate,organIdList));
+		//获取续费人数
+		sumForDateDto.setRenewNum(studentStatisticsDao.countRenewStudentNum(groupType,endDate,organIdList));
+		//获取回访人数
+		sumForDateDto.setVisitNum(studentStatisticsDao.countVisitNum(groupType,startDate,endDate,organIdList));
+        return sumForDateDto;
+    }
+
+	@Override
+	public List<Map<Integer, String>> queryTeacherList(String groupType) {
+		List<Integer> teacherIds = studentStatisticsDao.queryTeacherIds(groupType);
+		if(CollectionUtils.isNotEmpty(teacherIds)){
+			return teacherDao.queryNameByIdList(teacherIds);
+		}
+		return new ArrayList<>();
+	}
+
+	@Override
+	public List<Map<Integer, String>> queryDirectorList(String groupType) {
+		List<Integer> teacherIds = studentStatisticsDao.queryDirectorList(groupType);
+		if(CollectionUtils.isNotEmpty(teacherIds)){
+			return teacherDao.queryNameByIdList(teacherIds);
+		}
+		return new ArrayList<>();
+	}
+}

+ 7 - 1
mec-biz/src/main/java/com/ym/mec/biz/service/impl/SysMusicCompareRecordServiceImpl.java

@@ -207,7 +207,13 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 				head = userTrainStat.get(i);
 			}
 		}
-		head.setStudentNum(studentDao.countStudentsWithOrgan(null));
+		Map<String,Object> params = new HashMap<String, Object>();
+		params.put("tenantId", queryInfo.getTenantId());
+		List<Integer> organIds = new ArrayList<Integer>();
+		organIds.add(queryInfo.getOrganId());
+		params.put("organIds", organIds);
+		
+		head.setStudentNum(studentDao.countStudentsWithOrgan(params));
 		if(StringUtils.isBlank(head.getAvatar())){
 			SysUser user = sysUserFeignService.queryUserById(queryInfo.getUserId());
 			if(user != null){

+ 52 - 0
mec-biz/src/main/resources/config/mybatis/IndexBaseMonthDataMapper.xml

@@ -1873,4 +1873,56 @@
 		</if>
 		GROUP BY su.organ_id_
 	</select>
+	<select id="getStudentVipOrderNum"  resultMap="IndexBaseMonthData">
+		SELECT spo.create_time_ month_,spo.organ_id_,
+		       COUNT(DISTINCT spo.id_) total_num_,
+		       'STUDENT_VIP_ORDER_NUM' data_type_,spo.user_id_ extend_info_,spo.tenant_id_
+		FROM (SELECT id_,user_id_,organ_id_,activity_id_,music_group_id_,calender_id_,type_,group_type_,
+		             DATE_FORMAT(create_time_,'%Y-%m-%d') create_time_,tenant_id_ FROM student_payment_order
+		WHERE status_ = 'SUCCESS' AND DATE_FORMAT(create_time_,'%Y-%m-%d') = #{dayStr} AND tenant_id_ = #{tenantId}) spo
+		LEFT JOIN student_payment_order_detail spod ON spod.payment_order_id_ = spo.id_
+		LEFT JOIN vip_group_activity vga ON FIND_IN_SET(vga.id_,spo.activity_id_)
+		LEFT JOIN vip_group_category vgc ON vgc.id_ = vga.vip_group_category_id_list_
+		LEFT JOIN vip_group vg ON vg.id_ = spo.music_group_id_
+		LEFT JOIN vip_group_category vgc1 ON vgc1.id_ = vg.vip_group_category_id_
+		LEFT JOIN music_group_payment_calender_activity mgpca ON mgpca.calender_id_ = spo.calender_id_
+		LEFT JOIN vip_group_activity vga1 ON vga1.id_ = mgpca.activity_id_
+		LEFT JOIN vip_group_category vgc2 ON vgc2.id_ = vga1.vip_group_category_id_list_
+		WHERE (spo.group_type_ = 'SPORADIC' AND spo.type_ = 'DEGREE_REGISTRATION' AND spod.type_ = 'DEGREE_REGISTRATION')
+		OR (spo.group_type_ = 'SPORADIC' AND spo.type_ = 'DOUBLE_ELEVEN2020') OR (spo.group_type_ = 'DEGREE' AND spod.type_ = 'VIP')
+		OR (spo.type_ = 'SMALL_CLASS_TO_BUY' AND vgc1.name_ != '乐理课') OR (spo.group_type_ = 'MUSIC' AND spod.type_ = 'VIP' AND vgc2.name_ != '乐理课')
+		OR (spo.type_ = 'DOUBLE_ELEVEN2021' AND vgc.name_ != '乐理课')
+		GROUP BY spo.user_id_,spo.create_time_,spo.organ_id_;
+	</select>
+	<select id="getStudentTheoryOrderNum" resultMap="IndexBaseMonthData">
+		SELECT spo.create_time_ month_,spo.organ_id_,
+			   COUNT(DISTINCT spo.id_) total_num_,
+			   'STUDENT_THEORY_ORDER_NUM' data_type_,spo.user_id_ extend_info_,spo.tenant_id_
+		FROM (SELECT id_,user_id_,organ_id_,activity_id_,music_group_id_,calender_id_,type_,group_type_,
+					 DATE_FORMAT(create_time_,'%Y-%m-%d') create_time_,tenant_id_ FROM student_payment_order
+			  WHERE status_ = 'SUCCESS' AND DATE_FORMAT(create_time_,'%Y-%m-%d') = #{dayStr} AND tenant_id_ = #{tenantId}) spo
+				 LEFT JOIN student_payment_order_detail spod ON spod.payment_order_id_ = spo.id_
+				 LEFT JOIN vip_group_activity vga ON FIND_IN_SET(vga.id_,spo.activity_id_)
+				 LEFT JOIN vip_group_category vgc ON vgc.id_ = vga.vip_group_category_id_list_
+				 LEFT JOIN vip_group vg ON vg.id_ = spo.music_group_id_
+				 LEFT JOIN vip_group_category vgc1 ON vgc1.id_ = vg.vip_group_category_id_
+				 LEFT JOIN music_group_payment_calender_activity mgpca ON mgpca.calender_id_ = spo.calender_id_
+				 LEFT JOIN vip_group_activity vga1 ON vga1.id_ = mgpca.activity_id_
+				 LEFT JOIN vip_group_category vgc2 ON vgc2.id_ = vga1.vip_group_category_id_list_
+		WHERE (spo.group_type_ = 'DEGREE' AND spod.type_ = 'THEORY_COURSE')
+		   OR (spo.type_ = 'SMALL_CLASS_TO_BUY' AND vgc1.name_ = '乐理课') OR (spo.group_type_ = 'MUSIC' AND spod.type_ = 'VIP' AND vgc2.name_ = '乐理课')
+		   OR (spo.type_ = 'DOUBLE_ELEVEN2021' AND vgc.name_ = '乐理课')
+		GROUP BY spo.user_id_,spo.create_time_,spo.organ_id_;
+	</select>
+	<select id="getStudentPracticeOrderNum" resultMap="IndexBaseMonthData">
+		SELECT spo.create_time_ month_,spo.organ_id_,
+			   COUNT(DISTINCT spo.id_) total_num_,
+			   'STUDENT_PRACTICE_ORDER_NUM' data_type_,spo.user_id_ extend_info_,spo.tenant_id_
+		FROM (SELECT id_,user_id_,organ_id_,activity_id_,music_group_id_,calender_id_,type_,group_type_,
+					 DATE_FORMAT(create_time_,'%Y-%m-%d') create_time_,tenant_id_ FROM student_payment_order
+			  WHERE status_ = 'SUCCESS' AND DATE_FORMAT(create_time_,'%Y-%m-%d') = #{dayStr} AND tenant_id_ = #{tenantId}) spo
+				 LEFT JOIN student_payment_order_detail spod ON spod.payment_order_id_ = spo.id_
+		WHERE spo.type_ = 'PRACTICE_GROUP_BUY' OR spo.type_ = 'PRACTICE_GROUP_RENEW' OR (spo.group_type_ = 'MUSIC' AND spod.type_ = 'PRACTICE')
+		GROUP BY spo.user_id_,spo.create_time_,spo.organ_id_;
+	</select>
 </mapper>

+ 106 - 0
mec-biz/src/main/resources/config/mybatis/StudentBasicInfoMapper.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<!--
+这个文件是自动生成的。
+不要修改此文件。所有改动将在下次重新自动生成时丢失。
+-->
+<mapper namespace="com.ym.mec.biz.dal.dao.StudentBasicInfoDao">
+	
+	<resultMap type="com.ym.mec.biz.dal.entity.StudentBasicInfo" id="StudentBasicInfo">
+		<result column="user_id_" property="userId" />
+		<result column="user_name_" property="userName" />
+		<result column="phone_" property="phone" />
+		<result column="subject_id_" property="subjectId" />
+		<result column="subject_name_" property="subjectName" />
+		<result column="grade_" property="grade" />
+		<result column="organ_id_" property="organId" />
+		<result column="organ_name_" property="organName" />
+		<result column="cooperation_organ_id_" property="cooperationOrganId" />
+		<result column="cooperation_organ_name_" property="cooperationOrganName" />
+		<result column="subject_teacher_id_" property="subjectTeacherId" />
+		<result column="subject_teacher_name_" property="subjectTeacherName" />
+	</resultMap>
+	
+	<!-- 根据主键查询一条记录 -->
+	<select id="get" resultMap="StudentBasicInfo" >
+		SELECT * FROM student_basic_info WHERE user_id_ = #{userId} 
+	</select>
+	
+	<!-- 全查询 -->
+	<select id="findAll" resultMap="StudentBasicInfo">
+		SELECT * FROM student_basic_info ORDER BY user_id_
+	</select>
+	
+	<!-- 向数据库增加一条记录 -->
+	<insert id="insert" parameterType="com.ym.mec.biz.dal.entity.StudentBasicInfo" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
+		<!--
+		<selectKey resultClass="int" keyProperty="id" > 
+		SELECT SEQ_WSDEFINITION_ID.nextval AS ID FROM DUAL 
+		</selectKey>
+		-->
+		INSERT INTO student_basic_info (user_id_,user_name_,phone_,subject_id_,subject_name_,grade_,organ_id_,organ_name_,cooperation_organ_id_,cooperation_organ_name_,subject_teacher_id_,subject_teacher_name_) VALUES(#{userId},#{userName},#{phone},#{subjectId},#{subjectName},#{grade},#{organId},#{organName},#{cooperationOrganId},#{cooperationOrganName},#{subjectTeacherId},#{subjectTeacherName})
+	</insert>
+	
+	<!-- 根据主键查询一条记录 -->
+	<update id="update" parameterType="com.ym.mec.biz.dal.entity.StudentBasicInfo">
+		UPDATE student_basic_info <set>
+			<if test="subjectId != null">
+			subject_id_ = #{subjectId},
+			</if>
+			<if test="subjectName != null">
+			subject_name_ = #{subjectName},
+			</if>
+			<if test="userId != null">
+			user_id_ = #{userId},
+			</if>
+			<if test="organId != null">
+			organ_id_ = #{organId},
+			</if>
+			<if test="subjectTeacherId != null">
+			subject_teacher_id_ = #{subjectTeacherId},
+			</if>
+			<if test="userName != null">
+			user_name_ = #{userName},
+			</if>
+			<if test="cooperationOrganId != null">
+			cooperation_organ_id_ = #{cooperationOrganId},
+			</if>
+			<if test="organName != null">
+			organ_name_ = #{organName},
+			</if>
+			<if test="phone != null">
+			phone_ = #{phone},
+			</if>
+			<if test="cooperationOrganName != null">
+			cooperation_organ_name_ = #{cooperationOrganName},
+			</if>
+			<if test="grade != null">
+			grade_ = #{grade},
+			</if>
+			<if test="subjectTeacherName != null">
+			subject_teacher_name_ = #{subjectTeacherName},
+			</if>
+		</set> WHERE user_id_ = #{userId}
+	</update>
+	<update id="updateSubjectTeacher">
+		SELECT updateSubjectTeacher()
+	</update>
+
+	<!-- 根据主键删除一条记录 -->
+	<delete id="delete" >
+		DELETE FROM student_basic_info WHERE user_id_ = #{userId} 
+	</delete>
+	
+	<!-- 分页查询 -->
+	<select id="queryPage" resultMap="StudentBasicInfo" parameterType="map">
+		SELECT * FROM student_basic_info ORDER BY user_id_ <include refid="global.limit"/>
+	</select>
+	
+	<!-- 查询当前表的总记录数 -->
+	<select id="queryCount" resultType="int">
+		SELECT COUNT(*) FROM student_basic_info
+	</select>
+    <select id="getMaxId" resultType="java.lang.Integer">
+		SELECT MAX(id_) FROM student_basic_info
+	</select>
+</mapper>

+ 410 - 0
mec-biz/src/main/resources/config/mybatis/StudentStatisticsMapper.xml

@@ -0,0 +1,410 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<!--
+这个文件是自动生成的。
+不要修改此文件。所有改动将在下次重新自动生成时丢失。
+-->
+<mapper namespace="com.ym.mec.biz.dal.dao.StudentStatisticsDao">
+	
+	<resultMap type="com.ym.mec.biz.dal.entity.StudentStatistics" id="StudentStatistics">
+		<result column="id_" property="id" />
+		<result column="user_id_" property="userId" />
+		<result column="teacher_id_" property="teacherId" />
+		<result column="teacher_name_" property="teacherName" />
+		<result column="music_director_id_" property="musicDirectorId" />
+		<result column="music_director_name_" property="musicDirectorName" />
+		<result column="total_course_num_" property="totalCourseNum" />
+		<result column="over_course_num_" property="overCourseNum" />
+		<result column="sub_course_num_" property="subCourseNum" />
+		<result column="no_schedule_num_" property="noScheduleNum" />
+		<result column="first_course_time_" property="firstCourseTime" />
+		<result column="last_course_time_" property="lastCourseTime" />
+		<result column="lately_course_consumer_" property="latelyCourseConsumer" />
+		<result column="lately_year_course_consumer_" property="latelyYearCourseConsumer" />
+		<result column="visit_num_" property="visitNum" />
+		<result column="last_visit_status_" property="lastVisitStatus" />
+		<result column="visit_reason_" property="visitReason" />
+		<result column="last_visit_time_" property="lastVisitTime" />
+		<result column="not_start_course_fee_" property="notStartCourseFee" />
+		<result column="no_course_fee_" property="noCourseFee" />
+		<result column="preCourseFee" property="preCourseFee" />
+		<result column="first_order_time_" property="firstOrderTime" />
+		<result column="last_order_time_" property="lastOrderTime" />
+		<result column="order_num_" property="orderNum" />
+		<result column="group_type_" property="groupType" />
+	</resultMap>
+	
+	<!-- 根据主键查询一条记录 -->
+	<select id="get" resultMap="StudentStatistics" >
+		SELECT * FROM student_statistics WHERE id_ = #{id} 
+	</select>
+	
+	<!-- 全查询 -->
+	<select id="findAll" resultMap="StudentStatistics">
+		SELECT * FROM student_statistics ORDER BY id_
+	</select>
+
+	<!-- 向数据库增加一条记录 -->
+	<insert id="insert" parameterType="com.ym.mec.biz.dal.entity.StudentStatistics" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
+		INSERT INTO student_statistics (id_,user_id_,teacher_id_,teacher_name_,music_director_id_,
+		music_director_name_,total_course_num_,over_course_num_,sub_course_num_,
+		no_schedule_num_,first_course_time_,last_course_time_,lately_course_consumer_,
+		visit_num_,last_visit_status_,visit_reason_,last_visit_time_,not_start_course_fee_,no_course_fee_,first_order_time_,
+		last_order_time_,order_num_,group_type_)
+		VALUES(#{id},#{userId},#{teacherId},#{teacherName},#{musicDirectorId},#{musicDirectorName},
+		       #{totalCourseNum},#{overCourseNum},#{subCourseNum},#{noScheduleNum},#{firstCourseTime},#{lastCourseTime},
+		       #{latelyCourseConsumer},#{visitNum},#{lastVisitStatus},#{visitReason},#{lastVisitTime},#{notStartCourseFee},#{noCourseFee},#{firstOrderTime},
+		       #{lastOrderTime},#{orderNum},#{groupType})
+	</insert>
+
+	<!-- 根据主键查询一条记录 -->
+	<update id="update" parameterType="com.ym.mec.biz.dal.entity.StudentStatistics">
+		UPDATE student_statistics <set>
+		<if test="overCourseNum != null">
+		over_course_num_ = #{overCourseNum},
+		</if>
+		<if test="latelyCourseConsumer != null">
+		lately_course_consumer_ = #{latelyCourseConsumer},
+		</if>
+		<if test="lastCourseTime != null">
+		last_course_time_ = #{lastCourseTime},
+		</if>
+		<if test="totalCourseNum != null">
+		total_course_num_ = #{totalCourseNum},
+		</if>
+		<if test="musicDirectorName != null">
+		music_director_name_ = #{musicDirectorName},
+		</if>
+		<if test="visitNum != null">
+		visit_num_ = #{visitNum},
+		</if>
+		<if test="teacherName != null">
+		teacher_name_ = #{teacherName},
+		</if>
+		<if test="subCourseNum != null">
+		sub_course_num_ = #{subCourseNum},
+		</if>
+		<if test="lastVisitStatus != null">
+		last_visit_status_ = #{lastVisitStatus},
+		</if>
+		<if test="lastVisitTime != null">
+		last_visit_time_ = #{lastVisitTime},
+		</if>
+		<if test="teacherId != null">
+		teacher_id_ = #{teacherId},
+		</if>
+		<if test="musicDirectorId != null">
+		music_director_id_ = #{musicDirectorId},
+		</if>
+		<if test="lastOrderTime != null">
+		last_order_time_ = #{lastOrderTime},
+		</if>
+		<if test="firstOrderTime != null">
+		first_order_time_ = #{firstOrderTime},
+		</if>
+		<if test="orderNum != null">
+		order_num_ = #{orderNum},
+		</if>
+		<if test="groupType != null">
+		group_type_ = #{groupType},
+		</if>
+		<if test="visitReason != null">
+		visit_reason_ = #{visitReason},
+		</if>
+		<if test="notStartCourseFee != null">
+			not_start_course_fee_ = #{notStartCourseFee},
+		</if>
+		<if test="noCourseFee != null">
+			no_course_fee_ = #{noCourseFee},
+		</if>
+		<if test="noScheduleNum != null">
+		no_schedule_num_ = #{noScheduleNum},
+		</if>
+		<if test="firstCourseTime != null">
+		first_course_time_ = #{firstCourseTime},
+		</if>
+		</set> WHERE id_ = #{id}
+	</update>
+	<update id="updateTeacherAndEdu">
+		SELECT updateTeacherAndEdu()
+	</update>
+	<update id="updateCourseNum">
+		SELECT updateCourseNum()
+	</update>
+	<update id="updateNoCourseNum">
+		SELECT updateNoCourseNum()
+	</update>
+	<update id="updateNotStartCourseFee">
+		SELECT updateNotStartCourseFee()
+	</update>
+	<update id="updateNoCourseFee">
+		SELECT updateNoCourseFee()
+	</update>
+	<update id="updateFirstAndLastCourseTime">
+		SELECT updateFirstAndLastCourseTime()
+	</update>
+	<update id="updateNormalGroupNum">
+		SELECT updateNormalGroupNum()
+	</update>
+
+	<!-- 根据主键删除一条记录 -->
+	<delete id="delete" >
+		DELETE FROM student_statistics WHERE id_ = #{id} 
+	</delete>
+	
+	<!-- 分页查询 -->
+	<select id="queryPage" resultMap="StudentStatistics" parameterType="map">
+		SELECT * FROM student_statistics ORDER BY id_ <include refid="global.limit"/>
+	</select>
+	
+	<!-- 查询当前表的总记录数 -->
+	<select id="queryCount" resultType="int">
+		SELECT COUNT(*) FROM student_statistics
+	</select>
+	<resultMap id="StudentStatisticsDto" type="com.ym.mec.biz.dal.dto.StudentStatisticsDto" extends="StudentStatistics">
+		<association property="studentBasicInfo" javaType="com.ym.mec.biz.dal.entity.StudentBasicInfo">
+			<result column="user_id_" property="userId" />
+			<result column="user_name_" property="userName" />
+			<result column="phone_" property="phone" />
+			<result column="subject_id_" property="subjectId" />
+			<result column="subject_name_" property="subjectName" />
+			<result column="grade_" property="grade" />
+			<result column="organ_id_" property="organId" />
+			<result column="organ_name_" property="organName" />
+			<result column="cooperation_organ_id_" property="cooperationOrganId" />
+			<result column="cooperation_organ_name_" property="cooperationOrganName" />
+			<result column="subject_teacher_id_" property="subjectTeacherId" />
+			<result column="subject_teacher_name_" property="subjectTeacherName" />
+			<result column="course_balance_" property="courseBalance" />
+			<result column="student_status_" property="studentStatus" />
+		</association>
+	</resultMap>
+	<sql id="queryStatisticsSql">
+		<where>
+			<if test="search != null and search != ''">
+				AND (sbi.user_id_ = #{search} OR sbi.user_name_ LIKE CONCAT('%',#{search},'%'))
+			</if>
+			<if test="subjectId != null">
+				AND sbi.subject_id_ = #{subjectId}
+			</if>
+			<if test="studentStatus != null and studentStatus != ''">
+				<if test="studentStatus == 'NORMAL'">
+					AND (ss.no_schedule_num_ > 0 OR ss.sub_course_num_ > 0) AND (ss.lately_year_course_consumer_ > 0 OR ss.over_course_num_ &lt;= 0)
+				</if>
+				<if test="studentStatus == 'SLEEPY'">
+					AND ss.over_course_num_ > 0 AND (ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0) AND ss.lately_year_course_consumer_ &lt;= 0
+				</if>
+				<if test="studentStatus == 'LOST'">
+					AND ss.over_course_num_ > 0 AND ss.sub_course_num_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0 AND suca.course_balance_ &lt;= 0
+				</if>
+				<if test="studentStatus == 'PAUSE'">
+					AND suca.course_balance_ > 0 AND ss.sub_course_num_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0
+				</if>
+			</if>
+			<if test="studentStatus == null or studentStatus == ''">
+				AND (ss.over_course_num_ > 0 OR ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0 OR suca.course_balance_ > 0)
+			</if>
+			<if test="feedbackType != null and feedbackType != ''">
+				AND ss.last_visit_status_ = #{feedbackType}
+			</if>
+			<if test="latelyCourseConsumer != null">
+				AND ss.lately_course_consumer_ = #{latelyCourseConsumer}
+			</if>
+			<if test="latelyYearCourseConsumer != null">
+				AND ss.lately_year_course_consumer_ = #{latelyYearCourseConsumer}
+			</if>
+			<if test="visitNum != null">
+				AND ss.visit_num_ = #{visitNum}
+			</if>
+			<if test="teacherId != null">
+				AND ss.teacher_id_ = #{teacherId}
+			</if>
+			<if test="subjectTeacherId != null">
+				AND sbi.subject_teacher_id_ = #{subjectTeacherId}
+			</if>
+			<if test="musicDirectorId != null">
+				AND ss.music_director_id_ = #{musicDirectorId}
+			</if>
+			<if test="courseConsumerError != null and courseConsumerError == true">
+				AND ss.lately_course_consumer_ &lt; 4
+			</if>
+			<if test="courseConsumerError != null and courseConsumerError == false">
+				AND ss.lately_course_consumer_ >= 4
+			</if>
+			<if test="firstCourseStartTime != null">
+				AND ss.first_course_time_ >= #{firstCourseStartTime}
+			</if>
+			<if test="firstCourseEndTime != null">
+				AND ss.first_course_time_ &lt;= #{firstCourseEndTime}
+			</if>
+			<if test="groupType != null and groupType != ''">
+				AND ss.group_type_ = #{groupType}
+			</if>
+			<if test="organIdList != null and organIdList.size > 0">
+				AND sbi.organ_id_ IN
+				<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+					#{organId}
+				</foreach>
+			</if>
+		</where>
+	</sql>
+	<select id="countStatistics" resultType="java.lang.Integer">
+		SELECT COUNT(sbi.id_) FROM student_basic_info sbi
+		LEFT JOIN student_statistics ss ON ss.user_id_ = sbi.user_id_
+		LEFT JOIN sys_user_cash_account suca ON sbi.user_id_ = suca.user_id_
+		<include refid="queryStatisticsSql"/>
+	</select>
+	<select id="queryStatistics" resultMap="StudentStatisticsDto">
+		SELECT *,ss.not_start_course_fee_ + ss.no_course_fee_ preCourseFee,
+		CASE WHEN (ss.no_schedule_num_ > 0 OR ss.sub_course_num_ > 0) AND (ss.lately_year_course_consumer_ > 0 OR ss.over_course_num_ &lt;= 0) THEN '在读'
+		WHEN ss.over_course_num_ > 0 AND (ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0) AND ss.lately_year_course_consumer_ &lt;= 0 THEN '沉睡'
+		WHEN ss.over_course_num_ > 0 AND ss.sub_course_num_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0 AND suca.course_balance_ &lt;= 0 THEN '流失'
+		WHEN suca.course_balance_ > 0 AND ss.sub_course_num_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0 THEN '暂停' ELSE '其他' END student_status_
+		,suca.course_balance_
+		FROM student_basic_info sbi
+		LEFT JOIN student_statistics ss ON ss.user_id_ = sbi.user_id_
+		LEFT JOIN sys_user_cash_account suca ON sbi.user_id_ = suca.user_id_
+		<include refid="queryStatisticsSql"/>
+		<include refid="global.limit"/>
+	</select>
+	<resultMap id="StudentStatisticsSumDto" type="com.ym.mec.biz.dal.dto.StudentStatisticsSumDto">
+		<result property="sleepStudentNum" column="sleepStudentNum"/>
+		<result property="sleepStudentHasNotSchedule" column="sleepStudentHasNotSchedule"/>
+		<result property="sleepStudentNoNotSchedule" column="sleepStudentNoNotSchedule"/>
+		<result property="normalStudentNum" column="normalStudentNum"/>
+		<result property="normalStudentHasNormalGroupNum" column="normalStudentHasNormalGroupNum"/>
+		<result property="hasCourseBalanceAndNotSubCourseNum" column="hasCourseBalanceAndNotSubCourseNum"/>
+		<result property="normalStudentHasNoScheduleNum" column="normalStudentHasNoScheduleNum"/>
+		<result property="waitRenewNum" column="waitRenewNum"/>
+		<result property="subCourseNum" column="subCourseNum"/>
+		<result property="noScheduleNum" column="noScheduleNum"/>
+	</resultMap>
+	<select id="studentSmallClassStatisticsSum" resultMap="StudentStatisticsSumDto">
+		SELECT
+		COUNT(CASE WHEN ss.over_course_num_ > 0 AND (ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0) AND ss.lately_year_course_consumer_ &lt;= 0 THEN 1 ELSE NULL END) 'sleepStudentNum',
+		COUNT(CASE WHEN ss.over_course_num_ > 0 AND (ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0) AND ss.lately_year_course_consumer_ &lt;= 0 AND ss.no_schedule_num_ > 0 THEN 1 ELSE NULL END) 'sleepStudentHasNotSchedule',
+		COUNT(CASE WHEN ss.over_course_num_ > 0 AND (ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0) AND ss.lately_year_course_consumer_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0 THEN 1 ELSE NULL END) 'sleepStudentNoNotSchedule',
+		COUNT(CASE WHEN (ss.no_schedule_num_ > 0 OR ss.sub_course_num_ > 0) AND (ss.lately_year_course_consumer_ > 0 OR ss.over_course_num_ &lt;= 0) THEN 1 ELSE NULL END) 'normalStudentNum',
+		COUNT(CASE WHEN ((ss.no_schedule_num_ > 0 OR ss.sub_course_num_ > 0) AND (ss.lately_year_course_consumer_ > 0 OR ss.over_course_num_ &lt;= 0)) AND ss.normal_group_num_ > 0 THEN 1 ELSE NULL END) 'normalStudentHasNormalGroupNum',
+		COUNT(CASE WHEN suca.course_balance_ > 0 AND ss.sub_course_num_ &lt;= 0 AND ss.no_schedule_num_ &lt;= 0 THEN 1 ELSE NULL END) 'hasCourseBalanceAndNotSubCourseNum',
+		COUNT(CASE WHEN ((ss.no_schedule_num_ > 0 OR ss.sub_course_num_ > 0) AND (ss.lately_year_course_consumer_ > 0 OR ss.over_course_num_ &lt;= 0)) AND ss.no_schedule_num_ > 0 THEN 1 ELSE NULL END) 'normalStudentHasNoScheduleNum',
+		COUNT(CASE WHEN (ss.no_schedule_num_ + ss.sub_course_num_) &lt; 4 THEN 1 ELSE NULL END) 'waitRenewNum',
+		SUM(ss.sub_course_num_) 'subCourseNum',
+		SUM(ss.no_schedule_num_) 'noScheduleNum'
+		FROM student_statistics ss
+		LEFT JOIN sys_user_cash_account suca ON ss.user_id_ = suca.user_id_
+		LEFT JOIN student_basic_info sbi ON ss.user_id_ = sbi.user_id_
+		WHERE ss.group_type_ = #{groupType}
+		AND (ss.over_course_num_ > 0 OR ss.sub_course_num_ > 0 OR ss.no_schedule_num_ > 0 OR suca.course_balance_ > 0)
+		<if test="organIdList != null and organIdList.size > 0">
+			AND sbi.organ_id_ IN
+			<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+				#{organId}
+			</foreach>
+		</if>
+	</select>
+    <select id="countAddStudentNum" resultType="java.lang.Integer">
+		SELECT COUNT(extend_info_) FROM (
+		SELECT extend_info_ FROM index_base_month_data
+		WHERE data_type_ =
+		<if test="groupType == 'VIP'">
+			'STUDENT_VIP_ORDER_NUM'
+		</if>
+		<if test="groupType == 'THEORY'">
+			'STUDENT_THEORY_ORDER_NUM'
+		</if>
+		<if test="groupType == 'PRACTICE'">
+			'STUDENT_PRACTICE_ORDER_NUM'
+		</if>
+		AND extend_info_ IS NOT NULL
+		<if test="organIdList != null and organIdList.size > 0">
+			AND organ_id_ IN
+			<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+				#{organId}
+			</foreach>
+		</if>
+		GROUP BY extend_info_
+		<if test="startDate != null and startDate != '' and endDate != null and endDate != ''">
+			HAVING COUNT(CASE WHEN month_ &lt; #{startDate} THEN 1 ELSE NULL END) &lt; 1
+			AND COUNT(CASE WHEN month_ BETWEEN #{startDate} AND #{endDate} THEN 1 ELSE NULL END) > 0
+		</if>
+		)a
+	</select>
+	<select id="countRenewStudentNum" resultType="java.lang.Integer">
+		SELECT COUNT(extend_info_) FROM (
+		SELECT extend_info_ FROM index_base_month_data
+		<include refid="dateTypeSql"/>
+			AND extend_info_ IS NOT NULL
+		<if test="endDate != null and endDate != ''">
+			AND month_ &lt;= #{endDate}
+		</if>
+		<if test="organIdList != null and organIdList.size > 0">
+			AND organ_id_ IN
+			<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+				#{organId}
+			</foreach>
+		</if>
+		GROUP BY extend_info_
+		HAVING SUM(total_num_) > 1)a
+	</select>
+	<select id="countVisitNum" resultType="java.lang.Integer">
+		SELECT COUNT(DISTINCT student_id_) FROM student_visit
+		WHERE type_ = '小课回访' AND purpose_ =
+		<if test="groupType == 'VIP'">
+			'VIP课回访'
+		</if>
+		<if test="groupType == 'THEORY'">
+			'乐理课回访'
+		</if>
+		<if test="groupType == 'PRACTICE'">
+			'网管课回访'
+		</if>
+		<if test="startDate != null and startDate != ''">
+			AND visit_time_ >= #{startDate}
+		</if>
+		<if test="endDate != null and endDate != ''">
+			AND visit_time_ &lt;= #{endDate}
+		</if>
+		<if test="organIdList != null and organIdList.size > 0">
+			AND organ_id_ IN
+			<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+				#{organId}
+			</foreach>
+		</if>
+	</select>
+	<select id="countLostStudentNum" resultType="java.lang.Integer">
+		SELECT COUNT(ss.id_) FROM student_statistics ss
+		LEFT JOIN student_basic_info sbi ON ss.user_id_ = sbi.user_id_
+		WHERE ss.group_type_ = #{groupType} AND ss.last_visit_status_ = 'LOST'
+		<if test="startDate != null and startDate != ''">
+			AND ss.last_visit_time_ >= #{startDate}
+		</if>
+		<if test="endDate != null and endDate != ''">
+			AND ss.last_visit_time_ &lt;= #{endDate}
+		</if>
+		<if test="organIdList != null and organIdList.size > 0">
+			AND sbi.organ_id_ IN
+			<foreach collection="organIdList" item="organId" open="(" close=")" separator=",">
+				#{organId}
+			</foreach>
+		</if>
+	</select>
+	<select id="queryTeacherIds" resultType="java.lang.Integer">
+		SELECT DISTINCT teacher_id_ FROM student_statistics WHERE group_type_ = #{groupType} AND teacher_id_ IS NOT NULL
+	</select>
+	<select id="queryDirectorList" resultType="java.lang.Integer">
+		SELECT DISTINCT music_director_id_ FROM student_statistics WHERE group_type_ = #{groupType} AND music_director_id_ IS NOT NULL
+	</select>
+	<sql id="dateTypeSql">
+		WHERE data_type_ =
+		<if test="groupType == 'VIP'">
+			'STUDENT_VIP_ORDER_NUM'
+		</if>
+		<if test="groupType == 'THEORY'">
+			'STUDENT_THEORY_ORDER_NUM'
+		</if>
+		<if test="groupType == 'PRACTICE'">
+			'STUDENT_PRACTICE_ORDER_NUM'
+		</if>
+	</sql>
+</mapper>

+ 11 - 3
mec-biz/src/main/resources/config/mybatis/StudentVisitMapper.xml

@@ -11,7 +11,7 @@
         <result column="studentName" property="studentName"/>
         <result column="teacher_id_" property="teacherId"/>
         <result column="teacherName" property="teacherName"/>
-        <result column="visiter_type_" property="visiterType"/>
+        <result column="visiter_type_" property="visiterType" typeHandler="com.ym.mec.common.dal.CustomEnumTypeHandler"/>
         <result column="type_" property="type"/>
         <result column="purpose_" property="purpose"/>
         <result column="overview_" property="overview"/>
@@ -20,11 +20,12 @@
         <result column="create_time_" property="createTime"/>
         <result column="object_id_" property="objectId"/>
         <result column="tenant_id_" property="tenantId"/>
+        <result column="feedback_type_" property="feedbackType" typeHandler="com.ym.mec.common.dal.CustomEnumTypeHandler"/>
     </resultMap>
     <sql id="Base_Column_List">
         <!--@mbg.generated-->
         id_, music_group_id_, organ_id_, student_id_, teacher_id_, visiter_type_, type_, purpose_, overview_, feedback_,
-        visit_time_, create_time_,tenant_id_
+        visit_time_, create_time_,tenant_id_,feedback_type_
     </sql>
     <select id="get" parameterType="java.lang.Integer" resultMap="StudentVisit">
         select
@@ -40,11 +41,12 @@
     <insert id="insert" keyColumn="id_" keyProperty="id" parameterType="com.ym.mec.biz.dal.entity.StudentVisit"
             useGeneratedKeys="true">
         <!--@mbg.generated-->
-        insert into student_visit (music_group_id_, organ_id_, student_id_, teacher_id_, visiter_type_,
+        insert into student_visit (music_group_id_, organ_id_, student_id_, teacher_id_, visiter_type_, feedback_type_,
         type_, purpose_, overview_,
         feedback_, visit_time_, create_time_,object_id_,tenant_id_)
         values (#{musicGroupId,jdbcType=VARCHAR}, #{organId,jdbcType=INTEGER}, #{studentId,jdbcType=INTEGER},
         #{teacherId,jdbcType=INTEGER},#{visiterType,typeHandler=com.ym.mec.common.dal.CustomEnumTypeHandler},
+                #{feedbackType,typeHandler=com.ym.mec.common.dal.CustomEnumTypeHandler},
         #{type,jdbcType=VARCHAR}, #{purpose,jdbcType=VARCHAR}, #{overview,jdbcType=VARCHAR},
         #{feedback,jdbcType=VARCHAR}, #{visitTime}, #{createTime},#{objectId},#{tenantId})
     </insert>
@@ -116,6 +118,9 @@
             <if test="teacherId !=null">
                 AND sv.teacher_id_ = #{teacherId}
             </if>
+            <if test="studentId !=null">
+                AND sv.student_id_ = #{studentId}
+            </if>
             <if test="organId != null and organId != ''">
                 AND FIND_IN_SET(sv.organ_id_,#{organId})
             </if>
@@ -125,6 +130,9 @@
             <if test="type != null">
                 AND sv.type_ = #{type}
             </if>
+            <if test="feedbackType != null and feedbackType != ''">
+                AND sv.feedback_type_ = #{feedbackType}
+            </if>
             <if test="purpose != null">
                 AND sv.purpose_ = #{purpose}
             </if>

+ 3 - 3
mec-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml

@@ -418,9 +418,9 @@
 			COUNT(smcr.id_) trainNum,
 			COUNT(DISTINCT DATE(smcr.create_time_)) trainDays,
 			SUM(smcr.play_time_) trainTime,
-			MAX(IF(heard_level_='BEGINNER' AND source_time_ &lt;= play_time_, smcr.score_, 0)) beginnerMaxScore,
-			MAX(IF(heard_level_='ADVANCED' AND source_time_ &lt;= play_time_, smcr.score_, 0)) advancedMaxScore,
-			MAX(IF(heard_level_='PERFORMER' AND source_time_ &lt;= play_time_, smcr.score_, 0)) performerMaxScore
+			MAX(IF(heard_level_='BEGINNER' AND source_time_ &gt;= play_time_, smcr.score_, 0)) beginnerMaxScore,
+			MAX(IF(heard_level_='ADVANCED' AND source_time_ &gt;= play_time_, smcr.score_, 0)) advancedMaxScore,
+			MAX(IF(heard_level_='PERFORMER' AND source_time_ &gt;= play_time_, smcr.score_, 0)) performerMaxScore,smcr.tenant_id_ tenantId
 		FROM sys_music_compare_record smcr
 		WHERE user_id_=#{userId} AND monday_ = #{monday}
 	</select>

+ 6 - 0
mec-client-api/src/main/java/com/ym/mec/task/TaskRemoteService.java

@@ -254,4 +254,10 @@ public interface TaskRemoteService {
      */
     @GetMapping("task/destroyExpiredLiveRoom")
     void destroyExpiredLiveRoom();
+
+    /**
+     * 学员小课统计
+     */
+    @GetMapping("task/studentSmallClassStatistics")
+    void studentSmallClassStatistics();
 }

+ 5 - 0
mec-client-api/src/main/java/com/ym/mec/task/fallback/TaskRemoteServiceFallback.java

@@ -304,4 +304,9 @@ public class TaskRemoteServiceFallback implements TaskRemoteService {
     public void destroyExpiredLiveRoom() {
         logger.error("销毁直播间失败");
     }
+
+    @Override
+    public void studentSmallClassStatistics() {
+        logger.error("学员小课统计失败");
+    }
 }

+ 19 - 0
mec-task/src/main/java/com/ym/mec/task/jobs/StudentSmallClassStatisticsTask.java

@@ -0,0 +1,19 @@
+package com.ym.mec.task.jobs;
+
+import com.ym.mec.task.TaskRemoteService;
+import com.ym.mec.task.core.BaseTask;
+import com.ym.mec.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class StudentSmallClassStatisticsTask extends BaseTask {
+
+	@Autowired
+	private TaskRemoteService taskRemoteService;
+
+	@Override
+	public void execute() throws TaskException {
+		taskRemoteService.studentSmallClassStatistics();
+	}
+}

+ 16 - 0
mec-util/src/main/java/com/ym/mec/util/validator/CommonValidator.java

@@ -19,11 +19,14 @@ public class CommonValidator {
 	private static final String EMAIL_ADDR = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
 
 	private static final String PWD_CHECK_REGEX = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$";
+	
+	private static final String USER_NAME_CHECK_REGEX = "^[\\u4E00-\\u9FA5][\\u4E00-\\u9FA5|·]*[\\u4E00-\\u9FA5]$";
 
 	private static Pattern mobileNoPattern = Pattern.compile(MOBILE_NO);
 	private static Pattern telephoneNoPattern = Pattern.compile(TELEPHONE_NO);
 	private static Pattern emailAddrPattern = Pattern.compile(EMAIL_ADDR);
 	private static Pattern pwdCheckPattern = Pattern.compile(PWD_CHECK_REGEX);
+	private static Pattern userNameCheckPattern = Pattern.compile(USER_NAME_CHECK_REGEX);
 
 	/**
 	 * 是否邮箱地址
@@ -39,6 +42,19 @@ public class CommonValidator {
 	}
 
 	/**
+	 * 是否姓名
+	 * @param emailAddr
+	 * @return
+	 */
+	public static boolean isUserName(String userName) {
+		if (StringUtils.isBlank(userName)) {
+			return false;
+		}
+		Matcher matcher = userNameCheckPattern.matcher(userName);
+		return matcher.matches();
+	}
+
+	/**
 	 * 是否手机
 	 * @param mobileNo
 	 * @return boolean

+ 0 - 1
mec-web/src/main/java/com/ym/mec/web/controller/CourseScheduleController.java

@@ -4,7 +4,6 @@ import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.ClassGroupDao;
 import com.ym.mec.biz.dal.dao.ClassGroupTeacherMapperDao;
-import com.ym.mec.biz.dal.dao.EmployeeDao;
 import com.ym.mec.biz.dal.dao.VipGroupDao;
 import com.ym.mec.biz.dal.dto.*;
 import com.ym.mec.biz.dal.entity.*;

+ 119 - 0
mec-web/src/main/java/com/ym/mec/web/controller/StudentStatisticsController.java

@@ -0,0 +1,119 @@
+package com.ym.mec.web.controller;
+
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.biz.dal.dto.StudentStatisticsDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumDto;
+import com.ym.mec.biz.dal.dto.StudentStatisticsSumForDateDto;
+import com.ym.mec.biz.dal.entity.ManagerDownload;
+import com.ym.mec.biz.dal.enums.ExportTypeEnum;
+import com.ym.mec.biz.dal.page.StudentStatisticsQueryInfo;
+import com.ym.mec.biz.service.ExportService;
+import com.ym.mec.biz.service.OrganizationService;
+import com.ym.mec.biz.service.StudentStatisticsService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.common.exception.BizException;
+import com.ym.mec.common.page.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@RequestMapping("studentStatistics")
+@Api(tags = "学员小课统计")
+@RestController
+public class StudentStatisticsController extends BaseController {
+
+    @Autowired
+    private StudentStatisticsService studentStatisticsService;
+    @Autowired
+    private OrganizationService organizationService;
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
+    @Autowired
+    private ExportService exportService;
+
+    @ApiOperation(value = "分页查询收费类型列表")
+    @PostMapping("/queryPage")
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/queryPage')")
+    public HttpResponseResult<PageInfo<StudentStatisticsDto>> queryPage(StudentStatisticsQueryInfo queryInfo) {
+        queryInfo.setOrganId(organizationService.getEmployeeOrgan(queryInfo.getOrganId()));
+        return succeed(studentStatisticsService.queryStatisticsPage(queryInfo));
+    }
+
+    @ApiOperation(value = "小课学员管理汇总")
+    @GetMapping("/studentSmallClassStatisticsSum")
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/studentSmallClassStatisticsSum')")
+    @ApiImplicitParam(name = "groupType", value = "VIP、THEORY、PRACTICE", required = true, dataType = "String")
+    public HttpResponseResult<StudentStatisticsSumDto> studentSmallClassStatisticsSum(String groupType) {
+        return succeed(studentStatisticsService.studentSmallClassStatisticsSum(groupType,organizationService.getEmployeeOrgan(null)));
+    }
+
+    @ApiOperation(value = "小课学员管理按时间汇总")
+    @PostMapping("/studentSmallClassStatisticsSumForDate")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "groupType", value = "VIP、THEORY、PRACTICE", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "startDate", value = "开始时间-年月日", dataType = "String"),
+            @ApiImplicitParam(name = "endDate", value = "结束时间-年月日", dataType = "String"),
+    })
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/studentSmallClassStatisticsSumForDate')")
+    public HttpResponseResult<StudentStatisticsSumForDateDto> studentSmallClassStatisticsSumForDate(String groupType, String startDate, String endDate) {
+        return succeed(studentStatisticsService.studentSmallClassStatisticsSumForDate(groupType,startDate,endDate,organizationService.getEmployeeOrgan(null)));
+    }
+
+    @ApiOperation(value = "获取指导老师列表")
+    @GetMapping("/queryTeacherList")
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/queryTeacherList')")
+    @ApiImplicitParam(name = "groupType", value = "VIP、THEORY、PRACTICE", required = true, dataType = "String")
+    public HttpResponseResult<List<Map<Integer, String>>> queryTeacherList(String groupType) {
+        return succeed(studentStatisticsService.queryTeacherList(groupType));
+    }
+
+    @ApiOperation(value = "获取乐团主管列表")
+    @GetMapping("/queryDirectorList")
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/queryDirectorList')")
+    @ApiImplicitParam(name = "groupType", value = "VIP、THEORY、PRACTICE", required = true, dataType = "String")
+    public HttpResponseResult<List<Map<Integer, String>>> queryDirectorList(String groupType) {
+        return succeed(studentStatisticsService.queryDirectorList(groupType));
+    }
+
+    @ApiOperation(value = "导出小课学员管理")
+    @PostMapping("/exportStudentSmallClassStatisticsSum")
+    @PreAuthorize("@pcs.hasPermissions('studentStatistics/exportStudentSmallClassStatisticsSum')")
+    public HttpResponseResult exportStudentSmallClassStatisticsSum(StudentStatisticsQueryInfo queryInfo) throws IOException {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        queryInfo.setOrganId(organizationService.getEmployeeOrgan(sysUser.getId(),queryInfo.getOrganId(),sysUser.getIsSuperAdmin()));
+        PageInfo<StudentStatisticsDto> pageList = studentStatisticsService.queryStatisticsPage(queryInfo);
+        if (pageList.getTotal() <= 0) {
+            throw new BizException("没有可导出的记录");
+        }
+        ManagerDownload managerDownload = exportService.saveManagerDownload(ExportTypeEnum.STUDENT_SMALL_CLASS_STATISTICS,sysUser.getId());
+        ExecutorService executor = Executors.newCachedThreadPool();
+        CompletableFuture.runAsync(()->{
+            try {
+                queryInfo.setPage(1);
+                queryInfo.setRows(65535);
+                exportService.exportStudentSmallClassStatisticsSum(queryInfo, managerDownload);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        },executor);
+        HttpResponseResult<Object> succeed = succeed();
+        succeed.setMsg(managerDownload.getName() + "导出申请已提交,请到【报表中心-下载列表查看】");
+        return succeed;
+    }
+}

+ 8 - 0
mec-web/src/main/java/com/ym/mec/web/controller/TaskController.java

@@ -118,6 +118,8 @@ public class TaskController extends BaseController {
 	private TeacherContractsService teacherContractsService;
     @Autowired
     private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+	@Autowired
+	private StudentStatisticsService studentStatisticsService;
 
 	@GetMapping(value = "/syncImHistoryMessageTask")
 	// 同步即时通讯聊天记录
@@ -577,4 +579,10 @@ public class TaskController extends BaseController {
     public void destroyExpiredLiveRoom(){
         imLiveBroadcastRoomService.destroyExpiredLiveRoom();
     }
+
+    @ApiOperation("学员小课统计")
+    @GetMapping(value = "/studentSmallClassStatistics")
+    public void studentSmallClassStatistics(){
+		studentStatisticsService.updateStudentStatistics();
+    }
 }

BIN
mec-web/src/main/resources/excelTemplate/外部学生入团导入模板.xls