新增:教学管理查看使用时长

This commit is contained in:
joylink_zhangsai 2021-06-07 16:11:55 +08:00
parent 179b880409
commit 49f6b357d3
19 changed files with 453 additions and 69 deletions

3
sql/20210607-thesai.sql Normal file
View File

@ -0,0 +1,3 @@
ALTER TABLE `user_simulation_stats`
ADD COLUMN `end_time` datetime NOT NULL DEFAULT '1970-01-01 01:01:01' ON UPDATE CURRENT_TIMESTAMP AFTER `fake`;

View File

@ -19,6 +19,7 @@ import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.LessonVO; import club.joylink.rtss.vo.client.LessonVO;
import club.joylink.rtss.vo.client.Node; import club.joylink.rtss.vo.client.Node;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.org.*; import club.joylink.rtss.vo.client.org.*;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -290,49 +291,55 @@ public class OrgController {
return iOrgService.adminQueryOrgTree(orgId); return iOrgService.adminQueryOrgTree(orgId);
} }
@Transactional @ApiOperation("获取学生实训使用时长")
@ApiOperation("数据处理接口,用后即删") @GetMapping("/usage/students")
@PutMapping("/data/data") public List<StudentsUsageStatisticsVO> statisticUsage(@Validated UsageQueryVO queryVO) {
public void data() { return iOrgUserService.statisticUsage(queryVO);
OrgUserExample orgUserExample = new OrgUserExample();
orgUserExample.createCriteria().andRoleEqualTo(BusinessConsts.OrgRole.Student.name());
List<OrgUser> ous = orgUserDAO.selectByExample(orgUserExample);
Set<Long> orgIdSet = new HashSet<>();
Map<Long, Set<Long>> userId_orgIdSet_map = new HashMap<>();
ous.forEach(ou -> {
orgIdSet.add(ou.getOrgId());
Set<Long> userOrgIdSet = userId_orgIdSet_map.computeIfAbsent(ou.getUserId(), k -> new HashSet<>());
userOrgIdSet.add(ou.getOrgId());
});
List<Org> orgList = iOrgService.findEntities(new ArrayList<>(orgIdSet), null);
Map<Long, Long> orgId_rootId_map = orgList.stream().collect(Collectors.toMap(Org::getId, Org::getRootId));
Map<Long, Org> topOrgMap = iOrgService.findEntities(new ArrayList<>(orgId_rootId_map.values()), null)
.stream().collect(Collectors.toMap(Org::getId, Function.identity()));
List<SysUser> users = iSysUserService.findEntities(new ArrayList<>(userId_orgIdSet_map.keySet()), null);
Set<Long> nonRootOrgIds = new HashSet<>();
users.forEach(user -> {
Set<Long> userOrgIdSet = userId_orgIdSet_map.get(user.getId());
String orgCode = null;
Long rootId = null;
for (Long orgId : userOrgIdSet) {
rootId = orgId_rootId_map.get(orgId);
if (rootId == null) {
nonRootOrgIds.add(rootId);
} else {
Org org = topOrgMap.get(rootId);
if (orgCode == null) {
orgCode = org.getCode();
} else {
BusinessExceptionAssertEnum.DATA_ERROR.assertEquals(orgCode, org.getCode(), userOrgIdSet.toString());
}
}
}
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(orgCode, user.getId() + "无所属顶级组织");
user.setAccount(user.getAccount().substring(0, user.getAccount().indexOf(orgCode)));
user.setOrgId(rootId);
sysUserDAO.updateByPrimaryKey(user);
});
System.out.println(nonRootOrgIds.toString());
} }
// @Transactional
// @ApiOperation("数据处理接口,用后即删")
// @PutMapping("/data/data")
// public void data() {
// OrgUserExample orgUserExample = new OrgUserExample();
// orgUserExample.createCriteria().andRoleEqualTo(BusinessConsts.OrgRole.Student.name());
// List<OrgUser> ous = orgUserDAO.selectByExample(orgUserExample);
// Set<Long> orgIdSet = new HashSet<>();
// Map<Long, Set<Long>> userId_orgIdSet_map = new HashMap<>();
// ous.forEach(ou -> {
// orgIdSet.add(ou.getOrgId());
// Set<Long> userOrgIdSet = userId_orgIdSet_map.computeIfAbsent(ou.getUserId(), k -> new HashSet<>());
// userOrgIdSet.add(ou.getOrgId());
// });
// List<Org> orgList = iOrgService.findEntities(new ArrayList<>(orgIdSet), null);
// Map<Long, Long> orgId_rootId_map = orgList.stream().collect(Collectors.toMap(Org::getId, Org::getRootId));
// Map<Long, Org> topOrgMap = iOrgService.findEntities(new ArrayList<>(orgId_rootId_map.values()), null)
// .stream().collect(Collectors.toMap(Org::getId, Function.identity()));
// List<SysUser> users = iSysUserService.findEntities(new ArrayList<>(userId_orgIdSet_map.keySet()), null);
// Set<Long> nonRootOrgIds = new HashSet<>();
// users.forEach(user -> {
// Set<Long> userOrgIdSet = userId_orgIdSet_map.get(user.getId());
// String orgCode = null;
// Long rootId = null;
// for (Long orgId : userOrgIdSet) {
// rootId = orgId_rootId_map.get(orgId);
// if (rootId == null) {
// nonRootOrgIds.add(rootId);
// } else {
// Org org = topOrgMap.get(rootId);
// if (orgCode == null) {
// orgCode = org.getCode();
// } else {
// BusinessExceptionAssertEnum.DATA_ERROR.assertEquals(orgCode, org.getCode(), userOrgIdSet.toString());
// }
// }
// }
// BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(orgCode, user.getId() + "无所属顶级组织");
// user.setAccount(user.getAccount().substring(0, user.getAccount().indexOf(orgCode)));
// user.setOrgId(rootId);
// sysUserDAO.updateByPrimaryKey(user);
// });
// System.out.println(nonRootOrgIds.toString());
// }
} }

