From 841f1631b790d2c4caf24a40eb4830f57a9bafa5 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Wed, 17 Sep 2025 17:21:07 +0800 Subject: [PATCH] feat(ai): 添加知识点推荐功能- 新增 AiProductPointService接口的 recommend 方法 - 实现 AiProductPointServiceImpl 中的 recommend 方法逻辑 - 添加 ApiProductPointController 中的 recommend 接口 - 创建 ApiProductPointRecommendDto 和 ApiProductPointRecommendVo 类 --- src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberServiceImpl.java | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 248 insertions(+), 2 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberServiceImpl.java index 37f81eb..ac90ba3 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberServiceImpl.java @@ -1,12 +1,32 @@ package cc.mrbird.febs.ai.service.impl; -import cc.mrbird.febs.ai.entity.AiMember; +import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.mapper.AiMemberMapper; -import cc.mrbird.febs.ai.service.AiMemberService; +import cc.mrbird.febs.ai.req.member.ApiMemberTeamPageDto; +import cc.mrbird.febs.ai.req.member.ApiMemberTeamPracticeDto; +import cc.mrbird.febs.ai.req.member.ApiMemberTeamStudyDto; +import cc.mrbird.febs.ai.res.member.ApiMemberTeamPageVo; +import cc.mrbird.febs.ai.res.member.ApiMemberTeamPracticeVo; +import cc.mrbird.febs.ai.res.member.ApiMemberTeamStudyVo; +import cc.mrbird.febs.ai.res.productPoint.ApiProductPointListVo; +import cc.mrbird.febs.ai.service.*; +import cc.mrbird.febs.common.entity.FebsResponse; +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.common.utils.LoginUserUtil; +import cc.mrbird.febs.mall.entity.MallMember; +import cc.mrbird.febs.mall.mapper.MallMemberMapper; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; /** * @author Administrator @@ -15,4 +35,230 @@ @Service @RequiredArgsConstructor public class AiMemberServiceImpl extends ServiceImpl<AiMemberMapper, AiMember> implements AiMemberService { + + private final AiMemberMapper aiMemberMapper; + private final MallMemberMapper mallMemberMapper; + private final AiMemberTalkService aiMemberTalkService; + private final AiMemberAnswerService aiMemberAnswerService; + private final AiMemberPointService aiMemberPointService; + private final AiProductService aiProductService; + private final AiProductPointService aiProductPointService; + @Override + public AiMember getById(String id) { + return aiMemberMapper.selectById( id); + } + + @Override + public FebsResponse myTeam(ApiMemberTeamPageDto dto) { + List<ApiMemberTeamPageVo> objects = new ArrayList<>(); + + String companyId = LoginUserUtil.getLoginUser().getCompanyId(); + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + Integer checkOrder = LoginUserUtil.getLoginUser().getCheckOrder(); + if (1 != checkOrder){ + throw new FebsException("非管理员,无权限查看"); + } + + // 创建分页对象,传入当前页和每页大小 + Page<AiMember> page = new Page<>(dto.getPageNow(), dto.getPageSize()); + + LambdaQueryWrapper<AiMember> queryWrapper = Wrappers.lambdaQuery(AiMember.class); + queryWrapper.eq(AiMember::getCompanyId, companyId); + Page<AiMember> pageListByQuery = aiMemberMapper.selectPage(page, queryWrapper); + List<AiMember> records = pageListByQuery.getRecords(); + if (CollUtil.isNotEmpty( records)){ + objects = buildMemberPages(memberUuid,companyId,records,objects); + } + return new FebsResponse().success().data(objects); + } + + private List<ApiMemberTeamPageVo> buildMemberPages(String memberUuid, String companyId, List<AiMember> records, List<ApiMemberTeamPageVo> objects) { + /** + * 获取用户信息 + */ + //stream流操作records,获取全部的id + Set<String> memberIds = records.stream().map(AiMember::getId).collect(Collectors.toSet()); + + List<MallMember> mallMembers = mallMemberMapper.selectList( + Wrappers.lambdaQuery(MallMember.class) + .select(MallMember::getMemberUuid, MallMember::getName, MallMember::getRealName) + .in(MallMember::getMemberUuid, memberIds) + .eq(MallMember::getCompanyId, companyId) + ); + //Stream流操作mallMembers,获取一个map<memberUuid,mallMember>的对象 + Map<String, MallMember> mallMemberMap = mallMembers.stream().collect(Collectors.toMap(MallMember::getMemberUuid, mallMember -> mallMember)); + + /** + * 获取用户练习次数 + * ai陪练 + * ai答题 + */ + List<AiMemberTalk> aiMemberTalks = aiMemberTalkService.getListByCompanyId(companyId); + //stream流操作aiMemberTalks,获取一个Map<memberId,Integer>的对象,integer代表按照memberId分组的数量 + Map<String, Integer> memberIdToCntMapTalk = aiMemberTalks.stream() + .collect(Collectors.groupingBy( + AiMemberTalk::getMemberId, + Collectors.summingInt(t -> 1) + )); + + List<AiMemberAnswer> aiMemberAnswers = aiMemberAnswerService.getListByCompanyId(companyId); + //stream流操作aiMemberAnswers,获取一个Map<memberId,Integer>的对象,integer代表按照memberId分组的数量 + Map<String, Integer> memberIdToCntMapAnswer = aiMemberAnswers.stream() + .collect(Collectors.groupingBy( + AiMemberAnswer::getMemberId, + Collectors.summingInt(a -> 1) + )); + /** + * 用户学习总时长 + */ + List<AiMemberPoint> aiMemberPoints = aiMemberPointService.getListByCompanyId(companyId); + Map<String, Integer> memberStudyTimeMap = aiMemberPoints.stream().collect(Collectors.groupingBy( + AiMemberPoint::getMemberId, + Collectors.summingInt(AiMemberPoint::getTotalTime) + )); + + + for (AiMember aiMember : records){ + String aiMemberId = aiMember.getId(); + ApiMemberTeamPageVo apiMemberTeamPageVo = new ApiMemberTeamPageVo(); + apiMemberTeamPageVo.setType(0); + apiMemberTeamPageVo.setMemberUuid(aiMemberId); + if (memberUuid.equals(aiMemberId)){ + apiMemberTeamPageVo.setType(1); + } + + //判断mallMemberMap中是否存在该会员 + apiMemberTeamPageVo.setNickName(mallMemberMap.containsKey(aiMemberId) ? mallMemberMap.get(aiMemberId).getName() : ""); + apiMemberTeamPageVo.setMemberName(mallMemberMap.containsKey(aiMemberId) ? mallMemberMap.get(aiMemberId).getName() : ""); + Integer practiceCnt = 0; + if (memberIdToCntMapTalk.containsKey(aiMemberId)){ + practiceCnt = memberIdToCntMapTalk.get(aiMemberId); + } + if (memberIdToCntMapAnswer.containsKey(aiMemberId)){ + practiceCnt = memberIdToCntMapAnswer.get(aiMemberId) + practiceCnt; + } + apiMemberTeamPageVo.setPracticeCnt(practiceCnt); + + Integer studyTime = 0; + if (memberStudyTimeMap.containsKey(aiMemberId)){ + studyTime = memberStudyTimeMap.get(aiMemberId); + } + apiMemberTeamPageVo.setStudyTime(DateUtil.secondToTime(studyTime)); + objects.add(apiMemberTeamPageVo); + } + return objects; + } + + + + @Override + public FebsResponse practice(ApiMemberTeamPracticeDto dto) { + List<ApiMemberTeamPracticeVo> vos = new ArrayList<>(); + + String companyId = LoginUserUtil.getLoginUser().getCompanyId(); + String memberUuid = dto.getMemberUuid(); + + List<AiMemberTalk> aiMemberTalks = aiMemberTalkService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); + Map<String, List<AiMemberTalk>> aiMemberTalkMap = new HashMap<>(); + if (CollUtil.isNotEmpty(aiMemberTalks)){ + //stream操作aiMemberTalks,返回一个根据productId分组的集合 + aiMemberTalkMap = aiMemberTalks.stream().collect(Collectors.groupingBy(AiMemberTalk::getProductId)); + } + + List<AiMemberAnswer> aiMemberAnswers = aiMemberAnswerService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); + Map<String, List<AiMemberAnswer>> aiMemberAnswerMap = new HashMap<>(); + if (CollUtil.isNotEmpty(aiMemberAnswers)){ + aiMemberAnswerMap = aiMemberAnswers.stream().collect(Collectors.groupingBy(AiMemberAnswer::getProductId)); + } + + // 获取aiMemberTalkMap和aiMemberAnswerMap的全部的key,并且去重 + Set<String> productIds = new HashSet<>(); + if (aiMemberTalkMap != null) { + productIds.addAll(aiMemberTalkMap.keySet()); + } + if (aiMemberAnswerMap != null) { + productIds.addAll(aiMemberAnswerMap.keySet()); + } + if (CollUtil.isEmpty(productIds)){ + return new FebsResponse().success().data(vos); + } + + List<AiProduct> aiProducts = aiProductService.getProductListByQuery( + Wrappers.lambdaQuery(AiProduct.class) + .select(AiProduct::getId,AiProduct::getName, AiProduct::getTarget) + .in(AiProduct::getId, productIds) + ); + if (CollUtil.isEmpty(aiProducts)){ + return new FebsResponse().success().data(vos); + } + + for (AiProduct aiProduct : aiProducts){ + + String productId = aiProduct.getId(); + ApiMemberTeamPracticeVo vo = new ApiMemberTeamPracticeVo(); + vo.setName(aiProduct.getName()); + vo.setTarget(aiProduct.getTarget()); + + Integer answerCnt = 0; + if (aiMemberAnswerMap.containsKey(productId)){ + answerCnt = aiMemberAnswerMap.get(productId).size(); + } + vo.setAnswerCnt(answerCnt); + + Integer talkCnt = 0; + if (aiMemberTalkMap.containsKey(productId)){ + talkCnt = aiMemberTalkMap.get(productId).size(); + } + vo.setTalkCnt(talkCnt); + + vos.add( vo); + } + + + return new FebsResponse().success().data(vos); + } + + @Override + public FebsResponse study(ApiMemberTeamStudyDto dto) { + + List<ApiMemberTeamStudyVo> vos = new ArrayList<>(); + + String companyId = LoginUserUtil.getLoginUser().getCompanyId(); + String memberUuid = dto.getMemberUuid(); + + List<AiMemberPoint> aiMemberPoints = aiMemberPointService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); + if (CollUtil.isEmpty(aiMemberPoints)){ + return new FebsResponse().success().data(vos); + } + Map<String, AiMemberPoint> aiMemberPointMap = new HashMap<>(); + if (CollUtil.isNotEmpty(aiMemberPoints)){ + aiMemberPoints.forEach(aiMemberPoint -> aiMemberPointMap.put(aiMemberPoint.getProductPointId(),aiMemberPoint)); + } + + //stream流操作aiMemberPoints,返回一个productPointId的set集合 + Set<String> productPointIdSet = aiMemberPoints.stream().map(AiMemberPoint::getProductPointId).collect(Collectors.toSet()); + + List<AiProductPoint> aiProductPoints = aiProductPointService.getBaseMapper().selectList( + Wrappers.lambdaQuery(AiProductPoint.class) + .select(AiProductPoint::getId,AiProductPoint::getTitle) + .in(AiProductPoint::getId, productPointIdSet) + ); + if (CollUtil.isEmpty(aiProductPoints)){ + return new FebsResponse().success().data(vos); + } + + for (AiProductPoint aiProductPoint : aiProductPoints){ + ApiMemberTeamStudyVo vo = new ApiMemberTeamStudyVo(); + vo.setTitle(aiProductPoint.getTitle()); + Integer totalTime = 0; + if (aiMemberPointMap.containsKey(aiProductPoint.getId())){ + totalTime = aiMemberPointMap.get(aiProductPoint.getId()).getTotalTime(); + } + vo.setTotalTime(DateUtil.secondToTime(totalTime)); + + vos.add(vo); + } + + return new FebsResponse().success().data(vos); + } } -- Gitblit v1.9.1