|
@@ -5,6 +5,8 @@ import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
import com.fs.common.utils.DateUtils;
|
|
import com.fs.common.utils.DateUtils;
|
|
|
import com.fs.common.utils.spring.SpringUtils;
|
|
import com.fs.common.utils.spring.SpringUtils;
|
|
|
|
|
+import com.fs.hisStore.domain.FsUserScrm;
|
|
|
|
|
+import com.fs.hisStore.mapper.FsUserScrmMapper;
|
|
|
import com.fs.live.domain.*;
|
|
import com.fs.live.domain.*;
|
|
|
import com.fs.live.mapper.*;
|
|
import com.fs.live.mapper.*;
|
|
|
import com.fs.live.param.LiveDataParam;
|
|
import com.fs.live.param.LiveDataParam;
|
|
@@ -13,6 +15,16 @@ import com.fs.live.service.ILiveUserFavoriteService;
|
|
|
import com.fs.live.service.ILiveUserFollowService;
|
|
import com.fs.live.service.ILiveUserFollowService;
|
|
|
import com.fs.live.service.ILiveUserLikeService;
|
|
import com.fs.live.service.ILiveUserLikeService;
|
|
|
import com.fs.live.vo.*;
|
|
import com.fs.live.vo.*;
|
|
|
|
|
+import com.fs.company.domain.Company;
|
|
|
|
|
+import com.fs.company.domain.CompanyUser;
|
|
|
|
|
+import com.fs.company.mapper.CompanyMapper;
|
|
|
|
|
+import com.fs.company.mapper.CompanyUserMapper;
|
|
|
|
|
+import com.fs.course.domain.FsUserCompanyUser;
|
|
|
|
|
+import com.fs.course.mapper.FsUserCompanyUserMapper;
|
|
|
|
|
+import com.fs.his.domain.FsUser;
|
|
|
|
|
+import com.fs.his.mapper.FsUserMapper;
|
|
|
|
|
+import com.fs.hisStore.domain.FsStoreProductScrm;
|
|
|
|
|
+import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
import io.swagger.models.auth.In;
|
|
import io.swagger.models.auth.In;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
@@ -67,7 +79,16 @@ public class LiveDataServiceImpl implements ILiveDataService {
|
|
|
private LiveMsgMapper liveMsgMapper;
|
|
private LiveMsgMapper liveMsgMapper;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private LiveMapper liveMapper;
|
|
private LiveMapper liveMapper;
|
|
|
-
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsUserScrmMapper fsUserScrmMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsUserCompanyUserMapper fsUserCompanyUserMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private CompanyMapper companyMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private CompanyUserMapper companyUserMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private LiveOrderMapper liveOrderMapper;
|
|
|
|
|
|
|
|
/* 直播大屏展示 数据接口 */
|
|
/* 直播大屏展示 数据接口 */
|
|
|
@Override
|
|
@Override
|
|
@@ -139,8 +160,8 @@ public class LiveDataServiceImpl implements ILiveDataService {
|
|
|
public R listLiveData(LiveDataParam param) {
|
|
public R listLiveData(LiveDataParam param) {
|
|
|
// 第一步:查询当前公司的直播间数据
|
|
// 第一步:查询当前公司的直播间数据
|
|
|
// 直播类型 只展示已结束和直播回放的数据 录播展示直播中和已结束的直播数据
|
|
// 直播类型 只展示已结束和直播回放的数据 录播展示直播中和已结束的直播数据
|
|
|
- List<Live> lives = liveMapper.listLiveData(param.getCompanyId());
|
|
|
|
|
- int total = liveMapper.listLiveDataCount(param.getCompanyId());
|
|
|
|
|
|
|
+ List<Live> lives = liveMapper.listLiveData(param);
|
|
|
|
|
+ int total = liveMapper.listLiveDataCount(param);
|
|
|
|
|
|
|
|
if (lives == null || lives.isEmpty()) {
|
|
if (lives == null || lives.isEmpty()) {
|
|
|
LiveDataStatisticsVo statistics = new LiveDataStatisticsVo();
|
|
LiveDataStatisticsVo statistics = new LiveDataStatisticsVo();
|
|
@@ -661,4 +682,397 @@ public class LiveDataServiceImpl implements ILiveDataService {
|
|
|
return column;
|
|
return column;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R getLiveDataDetailBySql(Long liveId) {
|
|
|
|
|
+ LiveDataDetailVo detailVo = liveDataMapper.selectLiveDataDetailBySql(liveId);
|
|
|
|
|
+ if (detailVo == null) {
|
|
|
|
|
+ detailVo = new LiveDataDetailVo();
|
|
|
|
|
+ }
|
|
|
|
|
+ // 查询单品销量统计
|
|
|
|
|
+ List<ProductSalesVo> productSalesList = getProductSalesList(liveId);
|
|
|
|
|
+ detailVo.setProductSalesList(productSalesList);
|
|
|
|
|
+ return R.ok().put("data", detailVo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R getLiveUserDetailListBySql(Long liveId) {
|
|
|
|
|
+ List<LiveUserDetailVo> userDetailList = liveDataMapper.selectLiveUserDetailListBySql(liveId);
|
|
|
|
|
+ return R.ok().put("data", userDetailList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R getLiveDataDetailByServer(Long liveId) {
|
|
|
|
|
+ // 查询数据服务器处理方式:通过查询各个表的数据,在内存中计算统计
|
|
|
|
|
+ LiveDataDetailVo detailVo = calculateLiveDataDetailByServer(liveId);
|
|
|
|
|
+ // 查询单品销量统计
|
|
|
|
|
+ List<ProductSalesVo> productSalesList = getProductSalesList(liveId);
|
|
|
|
|
+ detailVo.setProductSalesList(productSalesList);
|
|
|
|
|
+ return R.ok().put("data", detailVo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R getLiveUserDetailListByServer(Long liveId) {
|
|
|
|
|
+ // 查询数据服务器处理方式:通过查询各个表的数据,在内存中计算
|
|
|
|
|
+ List<LiveUserDetailVo> userDetailList = calculateLiveUserDetailListByServer(liveId);
|
|
|
|
|
+ return R.ok().put("data", userDetailList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 通过查询数据服务器处理方式计算直播间详情数据
|
|
|
|
|
+ */
|
|
|
|
|
+ private LiveDataDetailVo calculateLiveDataDetailByServer(Long liveId) {
|
|
|
|
|
+ LiveDataDetailVo detailVo = new LiveDataDetailVo();
|
|
|
|
|
+
|
|
|
|
|
+ // 查询视频时长
|
|
|
|
|
+ LiveVideoMapper liveVideoMapper = SpringUtils.getBean(LiveVideoMapper.class);
|
|
|
|
|
+ List<LiveVideo> videos = liveVideoMapper.selectByLiveId(liveId);
|
|
|
|
|
+ Long videoDuration = videos.stream()
|
|
|
|
|
+ .filter(v -> v.getVideoType() != null && (v.getVideoType() == 1 || v.getVideoType() == 2))
|
|
|
|
|
+ .mapToLong(v -> v.getDuration() != null ? v.getDuration() : 0L)
|
|
|
|
|
+ .sum();
|
|
|
|
|
+ detailVo.setVideoDuration(videoDuration);
|
|
|
|
|
+
|
|
|
|
|
+ // 查询观看用户数据
|
|
|
|
|
+ LiveWatchUser queryParam = new LiveWatchUser();
|
|
|
|
|
+ queryParam.setLiveId(liveId);
|
|
|
|
|
+ List<LiveWatchUser> watchUsers = liveWatchUserMapper.selectLiveWatchUserList(queryParam);
|
|
|
|
|
+
|
|
|
|
|
+ // 累计观看人数
|
|
|
|
|
+ long totalViewers = watchUsers.stream().map(LiveWatchUser::getUserId).distinct().count();
|
|
|
|
|
+ detailVo.setTotalViewers(totalViewers);
|
|
|
|
|
+
|
|
|
|
|
+ // 直播观看人数
|
|
|
|
|
+ long liveViewers = watchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getLiveFlag() != null && w.getLiveFlag() == 1 && (w.getReplayFlag() == null || w.getReplayFlag() == 0))
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setLiveViewers(liveViewers);
|
|
|
|
|
+
|
|
|
|
|
+ // 回放观看人数
|
|
|
|
|
+ long playbackViewers = watchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getReplayFlag() != null && w.getReplayFlag() == 1 && (w.getLiveFlag() == null || w.getLiveFlag() == 0))
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setPlaybackViewers(playbackViewers);
|
|
|
|
|
+
|
|
|
|
|
+ // 累计完课人数(观看时长 >= 视频时长)
|
|
|
|
|
+ long totalCompletedCourses = watchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null && videoDuration > 0 && w.getOnlineSeconds() >= videoDuration)
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setTotalCompletedCourses(totalCompletedCourses);
|
|
|
|
|
+
|
|
|
|
|
+ // 计算到课完课率
|
|
|
|
|
+ if (totalViewers > 0) {
|
|
|
|
|
+ detailVo.setTotalCompletionRate(BigDecimal.valueOf(totalCompletedCourses * 100.0 / totalViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 直播相关统计
|
|
|
|
|
+ List<LiveWatchUser> liveWatchUsers = watchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getLiveFlag() != null && w.getLiveFlag() == 1 && (w.getReplayFlag() == null || w.getReplayFlag() == 0))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ long liveOver20Minutes = liveWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null && w.getOnlineSeconds() >= 1200)
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setLiveOver20Minutes(liveOver20Minutes);
|
|
|
|
|
+
|
|
|
|
|
+ long liveOver30Minutes = liveWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null && w.getOnlineSeconds() >= 1800)
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setLiveOver30Minutes(liveOver30Minutes);
|
|
|
|
|
+
|
|
|
|
|
+ if (liveViewers > 0) {
|
|
|
|
|
+ detailVo.setLiveCompletionRate20(BigDecimal.valueOf(liveOver20Minutes * 100.0 / liveViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ detailVo.setLiveCompletionRate30(BigDecimal.valueOf(liveOver30Minutes * 100.0 / liveViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 直播平均时长
|
|
|
|
|
+ double liveAvgDuration = liveWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null)
|
|
|
|
|
+ .mapToLong(LiveWatchUser::getOnlineSeconds)
|
|
|
|
|
+ .average()
|
|
|
|
|
+ .orElse(0.0);
|
|
|
|
|
+ detailVo.setLiveAvgDuration((long) liveAvgDuration);
|
|
|
|
|
+
|
|
|
|
|
+ // 回放相关统计
|
|
|
|
|
+ List<LiveWatchUser> playbackWatchUsers = watchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getReplayFlag() != null && w.getReplayFlag() == 1 && (w.getLiveFlag() == null || w.getLiveFlag() == 0))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ long playbackOver20Minutes = playbackWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null && w.getOnlineSeconds() >= 1200)
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setPlaybackOver20Minutes(playbackOver20Minutes);
|
|
|
|
|
+
|
|
|
|
|
+ long playbackOver30Minutes = playbackWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null && w.getOnlineSeconds() >= 1800)
|
|
|
|
|
+ .map(LiveWatchUser::getUserId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setPlaybackOver30Minutes(playbackOver30Minutes);
|
|
|
|
|
+
|
|
|
|
|
+ if (playbackViewers > 0) {
|
|
|
|
|
+ detailVo.setPlaybackCompletionRate20(BigDecimal.valueOf(playbackOver20Minutes * 100.0 / playbackViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ detailVo.setPlaybackCompletionRate30(BigDecimal.valueOf(playbackOver30Minutes * 100.0 / playbackViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 回放平均时长
|
|
|
|
|
+ double playbackAvgDuration = playbackWatchUsers.stream()
|
|
|
|
|
+ .filter(w -> w.getOnlineSeconds() != null)
|
|
|
|
|
+ .mapToLong(LiveWatchUser::getOnlineSeconds)
|
|
|
|
|
+ .average()
|
|
|
|
|
+ .orElse(0.0);
|
|
|
|
|
+ detailVo.setPlaybackAvgDuration((long) playbackAvgDuration);
|
|
|
|
|
+
|
|
|
|
|
+ // 回放完播率
|
|
|
|
|
+ if (videoDuration > 0) {
|
|
|
|
|
+ detailVo.setPlaybackFinishRate(BigDecimal.valueOf(playbackAvgDuration * 100.0 / videoDuration).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询直播峰值
|
|
|
|
|
+ LiveData liveData = liveDataMapper.selectLiveDataByLiveId(liveId);
|
|
|
|
|
+ if (liveData != null && liveData.getPeakConcurrentViewers() != null) {
|
|
|
|
|
+ detailVo.setLivePeak(liveData.getPeakConcurrentViewers());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询订单数据
|
|
|
|
|
+ LiveOrderMapper liveOrderMapper = SpringUtils.getBean(LiveOrderMapper.class);
|
|
|
|
|
+ LiveOrder orderQuery = new LiveOrder();
|
|
|
|
|
+ orderQuery.setLiveId(liveId);
|
|
|
|
|
+ List<LiveOrder> orders = liveOrderMapper.selectLiveOrderList(orderQuery);
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal gmv = orders.stream()
|
|
|
|
|
+ .filter(o -> "1".equals(o.getIsPay()))
|
|
|
|
|
+ .map(LiveOrder::getPayPrice)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ detailVo.setGmv(gmv);
|
|
|
|
|
+
|
|
|
|
|
+ long paidUsers = orders.stream()
|
|
|
|
|
+ .filter(o -> "1".equals(o.getIsPay()))
|
|
|
|
|
+ .filter(o -> o.getUserId() != null && !o.getUserId().isEmpty())
|
|
|
|
|
+ .map(o -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return Long.parseLong(o.getUserId());
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setPaidUsers(paidUsers);
|
|
|
|
|
+
|
|
|
|
|
+ long paidOrders = orders.stream()
|
|
|
|
|
+ .filter(o -> "1".equals(o.getIsPay()))
|
|
|
|
|
+ .count();
|
|
|
|
|
+ detailVo.setPaidOrders(paidOrders);
|
|
|
|
|
+
|
|
|
|
|
+ // 计算转化率
|
|
|
|
|
+ if (detailVo.getLivePeak() > 0) {
|
|
|
|
|
+ detailVo.setPeakConversionRate(BigDecimal.valueOf(paidUsers * 100.0 / detailVo.getLivePeak()).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ detailVo.setPeakRValue(gmv.divide(BigDecimal.valueOf(detailVo.getLivePeak()), 2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (totalViewers > 0) {
|
|
|
|
|
+ detailVo.setTotalViewerConversionRate(BigDecimal.valueOf(paidUsers * 100.0 / totalViewers).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (liveOver30Minutes > 0) {
|
|
|
|
|
+ detailVo.setCompletion30MinConversionRate(BigDecimal.valueOf(paidUsers * 100.0 / liveOver30Minutes).setScale(2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (totalCompletedCourses > 0) {
|
|
|
|
|
+ detailVo.setCompletionRValue(gmv.divide(BigDecimal.valueOf(totalCompletedCourses), 2, RoundingMode.HALF_UP));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return detailVo;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 通过查询数据服务器处理方式计算用户详情列表
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<LiveUserDetailVo> calculateLiveUserDetailListByServer(Long liveId) {
|
|
|
|
|
+ // 查询观看用户
|
|
|
|
|
+ List<LiveWatchUser> watchUsers = liveWatchUserMapper.selectLiveWatchUserListByLiveId(liveId);
|
|
|
|
|
+
|
|
|
|
|
+ LiveOrder orderQuery = new LiveOrder();
|
|
|
|
|
+ orderQuery.setLiveId(liveId);
|
|
|
|
|
+ List<LiveOrder> orders = liveOrderMapper.selectLiveOrderList(orderQuery);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 按用户ID分组统计
|
|
|
|
|
+ Map<Long, LiveUserDetailVo> userDetailMap = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (LiveWatchUser watchUser : watchUsers) {
|
|
|
|
|
+ Long userId = watchUser.getUserId();
|
|
|
|
|
+ if (userId == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ LiveUserDetailVo userDetail = userDetailMap.computeIfAbsent(userId, k -> {
|
|
|
|
|
+ LiveUserDetailVo vo = new LiveUserDetailVo();
|
|
|
|
|
+ vo.setUserId(userId);
|
|
|
|
|
+ // 查询用户信息
|
|
|
|
|
+ FsUserScrm user = fsUserScrmMapper.selectFsUserByUserId(userId);
|
|
|
|
|
+ if (user != null) {
|
|
|
|
|
+ vo.setUserName(user.getNickName() != null ? user.getNickName() : (user.getNickName() != null ? user.getNickName() : "未知用户"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ vo.setUserName("未知用户");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 查询用户和销售关系
|
|
|
|
|
+ FsUserCompanyUser queryUserCompanyUser = new FsUserCompanyUser();
|
|
|
|
|
+ queryUserCompanyUser.setUserId(userId);
|
|
|
|
|
+ List<FsUserCompanyUser> userCompanyUserList = fsUserCompanyUserMapper.selectFsUserCompanyUserList(queryUserCompanyUser);
|
|
|
|
|
+ FsUserCompanyUser userCompanyUser = userCompanyUserList != null && !userCompanyUserList.isEmpty() ? userCompanyUserList.get(0) : null;
|
|
|
|
|
+ if (userCompanyUser != null) {
|
|
|
|
|
+ if (userCompanyUser.getCompanyId() != null) {
|
|
|
|
|
+ Company company = companyMapper.selectCompanyById(userCompanyUser.getCompanyId());
|
|
|
|
|
+ if (company != null) {
|
|
|
|
|
+ vo.setCompanyName(company.getCompanyName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (userCompanyUser.getCompanyUserId() != null) {
|
|
|
|
|
+ CompanyUser companyUser = companyUserMapper.selectCompanyUserByUserId(userCompanyUser.getCompanyUserId());
|
|
|
|
|
+ if (companyUser != null) {
|
|
|
|
|
+ vo.setSalesName(companyUser.getUserName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 累加观看时长
|
|
|
|
|
+ if (watchUser.getOnlineSeconds() != null) {
|
|
|
|
|
+ if (watchUser.getLiveFlag() != null && watchUser.getLiveFlag() == 1 && (watchUser.getReplayFlag() == null || watchUser.getReplayFlag() == 0)) {
|
|
|
|
|
+ userDetail.setLiveWatchDuration(userDetail.getLiveWatchDuration() + watchUser.getOnlineSeconds());
|
|
|
|
|
+ } else if (watchUser.getReplayFlag() != null && watchUser.getReplayFlag() == 1 && (watchUser.getLiveFlag() == null || watchUser.getLiveFlag() == 0)) {
|
|
|
|
|
+ userDetail.setPlaybackWatchDuration(userDetail.getPlaybackWatchDuration() + watchUser.getOnlineSeconds());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 统计订单数据
|
|
|
|
|
+ Map<Long, List<LiveOrder>> userOrdersMap = orders.stream()
|
|
|
|
|
+ .filter(o -> o.getUserId() != null && !o.getUserId().isEmpty())
|
|
|
|
|
+ .filter(o -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Long.parseLong(o.getUserId());
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .collect(Collectors.groupingBy(o -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return Long.parseLong(o.getUserId());
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ return 0L;
|
|
|
|
|
+ }
|
|
|
|
|
+ }));
|
|
|
|
|
+
|
|
|
|
|
+ for (Map.Entry<Long, List<LiveOrder>> entry : userOrdersMap.entrySet()) {
|
|
|
|
|
+ Long userId = entry.getKey();
|
|
|
|
|
+ List<LiveOrder> userOrders = entry.getValue();
|
|
|
|
|
+
|
|
|
|
|
+ LiveUserDetailVo userDetail = userDetailMap.computeIfAbsent(userId, k -> {
|
|
|
|
|
+ LiveUserDetailVo vo = new LiveUserDetailVo();
|
|
|
|
|
+ vo.setUserId(userId);
|
|
|
|
|
+ FsUserScrm user = fsUserScrmMapper.selectFsUserByUserId(userId);
|
|
|
|
|
+ if (user != null) {
|
|
|
|
|
+ vo.setUserName(user.getNickName() != null ? user.getNickName() : (user.getNickName() != null ? user.getNickName() : "未知用户"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ vo.setUserName("未知用户");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 查询用户和销售关系
|
|
|
|
|
+ FsUserCompanyUser queryUserCompanyUser = new FsUserCompanyUser();
|
|
|
|
|
+ queryUserCompanyUser.setUserId(userId);
|
|
|
|
|
+ List<FsUserCompanyUser> userCompanyUserList = fsUserCompanyUserMapper.selectFsUserCompanyUserList(queryUserCompanyUser);
|
|
|
|
|
+ if (userCompanyUserList != null && !userCompanyUserList.isEmpty()) {
|
|
|
|
|
+ FsUserCompanyUser userCompanyUser = userCompanyUserList.get(0);
|
|
|
|
|
+ if (userCompanyUser.getCompanyId() != null) {
|
|
|
|
|
+ Company company = companyMapper.selectCompanyById(userCompanyUser.getCompanyId());
|
|
|
|
|
+ if (company != null) {
|
|
|
|
|
+ vo.setCompanyName(company.getCompanyName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (userCompanyUser.getCompanyUserId() != null) {
|
|
|
|
|
+ CompanyUser companyUser = companyUserMapper.selectCompanyUserByUserId(userCompanyUser.getCompanyUserId());
|
|
|
|
|
+ if (companyUser != null) {
|
|
|
|
|
+ vo.setSalesName(companyUser.getUserName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ userDetail.setOrderCount((long) userOrders.size());
|
|
|
|
|
+ BigDecimal orderAmount = userOrders.stream()
|
|
|
|
|
+ .filter(o -> "1".equals(o.getIsPay()))
|
|
|
|
|
+ .map(LiveOrder::getPayPrice)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ userDetail.setOrderAmount(orderAmount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为列表并排序
|
|
|
|
|
+ List<LiveUserDetailVo> result = new ArrayList<>(userDetailMap.values());
|
|
|
|
|
+ result.sort((a, b) -> {
|
|
|
|
|
+ int compare = b.getOrderAmount().compareTo(a.getOrderAmount());
|
|
|
|
|
+ if (compare != 0) return compare;
|
|
|
|
|
+ return Long.compare(b.getLiveWatchDuration(), a.getLiveWatchDuration());
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询单品销量统计
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<ProductSalesVo> getProductSalesList(Long liveId) {
|
|
|
|
|
+
|
|
|
|
|
+ List<LiveOrder> orders = liveOrderMapper.selectOrderByLiveId(liveId);
|
|
|
|
|
+
|
|
|
|
|
+ // 按商品ID分组统计
|
|
|
|
|
+ Map<Long, ProductSalesVo> productSalesMap = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (LiveOrder order : orders) {
|
|
|
|
|
+ if (!"1".equals(order.getIsPay()) || order.getProductId() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ProductSalesVo productSales = productSalesMap.computeIfAbsent(order.getProductId(), k -> {
|
|
|
|
|
+ ProductSalesVo vo = new ProductSalesVo();
|
|
|
|
|
+ vo.setProductId(order.getProductId());
|
|
|
|
|
+ // 查询商品名称
|
|
|
|
|
+ FsStoreProductScrmMapper productMapper = SpringUtils.getBean(FsStoreProductScrmMapper.class);
|
|
|
|
|
+ FsStoreProductScrm product = productMapper.selectFsStoreProductById(order.getProductId());
|
|
|
|
|
+ if (product != null) {
|
|
|
|
|
+ vo.setProductName(product.getProductName());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ vo.setProductName("未知商品");
|
|
|
|
|
+ }
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ productSales.setSalesCount(productSales.getSalesCount() + 1);
|
|
|
|
|
+ if (order.getPayPrice() != null) {
|
|
|
|
|
+ productSales.setSalesAmount(productSales.getSalesAmount().add(order.getPayPrice()));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<ProductSalesVo> result = new ArrayList<>(productSalesMap.values());
|
|
|
|
|
+ result.sort((a, b) -> b.getSalesAmount().compareTo(a.getSalesAmount()));
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|