View File

@ -5,11 +5,13 @@ import club.joylink.rtss.entity.UserSimulationStatsExample;
import club.joylink.rtss.vo.client.UserRankStatsVO; import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.UserSimulationStatsListVO; import club.joylink.rtss.vo.client.UserSimulationStatsListVO;
import club.joylink.rtss.vo.client.UserSimulationStatsQueryVO; import club.joylink.rtss.vo.client.UserSimulationStatsQueryVO;
import club.joylink.rtss.vo.client.org.StudentsUsageStatisticsVO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@ -108,4 +110,6 @@ public interface UserSimulationStatsDAO extends MyBatisBaseDao<UserSimulationSta
"where " + "where " +
"map_prd_id=#{prdId} ") "map_prd_id=#{prdId} ")
void fillPrdType(Long prdId, String prdType); void fillPrdType(Long prdId, String prdType);
List<StudentsUsageStatisticsVO> queryUsage(long mapId, List<Long> userIds, LocalDateTime startTime, LocalDateTime endTime);
} }

View File

@ -75,6 +75,31 @@ public interface UserTrainingStatsMapper {
"</script>") "</script>")
UserRankStatsVO selectRank(LocalDateTime startTime, LocalDateTime endTime, List<Long> lessonIds, Long userId); UserRankStatsVO selectRank(LocalDateTime startTime, LocalDateTime endTime, List<Long> lessonIds, Long userId);
@Select("<script>" +
"SELECT SUM(ut.duration) AS duration, " +
// "u.name AS username, " +
"ut.user_id AS userId " +
"FROM user_training_stats ut " +
// "LEFT JOIN sys_user u ON u.id = ut.user_id " +
"WHERE 1 = 1" +
"<if test=\"startTime != null\">" +
" AND ut.finish_time &gt;= #{startTime}" +
"</if>" +
"<if test=\"endTime != null\">" +
" AND ut.finish_time &lt;= #{endTime}" +
"</if>" +
"AND ut.lesson_id IN" +
"<foreach collection='lessonIds' item='lessonId' open='(' separator=',' close=')'>" +
" #{lessonId}" +
"</foreach>" +
"AND ut.user_id IN " +
"<foreach collection='userIds' item='userId' open='(' separator=',' close=')'>" +
" #{userId}" +
"</foreach>" +
"GROUP BY ut.user_id" +
"</script>")
List<UserRankStatsVO> selectUsage(LocalDateTime startTime, LocalDateTime endTime, List<Long> lessonIds, List<Long> userIds);
@Select("<script>" + @Select("<script>" +
"SELECT dd.name AS statsProjectName, " + "SELECT dd.name AS statsProjectName, " +
"SUM(ut.duration) AS duration, " + "SUM(ut.duration) AS duration, " +

View File

@ -1,10 +1,11 @@
package club.joylink.rtss.entity; package club.joylink.rtss.entity;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
* user_simulation_stats
* @author * @author
* 用户仿真统计
*/ */
public class UserSimulationStats implements Serializable { public class UserSimulationStats implements Serializable {
private Long id; private Long id;
@ -19,6 +20,11 @@ public class UserSimulationStats implements Serializable {
*/ */
private Long mapId; private Long mapId;
/**
* 产品编码
*/
private Long mapPrdId;
/** /**
* 产品类型 * 产品类型
*/ */
@ -39,6 +45,8 @@ public class UserSimulationStats implements Serializable {
*/ */
private Boolean fake; private Boolean fake;
private LocalDateTime endTime;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public Long getId() { public Long getId() {
@ -65,6 +73,14 @@ public class UserSimulationStats implements Serializable {
this.mapId = mapId; this.mapId = mapId;
} }
public Long getMapPrdId() {
return mapPrdId;
}
public void setMapPrdId(Long mapPrdId) {
this.mapPrdId = mapPrdId;
}
public String getPrdType() { public String getPrdType() {
return prdType; return prdType;
} }
@ -97,6 +113,14 @@ public class UserSimulationStats implements Serializable {
this.fake = fake; this.fake = fake;
} }
public LocalDateTime getEndTime() {
return endTime;
}
public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
}
@Override @Override
public boolean equals(Object that) { public boolean equals(Object that) {
if (this == that) { if (this == that) {
@ -112,10 +136,12 @@ public class UserSimulationStats implements Serializable {
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId()))
&& (this.getMapId() == null ? other.getMapId() == null : this.getMapId().equals(other.getMapId())) && (this.getMapId() == null ? other.getMapId() == null : this.getMapId().equals(other.getMapId()))
&& (this.getMapPrdId() == null ? other.getMapPrdId() == null : this.getMapPrdId().equals(other.getMapPrdId()))
&& (this.getPrdType() == null ? other.getPrdType() == null : this.getPrdType().equals(other.getPrdType())) && (this.getPrdType() == null ? other.getPrdType() == null : this.getPrdType().equals(other.getPrdType()))
&& (this.getDuration() == null ? other.getDuration() == null : this.getDuration().equals(other.getDuration())) && (this.getDuration() == null ? other.getDuration() == null : this.getDuration().equals(other.getDuration()))
&& (this.getRole() == null ? other.getRole() == null : this.getRole().equals(other.getRole())) && (this.getRole() == null ? other.getRole() == null : this.getRole().equals(other.getRole()))
&& (this.getFake() == null ? other.getFake() == null : this.getFake().equals(other.getFake())); && (this.getFake() == null ? other.getFake() == null : this.getFake().equals(other.getFake()))
&& (this.getEndTime() == null ? other.getEndTime() == null : this.getEndTime().equals(other.getEndTime()));
} }
@Override @Override
@ -125,10 +151,12 @@ public class UserSimulationStats implements Serializable {
result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode());
result = prime * result + ((getMapId() == null) ? 0 : getMapId().hashCode()); result = prime * result + ((getMapId() == null) ? 0 : getMapId().hashCode());
result = prime * result + ((getMapPrdId() == null) ? 0 : getMapPrdId().hashCode());
result = prime * result + ((getPrdType() == null) ? 0 : getPrdType().hashCode()); result = prime * result + ((getPrdType() == null) ? 0 : getPrdType().hashCode());
result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode()); result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode());
result = prime * result + ((getRole() == null) ? 0 : getRole().hashCode()); result = prime * result + ((getRole() == null) ? 0 : getRole().hashCode());
result = prime * result + ((getFake() == null) ? 0 : getFake().hashCode()); result = prime * result + ((getFake() == null) ? 0 : getFake().hashCode());
result = prime * result + ((getEndTime() == null) ? 0 : getEndTime().hashCode());
return result; return result;
} }
@ -141,10 +169,12 @@ public class UserSimulationStats implements Serializable {
sb.append(", id=").append(id); sb.append(", id=").append(id);
sb.append(", userId=").append(userId); sb.append(", userId=").append(userId);
sb.append(", mapId=").append(mapId); sb.append(", mapId=").append(mapId);
sb.append(", mapPrdId=").append(mapPrdId);
sb.append(", prdType=").append(prdType); sb.append(", prdType=").append(prdType);
sb.append(", duration=").append(duration); sb.append(", duration=").append(duration);
sb.append(", role=").append(role); sb.append(", role=").append(role);
sb.append(", fake=").append(fake); sb.append(", fake=").append(fake);
sb.append(", endTime=").append(endTime);
sb.append(", serialVersionUID=").append(serialVersionUID); sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.entity; package club.joylink.rtss.entity;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -304,6 +305,66 @@ public class UserSimulationStatsExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andMapPrdIdIsNull() {
addCriterion("map_prd_id is null");
return (Criteria) this;
}
public Criteria andMapPrdIdIsNotNull() {
addCriterion("map_prd_id is not null");
return (Criteria) this;
}
public Criteria andMapPrdIdEqualTo(Long value) {
addCriterion("map_prd_id =", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdNotEqualTo(Long value) {
addCriterion("map_prd_id <>", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdGreaterThan(Long value) {
addCriterion("map_prd_id >", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdGreaterThanOrEqualTo(Long value) {
addCriterion("map_prd_id >=", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdLessThan(Long value) {
addCriterion("map_prd_id <", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdLessThanOrEqualTo(Long value) {
addCriterion("map_prd_id <=", value, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdIn(List<Long> values) {
addCriterion("map_prd_id in", values, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdNotIn(List<Long> values) {
addCriterion("map_prd_id not in", values, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdBetween(Long value1, Long value2) {
addCriterion("map_prd_id between", value1, value2, "mapPrdId");
return (Criteria) this;
}
public Criteria andMapPrdIdNotBetween(Long value1, Long value2) {
addCriterion("map_prd_id not between", value1, value2, "mapPrdId");
return (Criteria) this;
}
public Criteria andPrdTypeIsNull() { public Criteria andPrdTypeIsNull() {
addCriterion("prd_type is null"); addCriterion("prd_type is null");
return (Criteria) this; return (Criteria) this;
@ -563,6 +624,66 @@ public class UserSimulationStatsExample {
addCriterion("fake not between", value1, value2, "fake"); addCriterion("fake not between", value1, value2, "fake");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andEndTimeIsNull() {
addCriterion("end_time is null");
return (Criteria) this;
}
public Criteria andEndTimeIsNotNull() {
addCriterion("end_time is not null");
return (Criteria) this;
}
public Criteria andEndTimeEqualTo(LocalDateTime value) {
addCriterion("end_time =", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeNotEqualTo(LocalDateTime value) {
addCriterion("end_time <>", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeGreaterThan(LocalDateTime value) {
addCriterion("end_time >", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeGreaterThanOrEqualTo(LocalDateTime value) {
addCriterion("end_time >=", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeLessThan(LocalDateTime value) {
addCriterion("end_time <", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeLessThanOrEqualTo(LocalDateTime value) {
addCriterion("end_time <=", value, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeIn(List<LocalDateTime> values) {
addCriterion("end_time in", values, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeNotIn(List<LocalDateTime> values) {
addCriterion("end_time not in", values, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeBetween(LocalDateTime value1, LocalDateTime value2) {
addCriterion("end_time between", value1, value2, "endTime");
return (Criteria) this;
}
public Criteria andEndTimeNotBetween(LocalDateTime value1, LocalDateTime value2) {
addCriterion("end_time not between", value1, value2, "endTime");
return (Criteria) this;
}
} }
/** /**

View File

@ -168,4 +168,6 @@ public interface ILessonService {
* 按条件查询非默认课程 * 按条件查询非默认课程
*/ */
List<LessonVO> queryNonDefaultLessons(Long creatorId, Project project, String status); List<LessonVO> queryNonDefaultLessons(Long creatorId, Project project, String status);
List<LsLesson> findLessonEntities(long mapId);
} }

View File

@ -5,6 +5,7 @@ import club.joylink.rtss.vo.client.UsageTotalStatsVO;
import club.joylink.rtss.vo.client.UserRankStatsVO; import club.joylink.rtss.vo.client.UserRankStatsVO;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
public interface IUserUsageStatsService { public interface IUserUsageStatsService {
@ -79,4 +80,6 @@ public interface IUserUsageStatsService {
* @return * @return
*/ */
List<UsageTotalStatsVO> totalDuration(boolean filter); List<UsageTotalStatsVO> totalDuration(boolean filter);
List<UserRankStatsVO> queryTrainingUsageGroupByUser(LocalDateTime start, LocalDateTime end, List<Long> lessonIds, List<Long> userIds);
} }

View File

@ -853,7 +853,8 @@ public class LessonService implements ILessonService {
return new LessonVO(lessonList.get(0)); return new LessonVO(lessonList.get(0));
} }
private List<LsLesson> findLessonEntities(@NonNull Long mapId) { @Override
public List<LsLesson> findLessonEntities(long mapId) {
LsLessonExample example = new LsLessonExample(); LsLessonExample example = new LsLessonExample();
example.createCriteria().andMapIdEqualTo(mapId); example.createCriteria().andMapIdEqualTo(mapId);
return lessonDAO.selectByExample(example); return lessonDAO.selectByExample(example);

View File

@ -153,6 +153,11 @@ public class UserUsageStatsService implements IUserUsageStatsService {
return usageTotalStatsVOS; return usageTotalStatsVOS;
} }
@Override
public List<UserRankStatsVO> queryTrainingUsageGroupByUser(LocalDateTime start, LocalDateTime end, List<Long> lessonIds, List<Long> userIds) {
return this.userTrainingStatsMapper.selectUsage(start, end, lessonIds, userIds);
}
public static void addMyRank(List<UserRankStatsVO> rankList, UserVO userVO) { public static void addMyRank(List<UserRankStatsVO> rankList, UserVO userVO) {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertCollectionNotEmpty(rankList); BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertCollectionNotEmpty(rankList);
for(int i = 0; i < rankList.size(); i++) { for(int i = 0; i < rankList.size(); i++) {

View File

@ -7,10 +7,8 @@ import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.ExamDefinitionVO; import club.joylink.rtss.vo.client.ExamDefinitionVO;
import club.joylink.rtss.vo.client.Node; import club.joylink.rtss.vo.client.Node;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.org.CompanyVO; import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.org.DepartmentVO; import club.joylink.rtss.vo.client.org.*;
import club.joylink.rtss.vo.client.org.NonTopOrgCreateVO;
import club.joylink.rtss.vo.client.org.OrgQueryVO;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;

View File

@ -6,6 +6,7 @@ import club.joylink.rtss.entity.OrgUser;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.LessonVO; import club.joylink.rtss.vo.client.LessonVO;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.org.*; import club.joylink.rtss.vo.client.org.*;
import java.util.List; import java.util.List;
@ -75,4 +76,6 @@ public interface IOrgUserService {
List<OrgUser> findEntitiesByUserId(long userId, BusinessConsts.OrgRole role); List<OrgUser> findEntitiesByUserId(long userId, BusinessConsts.OrgRole role);
void userBindCompanyManager(UserVO userVO, Long topOrgId); void userBindCompanyManager(UserVO userVO, Long topOrgId);
List<StudentsUsageStatisticsVO> statisticUsage(UsageQueryVO queryVO);
} }

View File

@ -6,11 +6,13 @@ import club.joylink.rtss.dao.OrgDAO;
import club.joylink.rtss.entity.*; import club.joylink.rtss.entity.*;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.ISysUserService; import club.joylink.rtss.services.ISysUserService;
import club.joylink.rtss.services.IUserUsageStatsService;
import club.joylink.rtss.vo.LoginUserInfoVO; import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.ExamDefinitionVO; import club.joylink.rtss.vo.client.ExamDefinitionVO;
import club.joylink.rtss.vo.client.Node; import club.joylink.rtss.vo.client.Node;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.org.*; import club.joylink.rtss.vo.client.org.*;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;

View File

@ -9,10 +9,13 @@ import club.joylink.rtss.entity.*;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.ILessonService; import club.joylink.rtss.services.ILessonService;
import club.joylink.rtss.services.ISysUserService; import club.joylink.rtss.services.ISysUserService;
import club.joylink.rtss.services.IUserUsageStatsService;
import club.joylink.rtss.services.completition.IRaceQuestionsRuleService; import club.joylink.rtss.services.completition.IRaceQuestionsRuleService;
import club.joylink.rtss.services.user.IUserSimulationStatService;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.LessonVO; import club.joylink.rtss.vo.client.LessonVO;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.UserRankStatsVO;
import club.joylink.rtss.vo.client.org.*; import club.joylink.rtss.vo.client.org.*;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
@ -25,6 +28,7 @@ import org.springframework.util.StringUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -47,11 +51,17 @@ public class OrgUserService implements IOrgUserService {
@Autowired @Autowired
private OrgExamDAO orgExamDAO; private OrgExamDAO orgExamDAO;
@Autowired @Autowired
private ILessonService lessonService; private ILessonService iLessonService;
@Autowired @Autowired
private IOrgService iOrgService; private IOrgService iOrgService;
@Autowired
private IUserUsageStatsService iUserUsageStatsService;
@Autowired
private IUserSimulationStatService iUserSimulationStatService;
@Override @Override
public CompanyVO userScanCodeBindCompanyManager(Long userId, Long companyId) { public CompanyVO userScanCodeBindCompanyManager(Long userId, Long companyId) {
@ -268,7 +278,7 @@ public class OrgUserService implements IOrgUserService {
public List<LessonVO> getLessonsByDepart(Long departId) { public List<LessonVO> getLessonsByDepart(Long departId) {
List<Long> lessonIds = getDepartLessonRefs(departId).stream().map(OrgLesson::getLessonId).collect(Collectors.toList()); List<Long> lessonIds = getDepartLessonRefs(departId).stream().map(OrgLesson::getLessonId).collect(Collectors.toList());
if (CollectionUtils.isEmpty(lessonIds)) return new ArrayList<>(); if (CollectionUtils.isEmpty(lessonIds)) return new ArrayList<>();
return lessonService.getValidLesson(null, lessonIds, null); return iLessonService.getValidLesson(null, lessonIds, null);
} }
@Override @Override
@ -398,7 +408,33 @@ public class OrgUserService implements IOrgUserService {
userVO.setOrgInfo(topOrg, true); userVO.setOrgInfo(topOrg, true);
} }
@Override
public List<StudentsUsageStatisticsVO> statisticUsage(UsageQueryVO queryVO) {
List<OrgUser> students = this.findEntitiesByOrgId(queryVO.getClsId(), BusinessConsts.OrgRole.Student);
if (CollectionUtils.isEmpty(students)) {
return List.of();
}
List<Long> userIds = students.stream().map(OrgUser::getUserId).collect(Collectors.toList());
List<StudentsUsageStatisticsVO> vos = StudentsUsageStatisticsVO.buildList(iSysUserService.findEntities(userIds, "id"));
Map<Long, StudentsUsageStatisticsVO> voMap = vos.stream().collect(Collectors.toMap(StudentsUsageStatisticsVO::getUserId, Function.identity()));
List<Long> lessonIds = iLessonService.findLessonEntities(queryVO.getMapId())
.stream().map(LsLesson::getId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(lessonIds)) {
List<UserRankStatsVO> trainingUsage =
iUserUsageStatsService.queryTrainingUsageGroupByUser(queryVO.getStartTime(), queryVO.getEndTime(), lessonIds, userIds);
for (UserRankStatsVO usage : trainingUsage) {
StudentsUsageStatisticsVO vo = voMap.get(usage.getUserId());
vo.setTrainingDuration(usage.getDuration());
}
}
List<StudentsUsageStatisticsVO> simulationUsage =
iUserSimulationStatService.querySimulationUsage(queryVO.getMapId(), userIds, queryVO.getStartTime(), queryVO.getEndTime());
for (StudentsUsageStatisticsVO usage : simulationUsage) {
StudentsUsageStatisticsVO vo = voMap.get(usage.getUserId());
vo.setSimulationDuration(usage.getSimulationDuration());
}
return vos;
}
/** /**

View File

@ -2,7 +2,9 @@ package club.joylink.rtss.services.user;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.*; import club.joylink.rtss.vo.client.*;
import club.joylink.rtss.vo.client.org.StudentsUsageStatisticsVO;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
public interface IUserSimulationStatService { public interface IUserSimulationStatService {
@ -88,4 +90,6 @@ public interface IUserSimulationStatService {
* @param filter * @param filter
*/ */
List<UsageTotalStatsVO> totalDuration(boolean filter, List<Long> userIds); List<UsageTotalStatsVO> totalDuration(boolean filter, List<Long> userIds);
List<StudentsUsageStatisticsVO> querySimulationUsage(long mapId, List<Long> userIds, LocalDateTime startTime, LocalDateTime endTime);
} }

View File

@ -9,11 +9,13 @@ import club.joylink.rtss.services.IMapService;
import club.joylink.rtss.services.UserUsageStatsService; import club.joylink.rtss.services.UserUsageStatsService;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.*; import club.joylink.rtss.vo.client.*;
import club.joylink.rtss.vo.client.org.StudentsUsageStatisticsVO;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -32,6 +34,7 @@ public class UserSimulationStatService implements IUserSimulationStatService {
public void addUserSimulationStats(UserSimulationStatsVO statsVO, UserVO userVO) { public void addUserSimulationStats(UserSimulationStatsVO statsVO, UserVO userVO) {
UserSimulationStats userSimulationStats = statsVO.convert2DB(); UserSimulationStats userSimulationStats = statsVO.convert2DB();
userSimulationStats.setFake(true); userSimulationStats.setFake(true);
userSimulationStats.setEndTime(LocalDateTime.now());
this.userSimulationStatsDAO.insertSelective(userSimulationStats); this.userSimulationStatsDAO.insertSelective(userSimulationStats);
} }
@ -44,6 +47,7 @@ public class UserSimulationStatService implements IUserSimulationStatService {
userSimulationStats.setDuration(duration); userSimulationStats.setDuration(duration);
userSimulationStats.setFake(false); userSimulationStats.setFake(false);
userSimulationStats.setRole(role); userSimulationStats.setRole(role);
userSimulationStats.setEndTime(LocalDateTime.now());
this.userSimulationStatsDAO.insertSelective(userSimulationStats); this.userSimulationStatsDAO.insertSelective(userSimulationStats);
} }
@ -123,4 +127,9 @@ public class UserSimulationStatService implements IUserSimulationStatService {
// 实训 // 实训
return usageTotalStatsVOList; return usageTotalStatsVOList;
} }
@Override
public List<StudentsUsageStatisticsVO> querySimulationUsage(long mapId, List<Long> userIds, LocalDateTime startTime, LocalDateTime endTime) {
return userSimulationStatsDAO.queryUsage(mapId, userIds, startTime, endTime);
}
} }

View File

@ -0,0 +1,50 @@
package club.joylink.rtss.vo.client.org;
import club.joylink.rtss.entity.OrgUser;
import club.joylink.rtss.entity.SysUser;
import club.joylink.rtss.vo.client.UserRankStatsVO;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 学生的实训/仿真使用时长统计
*/
@Getter
@Setter
@NoArgsConstructor
public class StudentsUsageStatisticsVO {
@JsonSerialize(using = ToStringSerializer.class)
private Long userId;
private String account;
private String userName;
@Setter
private Long trainingDuration;
@Setter
private Long simulationDuration;
public StudentsUsageStatisticsVO(SysUser user) {
this.userId = user.getId();
this.account = user.getAccount();
this.userName = user.getName();
}
public static List<StudentsUsageStatisticsVO> buildList(Collection<SysUser> users) {
if (CollectionUtils.isEmpty(users))
return Collections.emptyList();
return users.stream().map(StudentsUsageStatisticsVO::new).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,27 @@
package club.joylink.rtss.vo.client.org;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Getter
@Setter
@NoArgsConstructor
public class UsageQueryVO {
@NotNull(message = "班级id不能为空")
private Long clsId;
@NotNull(message = "地图id不能为空")
private Long mapId;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime startTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
}

View File

@ -5,10 +5,12 @@
<id column="id" jdbcType="BIGINT" property="id" /> <id column="id" jdbcType="BIGINT" property="id" />
<result column="user_id" jdbcType="BIGINT" property="userId" /> <result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="map_id" jdbcType="BIGINT" property="mapId" /> <result column="map_id" jdbcType="BIGINT" property="mapId" />
<result column="map_prd_id" jdbcType="BIGINT" property="mapPrdId" />
<result column="prd_type" jdbcType="VARCHAR" property="prdType" /> <result column="prd_type" jdbcType="VARCHAR" property="prdType" />
<result column="duration" jdbcType="INTEGER" property="duration" /> <result column="duration" jdbcType="INTEGER" property="duration" />
<result column="role" jdbcType="VARCHAR" property="role" /> <result column="role" jdbcType="VARCHAR" property="role" />
<result column="fake" jdbcType="BIT" property="fake" /> <result column="fake" jdbcType="TINYINT" property="fake" />
<result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -69,7 +71,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, user_id, map_id, prd_type, duration, `role`, fake id, user_id, map_id, map_prd_id, prd_type, duration, `role`, fake, end_time
</sql> </sql>
<select id="selectByExample" parameterType="club.joylink.rtss.entity.UserSimulationStatsExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="club.joylink.rtss.entity.UserSimulationStatsExample" resultMap="BaseResultMap">
select select
@ -110,10 +112,12 @@
</if> </if>
</delete> </delete>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.UserSimulationStats" useGeneratedKeys="true"> <insert id="insert" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.UserSimulationStats" useGeneratedKeys="true">
insert into user_simulation_stats (user_id, map_id, prd_type, insert into user_simulation_stats (user_id, map_id, map_prd_id,
duration, `role`, fake) prd_type, duration, `role`,
values (#{userId,jdbcType=BIGINT}, #{mapId,jdbcType=BIGINT}, #{prdType,jdbcType=VARCHAR}, fake, end_time)
#{duration,jdbcType=INTEGER}, #{role,jdbcType=VARCHAR}, #{fake,jdbcType=BIT}) values (#{userId,jdbcType=BIGINT}, #{mapId,jdbcType=BIGINT}, #{mapPrdId,jdbcType=BIGINT},
#{prdType,jdbcType=VARCHAR}, #{duration,jdbcType=INTEGER}, #{role,jdbcType=VARCHAR},
#{fake,jdbcType=TINYINT}, #{endTime,jdbcType=TIMESTAMP})
</insert> </insert>
<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.UserSimulationStats" useGeneratedKeys="true"> <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.UserSimulationStats" useGeneratedKeys="true">
insert into user_simulation_stats insert into user_simulation_stats
@ -124,6 +128,9 @@
<if test="mapId != null"> <if test="mapId != null">
map_id, map_id,
</if> </if>
<if test="mapPrdId != null">
map_prd_id,
</if>
<if test="prdType != null"> <if test="prdType != null">
prd_type, prd_type,
</if> </if>
@ -136,6 +143,9 @@
<if test="fake != null"> <if test="fake != null">
fake, fake,
</if> </if>
<if test="endTime != null">
end_time,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null"> <if test="userId != null">
@ -144,6 +154,9 @@
<if test="mapId != null"> <if test="mapId != null">
#{mapId,jdbcType=BIGINT}, #{mapId,jdbcType=BIGINT},
</if> </if>
<if test="mapPrdId != null">
#{mapPrdId,jdbcType=BIGINT},
</if>
<if test="prdType != null"> <if test="prdType != null">
#{prdType,jdbcType=VARCHAR}, #{prdType,jdbcType=VARCHAR},
</if> </if>
@ -154,7 +167,10 @@
#{role,jdbcType=VARCHAR}, #{role,jdbcType=VARCHAR},
</if> </if>
<if test="fake != null"> <if test="fake != null">
#{fake,jdbcType=BIT}, #{fake,jdbcType=TINYINT},
</if>
<if test="endTime != null">
#{endTime,jdbcType=TIMESTAMP},
</if> </if>
</trim> </trim>
</insert> </insert>
@ -176,6 +192,9 @@
<if test="record.mapId != null"> <if test="record.mapId != null">
map_id = #{record.mapId,jdbcType=BIGINT}, map_id = #{record.mapId,jdbcType=BIGINT},
</if> </if>
<if test="record.mapPrdId != null">
map_prd_id = #{record.mapPrdId,jdbcType=BIGINT},
</if>
<if test="record.prdType != null"> <if test="record.prdType != null">
prd_type = #{record.prdType,jdbcType=VARCHAR}, prd_type = #{record.prdType,jdbcType=VARCHAR},
</if> </if>
@ -186,7 +205,10 @@
`role` = #{record.role,jdbcType=VARCHAR}, `role` = #{record.role,jdbcType=VARCHAR},
</if> </if>
<if test="record.fake != null"> <if test="record.fake != null">
fake = #{record.fake,jdbcType=BIT}, fake = #{record.fake,jdbcType=TINYINT},
</if>
<if test="record.endTime != null">
end_time = #{record.endTime,jdbcType=TIMESTAMP},
</if> </if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">
@ -198,10 +220,12 @@
set id = #{record.id,jdbcType=BIGINT}, set id = #{record.id,jdbcType=BIGINT},
user_id = #{record.userId,jdbcType=BIGINT}, user_id = #{record.userId,jdbcType=BIGINT},
map_id = #{record.mapId,jdbcType=BIGINT}, map_id = #{record.mapId,jdbcType=BIGINT},
map_prd_id = #{record.mapPrdId,jdbcType=BIGINT},
prd_type = #{record.prdType,jdbcType=VARCHAR}, prd_type = #{record.prdType,jdbcType=VARCHAR},
duration = #{record.duration,jdbcType=INTEGER}, duration = #{record.duration,jdbcType=INTEGER},
`role` = #{record.role,jdbcType=VARCHAR}, `role` = #{record.role,jdbcType=VARCHAR},
fake = #{record.fake,jdbcType=BIT} fake = #{record.fake,jdbcType=TINYINT},
end_time = #{record.endTime,jdbcType=TIMESTAMP}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -215,6 +239,9 @@
<if test="mapId != null"> <if test="mapId != null">
map_id = #{mapId,jdbcType=BIGINT}, map_id = #{mapId,jdbcType=BIGINT},
</if> </if>
<if test="mapPrdId != null">
map_prd_id = #{mapPrdId,jdbcType=BIGINT},
</if>
<if test="prdType != null"> <if test="prdType != null">
prd_type = #{prdType,jdbcType=VARCHAR}, prd_type = #{prdType,jdbcType=VARCHAR},
</if> </if>
@ -225,7 +252,10 @@
`role` = #{role,jdbcType=VARCHAR}, `role` = #{role,jdbcType=VARCHAR},
</if> </if>
<if test="fake != null"> <if test="fake != null">
fake = #{fake,jdbcType=BIT}, fake = #{fake,jdbcType=TINYINT},
</if>
<if test="endTime != null">
end_time = #{endTime,jdbcType=TIMESTAMP},
</if> </if>
</set> </set>
where id = #{id,jdbcType=BIGINT} where id = #{id,jdbcType=BIGINT}
@ -234,10 +264,34 @@
update user_simulation_stats update user_simulation_stats
set user_id = #{userId,jdbcType=BIGINT}, set user_id = #{userId,jdbcType=BIGINT},
map_id = #{mapId,jdbcType=BIGINT}, map_id = #{mapId,jdbcType=BIGINT},
map_prd_id = #{mapPrdId,jdbcType=BIGINT},
prd_type = #{prdType,jdbcType=VARCHAR}, prd_type = #{prdType,jdbcType=VARCHAR},
duration = #{duration,jdbcType=INTEGER}, duration = #{duration,jdbcType=INTEGER},
`role` = #{role,jdbcType=VARCHAR}, `role` = #{role,jdbcType=VARCHAR},
fake = #{fake,jdbcType=BIT} fake = #{fake,jdbcType=TINYINT},
end_time = #{endTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT} where id = #{id,jdbcType=BIGINT}
</update> </update>
<!-- 额外添加 -->
<select id="queryUsage" resultType="club.joylink.rtss.vo.client.org.StudentsUsageStatisticsVO">
SELECT
sum(duration) AS simulationDuration,
user_id as userId
FROM
user_simulation_stats
WHERE
map_id = #{mapId}
<if test="startTime != null">
and end_time &gt;= #{startTime}
</if>
<if test="endTime != null">
and end_time &lt;= #{endTime}
</if>
AND user_id IN
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
GROUP BY user_id;
</select>
</mapper> </mapper>