Browse Source

Merge branch 'feature/0704-stat' into saas

yuanliang 1 year ago
parent
commit
1caef597e2

+ 98 - 0
mec-application/src/main/java/com/ym/mec/student/controller/StudentCoursewarePlayRecordController.java

@@ -0,0 +1,98 @@
+package com.ym.mec.student.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
+import com.ym.mec.biz.service.StudentCoursewarePlayRecordService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.page.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.student:}/studentCoursewarePlayRecord")
+@Api(tags = "学生课件播放统计记录")
+public class StudentCoursewarePlayRecordController extends BaseController {
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private StudentCoursewarePlayRecordService studentCoursewarePlayRecordService;
+
+    @ApiOperation(value = "详情", notes = "学生课件播放统计记录-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/detail')")
+//    @GetMapping("/detail/{id}")
+    public HttpResponseResult<StudentCoursewarePlayRecord> detail(@PathVariable("id") Long id) {
+
+        StudentCoursewarePlayRecord wrapper = studentCoursewarePlayRecordService.detail(id);
+
+        return succeed(wrapper);
+    }
+
+    @ApiOperation(value = "查询分页", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/page')")
+//    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<StudentCoursewarePlayRecord>> page(@RequestBody StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery query) {
+
+        IPage<StudentCoursewarePlayRecord> pages = studentCoursewarePlayRecordService.selectPage(QueryInfo.getPage(query), query);
+
+        return succeed(PageUtil.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord")
+    @PostMapping("/save")
+    public HttpResponseResult<JSONObject> add(@Validated @RequestBody StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordSave studentCoursewarePlayRecord) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null) {
+            return failed("用户信息获取失败");
+        }
+        studentCoursewarePlayRecord.setUserId(sysUser.getId());
+        studentCoursewarePlayRecord.setOrganizationId(sysUser.getOrganId());
+        // 新增数据
+        studentCoursewarePlayRecordService.save(studentCoursewarePlayRecord);
+
+        return succeed();
+    }
+
+    @ApiOperation(value = "修改", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/update')")
+//    @PostMapping("/update")
+    public HttpResponseResult<JSONObject> update(@Validated @RequestBody StudentCoursewarePlayRecord studentCoursewarePlayRecord) {
+
+        // 更新数据
+        studentCoursewarePlayRecordService.updateById(studentCoursewarePlayRecord);
+
+        return succeed();
+    }
+
+    @ApiOperation(value = "删除", notes = "学生课件播放统计记录- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/remove')")
+//    @PostMapping("/remove")
+    public HttpResponseResult<Boolean> remove(@RequestParam Long id) {
+
+        return succeed(studentCoursewarePlayRecordService.removeById(id));
+    }
+}

+ 140 - 0
mec-application/src/main/java/com/ym/mec/web/controller/StudentCoursewarePlayRecordController.java

@@ -0,0 +1,140 @@
+package com.ym.mec.web.controller;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord;
+import com.ym.mec.biz.dal.enums.ExportEnum;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
+import com.ym.mec.biz.service.ExportService;
+import com.ym.mec.biz.service.OrganizationService;
+import com.ym.mec.biz.service.StudentCoursewarePlayRecordService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.page.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.web:}/studentCoursewarePlayRecord")
+@Api(tags = "学生课件播放统计记录")
+public class StudentCoursewarePlayRecordController extends BaseController {
+
+    @Autowired
+    private StudentCoursewarePlayRecordService studentCoursewarePlayRecordService;
+
+    @Autowired
+    private ExportService exportService;
+
+    @Autowired
+    private OrganizationService organizationService;
+
+    @ApiOperation(value = "详情", notes = "学生课件播放统计记录-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/detail')")
+//    @GetMapping("/detail/{id}")
+    public HttpResponseResult<StudentCoursewarePlayRecord> detail(@PathVariable("id") Long id) {
+
+        StudentCoursewarePlayRecord wrapper = studentCoursewarePlayRecordService.detail(id);
+
+        return succeed(wrapper);
+    }
+
+    @ApiOperation(value = "查询分页", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/page')")
+//    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<StudentCoursewarePlayRecord>> page(@RequestBody StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery query) {
+
+        IPage<StudentCoursewarePlayRecord> pages = studentCoursewarePlayRecordService.selectPage(QueryInfo.getPage(query), query);
+
+        return succeed(PageUtil.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/save')")
+//    @PostMapping("/save")
+    public HttpResponseResult<JSONObject> add(@Validated @RequestBody StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord studentCoursewarePlayRecord) {
+        return succeed();
+    }
+
+    @ApiOperation(value = "修改", notes = "学生课件播放统计记录- 传入 StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/update')")
+//    @PostMapping("/update")
+    public HttpResponseResult<JSONObject> update(@Validated @RequestBody StudentCoursewarePlayRecord studentCoursewarePlayRecord) {
+
+        // 更新数据
+        studentCoursewarePlayRecordService.updateById(studentCoursewarePlayRecord);
+
+        return succeed();
+    }
+
+    @ApiOperation(value = "删除", notes = "学生课件播放统计记录- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/remove')")
+//    @PostMapping("/remove")
+    public HttpResponseResult<Boolean> remove(@RequestParam Long id) {
+
+        return succeed(studentCoursewarePlayRecordService.removeById(id));
+    }
+
+    /**
+     * 练习统计
+     */
+    @PostMapping("/statList")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/statList')")
+    public HttpResponseResult<List<StudentCoursewarePlayRecordWrapper.StatQueryData>> statList(@RequestBody StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        statQuery.setOrganizationId(organizationService.getEmployeeOrgan(statQuery.getOrganizationId()));
+        return succeed(studentCoursewarePlayRecordService.statList(statQuery));
+    }
+
+
+    /**
+     * 练习统计导出
+     */
+    @PostMapping("/exportStatList")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/exportStatList')")
+    public HttpResponseResult exportStatList(@RequestBody StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        statQuery.setOrganizationId(organizationService.getEmployeeOrgan(statQuery.getOrganizationId()));
+        return exportService.getExportManageFuncMap().get(ExportEnum.VIDEO_PLAY_STAT).apply(JSON.parseObject(JSON.toJSONString(statQuery), Map.class));
+    }
+
+
+    /**
+     * 练习详情统计
+     */
+    @PostMapping("/statDetailPage")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/statDetailPage')")
+    public HttpResponseResult<PageInfo<StudentCoursewarePlayRecordWrapper.StatQueryData>> statDetailPage(@RequestBody StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        return succeed(PageUtil.pageInfo(studentCoursewarePlayRecordService.statDetailPage(statQuery)));
+    }
+
+    /**
+     * 练习统计详情导出
+     */
+    @PostMapping("/exportStatDetailPage")
+    @PreAuthorize("@pcs.hasPermissions('studentCoursewarePlayRecord/exportStatDetailPage')")
+    public HttpResponseResult exportStatDetailPage(@RequestBody StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        statQuery.setPage(1);
+        statQuery.setRows(9999);
+        return exportService.getExportManageFuncMap().get(ExportEnum.VIDEO_PLAY_DETAIL_STAT).apply(JSON.parseObject(JSON.toJSONString(statQuery), Map.class));
+    }
+}

+ 9 - 1
mec-application/src/main/resources/exportColumnMapper.ini

@@ -400,4 +400,12 @@ fieldColumns = ["organName","musicGroupId","musicGroupName","studentId","student
 
 [平衡关系(分表)-乐团退团学员]
 headColumns = ["分部","乐团编号","乐团名称","学员编号","学员名称"]
-fieldColumns = ["organName","musicGroupId","musicGroupName","studentId","studentName"]
+fieldColumns = ["organName","musicGroupId","musicGroupName","studentId","studentName"]
+
+[云课堂统计导出]
+headColumns = ["分部名称","会员人数","无练习人数","0-10分钟","10-60分钟","60-120分钟","120-240分钟",">240分钟","平均时长(分钟)"]
+fieldColumns = ["organizationName","memberNum","noPlayNum","playTimeLess10","playTimeLess60","playTimeLess120","playTimeLess240","playTimeRather240","avgPlayTime"]
+
+[云课堂统计详情导出]
+headColumns = ["声部老师","会员人数","无练习人数","0-10分钟","10-60分钟","60-120分钟","120-240分钟",">240分钟","平均时长(分钟)"]
+fieldColumns = ["teacherName","memberNum","noPlayNum","playTimeLess10","playTimeLess60","playTimeLess120","playTimeLess240","playTimeRather240","avgPlayTime"]

+ 52 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/StudentCoursewarePlayRecord.java

@@ -0,0 +1,52 @@
+package com.ym.mec.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+ * 学生课件播放统计记录
+ * 2024-07-04 14:48:14
+ */
+@Data
+@ApiModel(" StudentCoursewarePlayRecord-学生课件播放统计记录")
+@TableName("student_courseware_play_record")
+public class StudentCoursewarePlayRecord implements Serializable {
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id_")
+    private Long id;
+
+    @ApiModelProperty("分部ID")
+    @TableField(value = "organization_id_")
+    private Integer organizationId;
+
+    @ApiModelProperty("用户编号")
+    @TableField(value = "user_id_")
+    private Integer userId;
+
+    @ApiModelProperty("播放时长,单位为秒")
+    @TableField(value = "play_time_")
+    private BigDecimal playTime;
+
+    @ApiModelProperty("创建的天")
+    @TableField(value = "create_date_")
+    private String createDate;
+
+    @ApiModelProperty("更新时间")
+    @TableField(value = "update_time_")
+    private Date updateTime;
+
+    @ApiModelProperty("创建时间")
+    @TableField(value = "create_time_")
+    private Date createTime;
+
+}

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

@@ -103,6 +103,8 @@ public enum ExportEnum implements BaseEnum<String, ExportEnum> {
     EXPORT_BALANCED_RELATIONSHIP_STUDENT_INFO("EXPORT_BALANCED_RELATIONSHIP_STUDENT_INFO","平衡关系-学员情况总表"),
     EXPORT_BALANCED_RELATIONSHIP_STUDENT_NORMAL_DETAIL("EXPORT_BALANCED_RELATIONSHIP_STUDENT_NORMAL_DETAIL","平衡关系(分表)-乐团在读学员"),
     EXPORT_BALANCED_RELATIONSHIP_STUDENT_QUIT_DETAIL("EXPORT_BALANCED_RELATIONSHIP_STUDENT_QUIT_DETAIL","平衡关系(分表)-乐团退团学员"),
+    VIDEO_PLAY_STAT("VIDEO_PLAY_STAT","云课堂统计导出"),
+    VIDEO_PLAY_DETAIL_STAT("VIDEO_PLAY_DETAIL_STAT","云课堂统计详情导出"),
     ;
 
     private String code;

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

@@ -41,6 +41,8 @@ public enum ExportTypeEnum implements BaseEnum<Integer, ExportTypeEnum> {
 	EXPORT_BALANCED_RELATIONSHIP_STUDENT_INFO(34,"平衡关系-学员情况总表"),
 	EXPORT_BALANCED_RELATIONSHIP_STUDENT_NORMAL_DETAIL(35,"平衡关系(分表)-乐团在读学员"),
 	EXPORT_BALANCED_RELATIONSHIP_STUDENT_QUIT_DETAIL(36,"平衡关系(分表)-乐团退团学员"),
+	VIDEO_PLAY_STAT(37,"云课堂统计导出"),
+	VIDEO_PLAY_DETAIL_STAT(38,"云课堂统计详情导出"),
 	;
 
 	private Integer code;

+ 34 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/mapper/StudentCoursewarePlayRecordMapper.java

@@ -0,0 +1,34 @@
+package com.ym.mec.biz.dal.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+import com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
+
+/**
+ * 学生课件播放统计记录
+ * 2024-07-04 14:48:14
+ */
+@Repository
+public interface StudentCoursewarePlayRecordMapper extends BaseMapper<StudentCoursewarePlayRecord> {
+
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord>
+     * @param param StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery
+     * @return List<StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord>
+     */
+    List<StudentCoursewarePlayRecord> selectPage(@Param("page") IPage<StudentCoursewarePlayRecord> page, @Param("param") StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery param);
+
+    void save(@Param("record") StudentCoursewarePlayRecord record);
+
+    List<StudentCoursewarePlayRecordWrapper.StatQueryData> statList(@Param("statQuery") StudentCoursewarePlayRecordWrapper.StatQuery statQuery);
+
+    List<StudentCoursewarePlayRecordWrapper.StatQueryData> statDetailPage(@Param("page") IPage<StudentCoursewarePlayRecordWrapper.StatQueryData> page,
+                                                                          @Param("statQuery") StudentCoursewarePlayRecordWrapper.StatQuery statQuery);
+}

+ 177 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/wrapper/StudentCoursewarePlayRecordWrapper.java

@@ -0,0 +1,177 @@
+package com.ym.mec.biz.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 学生课件播放统计记录
+ * 2024-07-04 14:48:14
+ */
+@ApiModel(value = "StudentCoursewarePlayRecordWrapper对象", description = "学生课件播放统计记录查询对象")
+public class StudentCoursewarePlayRecordWrapper {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" StudentCoursewarePlayRecordQuery-学生课件播放统计记录")
+    public static class StudentCoursewarePlayRecordQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+        private String keyword;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static StudentCoursewarePlayRecordQuery from(String json) {
+            return JSON.parseObject(json, StudentCoursewarePlayRecordQuery.class);
+        }
+    }
+
+
+    @Data
+    @ApiModel(" StudentCoursewarePlayRecord-学生课件播放统计记录")
+    public static class StudentCoursewarePlayRecord {
+
+        @ApiModelProperty("乐团ID")
+        private String musicGroupId;
+
+        @ApiModelProperty("用户编号")
+        private Long userId;
+
+        @ApiModelProperty("在读状态")
+        private Boolean readingStatus;
+
+        @ApiModelProperty("播放时长,单位为秒")
+        private Float playTime;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static StudentCoursewarePlayRecord from(String json) {
+            return JSON.parseObject(json, StudentCoursewarePlayRecord.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" StudentCoursewarePlayRecord-学生课件播放统计记录")
+    public static class StudentCoursewarePlayRecordSave {
+
+        @ApiModelProperty(value = "用户编号",hidden = true)
+        private Integer userId;
+
+        @ApiModelProperty(hidden = true)
+        private Integer organizationId;
+
+        @ApiModelProperty("播放时长,单位为秒")
+        @NotNull
+        private BigDecimal playTime;
+
+    }
+
+
+    @Data
+    @ApiModel("云课堂观看统计查询")
+    public static class StatQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("开始时间")
+        private Date startTime;
+
+        @ApiModelProperty("结束时间")
+        private Date endTime;
+
+        @ApiModelProperty("分部ID")
+        private String organizationId;
+
+        @ApiModelProperty("排序值,1:会员,2:无练习,3:10分钟,4:60分钟,5:120分钟,6:240分钟,7:>240分钟,8:平均时长")
+        private Integer sort = 1;
+
+        @ApiModelProperty("声降序,true:升序,false:降序")
+        private Boolean asc = false;
+
+        @ApiModelProperty(hidden = true)
+        private String sortBy;
+
+        @ApiModelProperty(hidden = true)
+        private static List<String> sortKeys = Arrays.asList("memberNum", "noPlayNum", "playTimeLess10", "playTimeLess60", "playTimeLess120", "playTimeLess240", "playTimeRather240", "avgPlayTime");
+
+        public String getSortBy() {
+            String key = sortKeys.get(getSort() > sortKeys.size() ? 0 : getSort() - 1);
+            return key + (asc ? " asc" : " desc");
+        }
+    }
+
+    @Data
+    @ApiModel("云课堂观看统计查询结果")
+    public static class StatQueryData {
+
+        @ApiModelProperty("分部ID")
+        private Long organizationId;
+
+        @ApiModelProperty("分部名称")
+        private String organizationName;
+
+        @ApiModelProperty("声部老师")
+        private String teacherName;
+
+        @ApiModelProperty("会员数量")
+        private Integer memberNum;
+
+        @ApiModelProperty("无练习人数")
+        private Integer noPlayNum;
+
+        @ApiModelProperty("练习时长少于等于10分钟")
+        private Integer playTimeLess10;
+
+        @ApiModelProperty("练习时长少于等于60分钟")
+        private Integer playTimeLess60;
+
+        @ApiModelProperty("练习时长少于等于120分钟")
+        private Integer playTimeLess120;
+
+        @ApiModelProperty("练习时长少于等于240")
+        private Integer playTimeLess240;
+
+        @ApiModelProperty("练习时长大于240")
+        private Integer playTimeRather240;
+
+        @ApiModelProperty("平均练习时长")
+        private BigDecimal avgPlayTime;
+
+    }
+
+}

+ 50 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/StudentCoursewarePlayRecordService.java

@@ -0,0 +1,50 @@
+package com.ym.mec.biz.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
+import com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord;
+
+import java.util.List;
+
+/**
+ * 学生课件播放统计记录
+ * 2024-07-04 14:48:14
+ */
+public interface StudentCoursewarePlayRecordService extends IService<StudentCoursewarePlayRecord>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return StudentCoursewarePlayRecord
+     */
+    StudentCoursewarePlayRecord detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<StudentCoursewarePlayRecord>
+     * @param query StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery
+     * @return IPage<StudentCoursewarePlayRecord>
+     */
+    IPage<StudentCoursewarePlayRecord> selectPage(IPage<StudentCoursewarePlayRecord> page, StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery query);
+
+    /**
+     * 添加
+     * @param studentCoursewarePlayRecord StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord
+     * @return Boolean
+     */
+    Boolean add(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord studentCoursewarePlayRecord);
+
+    /**
+     * 更新
+     * @param studentCoursewarePlayRecord StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord
+     * @return Boolean
+     */
+    Boolean update(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord studentCoursewarePlayRecord);
+
+    void save(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordSave studentCoursewarePlayRecord);
+
+    List<StudentCoursewarePlayRecordWrapper.StatQueryData> statList(StudentCoursewarePlayRecordWrapper.StatQuery statQuery);
+
+    IPage<StudentCoursewarePlayRecordWrapper.StatQueryData> statDetailPage(StudentCoursewarePlayRecordWrapper.StatQuery statQuery);
+}

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

@@ -11,6 +11,7 @@ import com.ym.mec.biz.dal.entity.*;
 import com.ym.mec.biz.dal.enums.*;
 import com.ym.mec.biz.dal.page.*;
 import com.ym.mec.biz.dal.vo.TeacherCloudCourseReportDto;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
 import com.ym.mec.biz.service.*;
 import com.ym.mec.common.constant.CommonConstants;
 import com.ym.mec.common.controller.BaseController;
@@ -180,6 +181,9 @@ public class ExportServiceImpl implements ExportService {
     @Resource
     private HfMerchantConfigService hfMerchantConfigService;
 
+    @Resource
+    private StudentCoursewarePlayRecordService studentCoursewarePlayRecordService;
+
     private static final ExecutorService exportExecutorService = Executors.newFixedThreadPool(10);
 
     @Value("${spring.profiles.active:dev}")
@@ -384,6 +388,24 @@ public class ExportServiceImpl implements ExportService {
         exportManageFuncMap.put(ExportEnum.EXPORT_BALANCED_RELATIONSHIP_STUDENT_INFO, this::exportBalancedRelationshipStudentInfo);
         exportManageFuncMap.put(ExportEnum.EXPORT_BALANCED_RELATIONSHIP_STUDENT_NORMAL_DETAIL, this::exportBalancedRelationshipStudentNormalDetail);
         exportManageFuncMap.put(ExportEnum.EXPORT_BALANCED_RELATIONSHIP_STUDENT_QUIT_DETAIL, this::exportBalancedRelationshipStudentQuitDetail);
+        exportManageFuncMap.put(ExportEnum.VIDEO_PLAY_STAT, this::exportVideoPlayStat);
+        exportManageFuncMap.put(ExportEnum.VIDEO_PLAY_DETAIL_STAT, this::exportVideoPlayDetailStat);
+    }
+
+    private HttpResponseResult<String> exportVideoPlayStat(Map<String, Object> info) {
+        StudentCoursewarePlayRecordWrapper.StatQuery queryInfo = JSONObject.parseObject(JSONObject.toJSONString(info), StudentCoursewarePlayRecordWrapper.StatQuery.class);
+        SysUser sysUser = sysUserService.getUser();
+        ManagerDownload managerDownload = saveManagerDownload(ExportTypeEnum.VIDEO_PLAY_STAT, sysUser.getId());
+        return this.asyncExport(() -> this.initExportInfo(studentCoursewarePlayRecordService.statList(queryInfo), managerDownload, ExportEnum.VIDEO_PLAY_STAT),
+                managerDownload.getName());
+    }
+
+    private HttpResponseResult<String> exportVideoPlayDetailStat(Map<String, Object> info) {
+        StudentCoursewarePlayRecordWrapper.StatQuery queryInfo = JSONObject.parseObject(JSONObject.toJSONString(info), StudentCoursewarePlayRecordWrapper.StatQuery.class);
+        SysUser sysUser = sysUserService.getUser();
+        ManagerDownload managerDownload = saveManagerDownload(ExportTypeEnum.VIDEO_PLAY_DETAIL_STAT, sysUser.getId());
+        return this.asyncExport(() -> this.initExportInfo(studentCoursewarePlayRecordService.statDetailPage(queryInfo).getRecords(), managerDownload, ExportEnum.VIDEO_PLAY_DETAIL_STAT),
+                managerDownload.getName());
     }
 
     private HttpResponseResult<String> exportOaSummaryExpenses(Map<String, Object> info) {

+ 132 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentCoursewarePlayRecordServiceImpl.java

@@ -0,0 +1,132 @@
+package com.ym.mec.biz.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.ym.mec.biz.dal.dao.MusicGroupDao;
+import com.ym.mec.biz.dal.dao.StudentDao;
+import com.ym.mec.biz.dal.dao.StudentRegistrationDao;
+import com.ym.mec.biz.dal.entity.Student;
+import com.ym.mec.biz.dal.entity.StudentRegistration;
+import com.ym.mec.biz.service.StudentServeService;
+import com.ym.mec.common.page.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import lombok.extern.slf4j.Slf4j;
+import com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord;
+import com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper;
+import com.ym.mec.biz.dal.mapper.StudentCoursewarePlayRecordMapper;
+import com.ym.mec.biz.service.StudentCoursewarePlayRecordService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 学生课件播放统计记录
+ * 2024-07-04 14:48:14
+ */
+@Slf4j
+@Service
+public class StudentCoursewarePlayRecordServiceImpl extends ServiceImpl<StudentCoursewarePlayRecordMapper, StudentCoursewarePlayRecord> implements StudentCoursewarePlayRecordService {
+
+    @Autowired
+    private StudentDao studentDao;
+
+    @Autowired
+    private StudentRegistrationDao studentRegistrationDao;
+
+    @Autowired
+    private MusicGroupDao musicGroupDao;
+
+    /**
+     * 查询详情
+     *
+     * @param id 详情ID
+     * @return StudentCoursewarePlayRecord
+     */
+    @Override
+    public StudentCoursewarePlayRecord detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<StudentCoursewarePlayRecord>
+     * @param query StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery
+     * @return IPage<StudentCoursewarePlayRecord>
+     */
+    @Override
+    public IPage<StudentCoursewarePlayRecord> selectPage(IPage<StudentCoursewarePlayRecord> page, StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordQuery query) {
+
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     *
+     * @param studentCoursewarePlayRecord StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord studentCoursewarePlayRecord) {
+
+        return this.save(JSON.parseObject(studentCoursewarePlayRecord.jsonString(), StudentCoursewarePlayRecord.class));
+    }
+
+    /**
+     * 更新
+     *
+     * @param studentCoursewarePlayRecord StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecord studentCoursewarePlayRecord) {
+
+        return this.updateById(JSON.parseObject(studentCoursewarePlayRecord.jsonString(), StudentCoursewarePlayRecord.class));
+    }
+
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void save(StudentCoursewarePlayRecordWrapper.StudentCoursewarePlayRecordSave studentCoursewarePlayRecord) {
+        Integer userId = studentCoursewarePlayRecord.getUserId();
+        Student student = studentDao.get(userId);
+        if (student == null) {
+            return;
+        }
+
+        StudentCoursewarePlayRecord record = new StudentCoursewarePlayRecord();
+        record.setOrganizationId(studentCoursewarePlayRecord.getOrganizationId());
+        record.setUserId(studentCoursewarePlayRecord.getUserId());
+        record.setPlayTime(studentCoursewarePlayRecord.getPlayTime());
+        record.setCreateDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
+        baseMapper.save(record);
+    }
+
+    @Override
+    public List<StudentCoursewarePlayRecordWrapper.StatQueryData> statList(StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        List<StudentCoursewarePlayRecordWrapper.StatQueryData> list = baseMapper.statList(statQuery);
+        list.forEach(n -> n.setAvgPlayTime(n.getAvgPlayTime().setScale(2, RoundingMode.HALF_UP)));
+        return list;
+    }
+
+    @Override
+    public IPage<StudentCoursewarePlayRecordWrapper.StatQueryData> statDetailPage(StudentCoursewarePlayRecordWrapper.StatQuery statQuery) {
+        IPage<StudentCoursewarePlayRecordWrapper.StatQueryData> page = QueryInfo.getPage(statQuery);
+        List<StudentCoursewarePlayRecordWrapper.StatQueryData> statQueryData = baseMapper.statDetailPage(page, statQuery);
+        statQueryData.forEach(n -> n.setAvgPlayTime(n.getAvgPlayTime().setScale(2, RoundingMode.HALF_UP)));
+        page.setRecords(statQueryData);
+        return page;
+    }
+
+
+}

+ 70 - 0
mec-biz/src/main/resources/config/mybatis/StudentCoursewarePlayRecordMapper.xml

@@ -0,0 +1,70 @@
+<?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.mapper.StudentCoursewarePlayRecordMapper">
+    <select id="selectPage" resultType="com.ym.mec.biz.dal.entity.StudentCoursewarePlayRecord">
+        SELECT t.*
+        FROM student_courseware_play_record t
+    </select>
+
+    <insert id="save">
+        INSERT INTO student_courseware_play_record (organization_id_, user_id_, play_time_, create_date_, update_time_, create_time_)
+        VALUES (#{record.organizationId}, #{record.userId}, #{record.playTime}, #{record.createDate}, NOW(), NOW())
+        ON DUPLICATE KEY UPDATE play_time_ = (ifnull(play_time_, 0) + #{record.playTime})
+    </insert>
+
+    <select id="statList" resultType="com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper$StatQueryData">
+        select o.id_                                                                                             as organizationId
+             , o.name_                                                                                           as organizationName
+             , count(distinct s.user_id_)                                                                        as memberNum
+             , (count(distinct s.user_id_) - count(distinct pr.user_id_))                                        as noPlayNum
+             , count(distinct if(10 * 60 >= pr.play_time_, pr.user_id_, null))                                   as playTimeLess10
+             , count(distinct if(pr.play_time_ > 10 * 60 and 60 * 60 >= pr.play_time_, pr.user_id_, null))       as playTimeLess60
+             , count(distinct if(pr.play_time_ > 60 * 60 and 120 * 60 >= pr.play_time_, pr.user_id_, null))      as playTimeLess120
+             , count(distinct if(pr.play_time_ > 120 * 60 and 240 * 60 >= pr.play_time_, pr.user_id_, null))     as playTimeLess240
+             , count(distinct if(pr.play_time_ > 240 * 60, pr.user_id_, null))                                   as playTimeRather240
+             , if(count(distinct pr.user_id_) = 0, 0, (sum(pr.play_time_) / (count(distinct pr.user_id_) * 60))) as avgPlayTime
+        from organization o
+                 left join sys_user su on o.id_ = su.organ_id_
+                 left join student s on s.user_id_ = su.id_
+                 left join (select user_id_, sum(play_time_) play_time_
+                            from student_courseware_play_record
+                            where create_time_ > #{statQuery.startTime}
+                              and #{statQuery.endTime} > create_time_
+                            group by user_id_) pr on s.user_id_ = pr.user_id_
+        <where>
+            s.membership_end_time_ >= now()
+            <if test="statQuery.organizationId != null and statQuery.organizationId.trim() !=''">
+                and find_in_set(o.id_,#{statQuery.organizationId})
+            </if>
+        </where>
+        group by o.id_
+        order by ${statQuery.sortBy}
+    </select>
+    <select id="statDetailPage" resultType="com.ym.mec.biz.dal.wrapper.StudentCoursewarePlayRecordWrapper$StatQueryData">
+        select o.id_                                                                                             as organizationId
+             , o.name_                                                                                           as organizationName
+             , su2.username_                                                                                     as teacherName
+             , count(distinct s.user_id_)                                                                        as memberNum
+             , (count(distinct s.user_id_) - count(distinct pr.user_id_))                                        as noPlayNum
+             , count(distinct if(10 * 60 >= pr.play_time_, pr.user_id_, null))                                   as playTimeLess10
+             , count(distinct if(pr.play_time_ > 10 * 60 and 60 * 60 >= pr.play_time_, pr.user_id_, null))       as playTimeLess60
+             , count(distinct if(pr.play_time_ > 60 * 60 and 120 * 60 >= pr.play_time_, pr.user_id_, null))      as playTimeLess120
+             , count(distinct if(pr.play_time_ > 120 * 60 and 240 * 60 >= pr.play_time_, pr.user_id_, null))     as playTimeLess240
+             , count(distinct if(pr.play_time_ > 240 * 60, pr.user_id_, null))                                   as playTimeRather240
+             , if(count(distinct pr.user_id_) = 0, 0, (sum(pr.play_time_) / (count(distinct pr.user_id_) * 60))) as avgPlayTime
+        from organization o
+                 left join sys_user su on su.organ_id_ = o.id_
+                 left join student s on s.user_id_ = su.id_
+                 left join student_teacher_mapper stm on stm.student_id_ = s.user_id_
+                 left join sys_user su2 on su2.id_ = stm.teacher_id_
+                 left join (select user_id_, sum(play_time_) play_time_
+                            from student_courseware_play_record
+                            where create_time_ > #{statQuery.startTime}
+                              and #{statQuery.endTime} > create_time_
+                            group by user_id_) pr on s.user_id_ = pr.user_id_
+        where o.id_ = #{statQuery.organizationId}
+          and s.membership_end_time_ >= now() and stm.id_ is not null
+        group by stm.teacher_id_
+        order by ${statQuery.sortBy}
+    </select>
+</mapper>