|
|
@@ -11,9 +11,11 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.fs.common.BeanCopyUtils;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.common.exception.ServiceException;
|
|
|
import com.fs.common.utils.DateUtils;
|
|
|
import com.fs.common.utils.DictUtils;
|
|
|
import com.fs.common.utils.date.DateUtil;
|
|
|
+import com.github.pagehelper.PageHelper;
|
|
|
import com.fs.company.cache.ICompanyCacheService;
|
|
|
import com.fs.company.cache.ICompanyDeptCacheService;
|
|
|
import com.fs.company.cache.ICompanyUserCacheService;
|
|
|
@@ -749,6 +751,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
|
|
|
@Override
|
|
|
public List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVO(FsCourseWatchLogListParam param) {
|
|
|
+ prepareTagIdsForWatchLogList(param);
|
|
|
|
|
|
// 因为selectFsCourseWatchLogListVO 这个方法中查询了看课日志记录表 需要限制创建时间必传
|
|
|
if ((StringUtils.isEmpty(param.getSTime()) || StringUtils.isEmpty(param.getETime())) &&
|
|
|
@@ -1516,7 +1519,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
|
|
|
@Override
|
|
|
public List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVOexport(FsCourseWatchLogListParam param) {
|
|
|
-
|
|
|
+ prepareTagIdsForWatchLogList(param);
|
|
|
|
|
|
if (param.getSendType() == 1 && param.getPeriodETime() != null && param.getPeriodSTime() != null) {
|
|
|
List<Long> periodIds = userCoursePeriodDaysService.selectFsUserCoursePeriodDaysByTime(param.getPeriodSTime(), param.getPeriodETime());
|
|
|
@@ -1798,7 +1801,145 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
}
|
|
|
@Override
|
|
|
public List<FsCoureseWatchLogVO> selectUserIdList(FsCourseWatchLogParam fsCourseWatchLog) {
|
|
|
- return fsCourseWatchLogMapper.selectUserIdList(fsCourseWatchLog);
|
|
|
+ // 有小节区间时先解析 video_id,无匹配则直接空列表
|
|
|
+ if (!prepareVideoIdsForUserIdList(fsCourseWatchLog)) {
|
|
|
+ PageHelper.clearPage();
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ return fsCourseWatchLogMapper.selectUserIdList(fsCourseWatchLog);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析小节过滤口径:
|
|
|
+ * 1) 未选小节,或勾选了该课程当前全部小节 → 按 course_id 统计(与「全选」一致,含历史小节日志)
|
|
|
+ * 2) 仅勾选部分小节 → 按 video_id IN (...) 精确过滤
|
|
|
+ *
|
|
|
+ * @return false 表示有小节筛选但无有效 ID,应返回空列表;无需 video_id 收窄时返回 true
|
|
|
+ */
|
|
|
+ private boolean prepareVideoIdsForUserIdList(FsCourseWatchLogParam param) {
|
|
|
+ if (param == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (param.getCourseId() != null && param.getProject() == null) {
|
|
|
+ throw new ServiceException("请先选择项目后再选择课程");
|
|
|
+ }
|
|
|
+ // 未选课程:不能带小节;仅按项目(或都不选)过滤
|
|
|
+ if (param.getCourseId() == null) {
|
|
|
+ if (com.fs.common.utils.StringUtils.isNotEmpty(param.getVideoIdList())) {
|
|
|
+ throw new ServiceException("请先选择课程后再按小节筛选");
|
|
|
+ }
|
|
|
+ param.setVideoIds(null);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> requestVideoIds = parseVideoIdList(param.getVideoIdList());
|
|
|
+ // 未选手动小节:按课程统计,不用 video_id 收窄
|
|
|
+ if (CollectionUtils.isEmpty(requestVideoIds)) {
|
|
|
+ param.setVideoIds(null);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<FsUserCourseVideo> courseVideos = fsUserCourseVideoMapper.selectVideoByCourseId(param.getCourseId());
|
|
|
+ Set<Long> validSet = new HashSet<>();
|
|
|
+ if (CollectionUtils.isNotEmpty(courseVideos)) {
|
|
|
+ for (FsUserCourseVideo video : courseVideos) {
|
|
|
+ if (video.getVideoId() != null) {
|
|
|
+ validSet.add(video.getVideoId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ List<Long> videoIds = new ArrayList<>();
|
|
|
+ for (Long videoId : requestVideoIds) {
|
|
|
+ if (validSet.contains(videoId) && !videoIds.contains(videoId)) {
|
|
|
+ videoIds.add(videoId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (videoIds.isEmpty()) {
|
|
|
+ param.setVideoIds(Collections.emptyList());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 勾选数量覆盖当前课程全部小节时,视为「全选」,与不选小节同一课程口径
|
|
|
+ if (!validSet.isEmpty() && videoIds.size() == validSet.size() && validSet.containsAll(videoIds)) {
|
|
|
+ param.setVideoIds(null);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ param.setVideoIds(videoIds);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 解析逗号分隔的视频 ID 字符串 */
|
|
|
+ private List<Long> parseVideoIdList(String videoIdList) {
|
|
|
+ if (StringUtils.isEmpty(videoIdList)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ List<Long> result = new ArrayList<>();
|
|
|
+ String[] parts = videoIdList.split(",");
|
|
|
+ for (String part : parts) {
|
|
|
+ if (part == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String trimmed = part.trim();
|
|
|
+ if (trimmed.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ result.add(Long.valueOf(trimmed));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ throw new ServiceException("小节视频ID格式不正确:" + trimmed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析标签参数,对齐企微客户:支持 tagIdList / tagIds 逗号串 / List
|
|
|
+ */
|
|
|
+ private void prepareTagIdsForWatchLogList(FsCourseWatchLogListParam param) {
|
|
|
+ if (param == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<String> result = new ArrayList<>();
|
|
|
+ if (StringUtils.isNotEmpty(param.getTagIdList())) {
|
|
|
+ result.addAll(splitTagIdCsv(param.getTagIdList()));
|
|
|
+ } else if (CollectionUtils.isNotEmpty(param.getTagIds())) {
|
|
|
+ for (String item : param.getTagIds()) {
|
|
|
+ if (item == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 企微客户前端 join 成逗号串后,Spring 可能绑成单元素 List
|
|
|
+ if (item.contains(",")) {
|
|
|
+ result.addAll(splitTagIdCsv(item));
|
|
|
+ } else {
|
|
|
+ String trimmed = item.trim();
|
|
|
+ if (!trimmed.isEmpty()) {
|
|
|
+ result.add(trimmed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (result.isEmpty()) {
|
|
|
+ param.setTagIds(null);
|
|
|
+ } else {
|
|
|
+ param.setTagIds(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> splitTagIdCsv(String csv) {
|
|
|
+ List<String> result = new ArrayList<>();
|
|
|
+ if (StringUtils.isEmpty(csv)) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ String[] parts = csv.split(",");
|
|
|
+ for (String part : parts) {
|
|
|
+ if (part == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String trimmed = part.trim();
|
|
|
+ if (!trimmed.isEmpty()) {
|
|
|
+ result.add(trimmed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
}
|