|
|
@@ -0,0 +1,1728 @@
|
|
|
+package shop.alien.lawyer.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+import org.springframework.web.multipart.MultipartRequest;
|
|
|
+import shop.alien.entity.result.R;
|
|
|
+import shop.alien.entity.store.*;
|
|
|
+import shop.alien.entity.store.dto.OrderReviewDto;
|
|
|
+import shop.alien.entity.store.dto.ReviewCommentRequestDto;
|
|
|
+import shop.alien.entity.store.dto.ReviewReplyDto;
|
|
|
+import shop.alien.entity.store.vo.*;
|
|
|
+import shop.alien.lawyer.config.WebSocketProcess;
|
|
|
+import shop.alien.lawyer.service.StoreCommentService;
|
|
|
+import shop.alien.lawyer.service.StoreImgService;
|
|
|
+import shop.alien.lawyer.util.FileUploadUtil;
|
|
|
+import shop.alien.mapper.*;
|
|
|
+import shop.alien.util.common.DateUtils;
|
|
|
+import shop.alien.util.common.netease.ImageCheckUtil;
|
|
|
+import shop.alien.util.common.netease.TextCheckUtil;
|
|
|
+import shop.alien.util.common.safe.TextModerationResultVO;
|
|
|
+import shop.alien.util.common.safe.TextModerationUtil;
|
|
|
+import shop.alien.util.common.safe.TextReviewServiceEnum;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 评论表 服务实现类
|
|
|
+ *
|
|
|
+ * @author ssk
|
|
|
+ * @since 2025-01-02
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, StoreComment> implements StoreCommentService {
|
|
|
+
|
|
|
+ private final StoreCommentMapper storeCommentMapper;
|
|
|
+
|
|
|
+ private final LifeLikeRecordMapper lifeLikeRecordMapper;
|
|
|
+
|
|
|
+ private final FileUploadUtil fileUploadUtil;
|
|
|
+
|
|
|
+ private final StoreImgMapper storeImgMapper;
|
|
|
+
|
|
|
+ private final LifeUserViolationMapper lifeUserViolationMapper;
|
|
|
+
|
|
|
+ private final StoreUserMapper storeUserMapper;
|
|
|
+
|
|
|
+ private final LifeUserMapper lifeUserMapper;
|
|
|
+
|
|
|
+ private final StoreCommentAppealMapper storeCommentAppealMapper;
|
|
|
+
|
|
|
+ private final StoreInfoMapper storeInfoMapper;
|
|
|
+
|
|
|
+ private final LifeNoticeMapper lifeNoticeMapper;
|
|
|
+
|
|
|
+ private final WebSocketProcess webSocketProcess;
|
|
|
+
|
|
|
+ private final TagsSynonymMapper tagsSynonymMapper;
|
|
|
+
|
|
|
+ private final LifeUserOrderMapper lifeUserOrderMapper;
|
|
|
+
|
|
|
+ private final LawyerConsultationOrderMapper lawyerConsultationOrderMapper;
|
|
|
+ private final LawyerUserMapper lawyerUserMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TextModerationUtil textModerationUtil;
|
|
|
+ @Autowired
|
|
|
+ private StoreImgService storeImgService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 评论列表
|
|
|
+ *
|
|
|
+ * @param pageNum 页数
|
|
|
+ * @param pageSize 页容
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价, 6:订单评论的评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @param replyStatus 回复状态(0:全部, 1:已回复, 2:未回复)
|
|
|
+ * @param commentLevel 评论等级(0:全部, 1:好评, 2:中评, 3:差评)
|
|
|
+ * @param days 查询时间, 多少天前
|
|
|
+ * @param phoneId 消息标识
|
|
|
+ * @param userType 评论的用户类型(0:商家, 其他:用户)
|
|
|
+ * @param tagId 标签id
|
|
|
+ * @param hasImage 是否有图片(0否/1是)
|
|
|
+ * @return IPage<StoreComment>
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public IPage<StoreCommentVo> getList(Integer pageNum, Integer pageSize, Integer businessId, Integer businessType, Integer storeId, Integer replyStatus, Integer commentLevel, Integer days, String phoneId, Integer userType, Integer tagId, Boolean hasImage) {
|
|
|
+ IPage<StoreCommentVo> storeCommentIPage = new Page<>(pageNum, pageSize);
|
|
|
+ QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq(null != businessId, "a.business_id", businessId);
|
|
|
+ queryWrapper.eq(null != businessType, "a.business_type", businessType);
|
|
|
+ queryWrapper.eq(null != storeId, "a.store_id", storeId);
|
|
|
+ //好评 a>=4
|
|
|
+ queryWrapper.ge(null != commentLevel && 1 == commentLevel, "a.score", 4.5);
|
|
|
+ //中评 a>=2&& a<4
|
|
|
+ queryWrapper.ge(null != commentLevel && 2 == commentLevel, "a.score", 3).le(null != commentLevel && 2 == commentLevel, "a.score", 4);
|
|
|
+ //差评 a<2
|
|
|
+ queryWrapper.ge(null != commentLevel && 3 == commentLevel, "a.score", 0.5).le(null != commentLevel && 3 == commentLevel, "a.score", 2.5);
|
|
|
+ if (null != days) {
|
|
|
+ Date date = DateUtils.calcDays(new Date(), -days);
|
|
|
+ queryWrapper.ge("a.created_time", DateUtils.formatDate(date, "yyyy-MM-dd"));
|
|
|
+ }
|
|
|
+ //通过当前登录人id 类型 查询举报业务id
|
|
|
+ List<LifeUserViolation> lifeUserViolations = new ArrayList<>();
|
|
|
+ if(businessType==2){
|
|
|
+ String userId;
|
|
|
+ if(phoneId.startsWith("store_")){
|
|
|
+ userId = phoneId.substring("store_".length());
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getPhone,userId));
|
|
|
+ if(storeUser!=null){
|
|
|
+ LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,storeUser.getId());
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,1);
|
|
|
+ lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
|
|
|
+ lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ userId = phoneId.substring("user_".length());
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectOne(new LambdaQueryWrapper<LifeUser>().eq(LifeUser::getUserPhone,userId));
|
|
|
+ if(lifeUser!=null){
|
|
|
+ LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,lifeUser.getId());
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,2);
|
|
|
+ lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
|
|
|
+ lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ List<Integer> businessIds = lifeUserViolations.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(LifeUserViolation::getBusinessId)
|
|
|
+ .filter(id -> id != null && !id.toString().isEmpty())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if(businessIds!=null && businessIds.size()>0){
|
|
|
+ queryWrapper.notIn("a.id",businessIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ //根据标签id查询表签字表拿到评论ids
|
|
|
+ if(tagId !=null){
|
|
|
+ List<TagsSynonym> tagsSynonymList = tagsSynonymMapper.selectList(new LambdaQueryWrapper<TagsSynonym>().eq(TagsSynonym::getMainTagId,tagId));
|
|
|
+ if(CollectionUtils.isNotEmpty(tagsSynonymList)){
|
|
|
+ List<Integer> commentIdList = tagsSynonymList.stream().filter(synonym -> synonym != null)
|
|
|
+ .map(TagsSynonym::getCommentId).filter(commentId -> commentId != null).collect(Collectors.toList());
|
|
|
+ queryWrapper.in("a.id",commentIdList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //先查询父级评论
|
|
|
+ queryWrapper.isNull(businessType != 1, "a.reply_id").eq("a.delete_flag", 0).orderByDesc("a.created_time");
|
|
|
+ IPage<StoreCommentVo> page = storeCommentMapper.getCommentPage(storeCommentIPage, queryWrapper);
|
|
|
+ List<StoreCommentVo> records = page.getRecords();
|
|
|
+ List<StoreCommentVo> storeCommentVoList = new ArrayList<>();
|
|
|
+
|
|
|
+ //评价图片
|
|
|
+ Set<Integer> imgIdList = new HashSet<>();
|
|
|
+ for (int i = 0; i < records.size(); i++) {
|
|
|
+ StoreCommentVo storeCommentVo = new StoreCommentVo();
|
|
|
+ BeanUtils.copyProperties(records.get(i), storeCommentVo);
|
|
|
+ //首评
|
|
|
+ storeCommentVo.setFirstComment(i == 0);
|
|
|
+ //有无图片
|
|
|
+ if (records.get(i).getImgId() != null) {
|
|
|
+ storeCommentVo.setHasImage(true);
|
|
|
+ String[] split = records.get(i).getImgId().split(",");
|
|
|
+ for (String s : split) {
|
|
|
+ imgIdList.add(Integer.parseInt(s));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ storeCommentVo.setHasImage(false);
|
|
|
+ }
|
|
|
+ //低分
|
|
|
+ storeCommentVo.setLowScore(records.get(i).getScore() <= 1);
|
|
|
+
|
|
|
+ QueryWrapper<StoreCommentAppealVo> storeCommentAppealVoQueryWrapper = new QueryWrapper<>();
|
|
|
+ storeCommentAppealVoQueryWrapper.eq("a.comment_id", storeCommentVo.getId()).eq("a.delete_flag", 0).orderByDesc("a.created_time").last("limit 1");
|
|
|
+ StoreCommentAppealVo commentDetail = storeCommentAppealMapper.getCommentDetail(storeCommentAppealVoQueryWrapper);
|
|
|
+ if (ObjectUtils.isNotEmpty(commentDetail)) {
|
|
|
+ storeCommentVo.setAppealFlag(1);
|
|
|
+ storeCommentVo.setAppealStatusStr(commentDetail.getAppealStatusStr());
|
|
|
+ storeCommentVo.setAppealStatus(commentDetail.getAppealStatus());
|
|
|
+ }else {
|
|
|
+ storeCommentVo.setAppealFlag(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ //商家用户
|
|
|
+ if (StringUtils.isNotEmpty(records.get(i).getPhoneId())) {
|
|
|
+ if (records.get(i).getPhoneId().contains("store_")) {
|
|
|
+ storeCommentVo.setStoreUserFlag(0);
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, records.get(i).getStoreId()));
|
|
|
+ storeCommentVo.setStoreUserName(storeUser.getName());
|
|
|
+ storeCommentVo.setStoreUserImg(storeUser.getHeadImg());
|
|
|
+ } else {
|
|
|
+ storeCommentVo.setStoreUserFlag(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ StoreInfo storeInfo = storeInfoMapper.selectById(records.get(i).getStoreId());
|
|
|
+ if (storeInfo != null) {
|
|
|
+ storeCommentVo.setStoreName(storeInfo.getStoreName());
|
|
|
+ }
|
|
|
+ storeCommentVoList.add(storeCommentVo);
|
|
|
+ }
|
|
|
+
|
|
|
+ //塞图片
|
|
|
+ if (!imgIdList.isEmpty()) {
|
|
|
+ List<StoreImg> storeImgList = storeImgMapper.selectList(new QueryWrapper<StoreImg>().in("id", imgIdList));
|
|
|
+
|
|
|
+ storeCommentVoList.forEach(storeCommentVo -> {
|
|
|
+ if (null != storeCommentVo.getImgId()) {
|
|
|
+ storeCommentVo.setImgUrl(new ArrayList<>());
|
|
|
+ for (StoreImg storeImg : storeImgList) {
|
|
|
+ for (String s : storeCommentVo.getImgId().split(",")) {
|
|
|
+ if (storeImg.getId().equals(Integer.parseInt(s))) {
|
|
|
+ storeCommentVo.getImgUrl().add(storeImg.getImgUrl());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ //父级评论下拼接子评论
|
|
|
+ for (StoreCommentVo storeCommentVo : storeCommentVoList) {
|
|
|
+ storeCommentVo.setCommitCount(0);
|
|
|
+ //父级点赞状态
|
|
|
+ if (StringUtils.isNotEmpty(phoneId)) {
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> likeRecordQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ likeRecordQueryWrapper.eq(LifeLikeRecord::getDianzanId, phoneId).eq(LifeLikeRecord::getHuifuId, storeCommentVo.getId());
|
|
|
+ Integer i = lifeLikeRecordMapper.selectCount(likeRecordQueryWrapper);
|
|
|
+ if (i > 0) {
|
|
|
+ storeCommentVo.setIsLike(1);
|
|
|
+ } else {
|
|
|
+ storeCommentVo.setIsLike(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
|
|
|
+ if(businessIds!=null && businessIds.size()>0){
|
|
|
+ childQueryWrapper.notIn("a.id",businessIds);
|
|
|
+ }
|
|
|
+ childQueryWrapper.eq(null != businessId && 6 == businessId, "a.business_id", businessId).eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId()).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
|
|
|
+ storeCommentVo.setCommitCount(storeCommentVo.getCommitCount() + childCommentList.size());
|
|
|
+ //评价的评论的评论
|
|
|
+ childCommentList.forEach(child -> {
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
|
|
|
+ childQueryCommentWrapper
|
|
|
+// .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
|
|
|
+ .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
|
|
|
+
|
|
|
+ //商家用户
|
|
|
+ for (StoreCommentVo commentVo : childComment2List) {
|
|
|
+ if (StringUtils.isNotEmpty(commentVo.getPhoneId())) {
|
|
|
+ if (commentVo.getPhoneId().contains("store_")) {
|
|
|
+ commentVo.setStoreUserFlag(0);
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, child.getStoreId()));
|
|
|
+ commentVo.setStoreUserName(storeUser.getName());
|
|
|
+ commentVo.setStoreUserImg(storeUser.getHeadImg());
|
|
|
+ } else {
|
|
|
+ commentVo.setStoreUserFlag(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ child.setStoreComment(childComment2List);
|
|
|
+ storeCommentVo.setCommitCount(storeCommentVo.getCommitCount() + childComment2List.size());
|
|
|
+
|
|
|
+ //商家用户
|
|
|
+ if (StringUtils.isNotEmpty(child.getPhoneId())) {
|
|
|
+ if (child.getPhoneId().contains("store_")) {
|
|
|
+ child.setStoreUserFlag(0);
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, child.getStoreId()));
|
|
|
+ child.setStoreUserName(storeUser.getName());
|
|
|
+ child.setStoreUserImg(storeUser.getHeadImg());
|
|
|
+ } else {
|
|
|
+ child.setStoreUserFlag(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+ //筛选商家评论
|
|
|
+ List<StoreCommentVo> storeCommentList = new ArrayList<>();
|
|
|
+ if (null != userType && userType == 0) {
|
|
|
+ List<StoreCommentVo> collect = childCommentList.stream().filter(childComment -> childComment.getPhoneId().contains("store_")).collect(Collectors.toList());
|
|
|
+ if (!collect.isEmpty()) {
|
|
|
+ storeCommentList.add(collect.get(0));
|
|
|
+ storeCommentVo.setStoreComment(storeCommentList);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ storeCommentVo.setStoreComment(childCommentList);
|
|
|
+ }
|
|
|
+ //子级点赞状态
|
|
|
+ if (StringUtils.isNotEmpty(phoneId)) {
|
|
|
+ childCommentList.forEach(child -> {
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> childlikeRecordQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ childlikeRecordQueryWrapper.eq(LifeLikeRecord::getDianzanId, phoneId).eq(LifeLikeRecord::getHuifuId, child.getId());
|
|
|
+ if (lifeLikeRecordMapper.selectCount(childlikeRecordQueryWrapper) > 0) {
|
|
|
+ child.setIsLike(1);
|
|
|
+ } else {
|
|
|
+ child.setIsLike(0);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IPage<StoreCommentVo> resultPage = new Page<>();
|
|
|
+ resultPage.setCurrent(page.getCurrent());
|
|
|
+ resultPage.setSize(page.getSize());
|
|
|
+ resultPage.setTotal(page.getTotal());
|
|
|
+ resultPage.setPages(page.getPages());
|
|
|
+ //筛选有无评论
|
|
|
+ List<StoreCommentVo> collect = new ArrayList<>();
|
|
|
+ if (replyStatus != null) {
|
|
|
+ if (1 == replyStatus) {
|
|
|
+ //只查询有回复的评论
|
|
|
+ collect = storeCommentVoList.stream().filter(storeCommentVo -> ObjectUtils.isNotEmpty(storeCommentVo.getStoreComment())).collect(Collectors.toList());
|
|
|
+ } else if (2 == replyStatus) {
|
|
|
+ //只查询无回复的评论
|
|
|
+ collect = storeCommentVoList.stream().filter(storeCommentVo -> ObjectUtils.isEmpty(storeCommentVo.getStoreComment())).collect(Collectors.toList());
|
|
|
+ } else {
|
|
|
+ collect = storeCommentVoList;
|
|
|
+ }
|
|
|
+ }
|
|
|
+// collect.forEach(item -> {
|
|
|
+// item.setCommitCount(null != item.getStoreComment() ? item.getStoreComment().size() : 0);
|
|
|
+// });
|
|
|
+ resultPage.setRecords(collect);
|
|
|
+ return resultPage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取最新一条评论/评价
|
|
|
+ *
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @return StoreCommentVo
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StoreCommentVo getOne(Integer businessId, Integer businessType, Integer storeId) {
|
|
|
+ AtomicReference<Integer> count = new AtomicReference<>(0);
|
|
|
+ QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq(null != businessId, "a.business_id", businessId).eq(null != businessType, "a.business_type", businessType).eq(null != storeId, "a.store_id", storeId).eq("a.delete_flag", 0).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> commentList = storeCommentMapper.getCommentList(queryWrapper);
|
|
|
+ count.updateAndGet(v -> v + commentList.size());
|
|
|
+ //父级评论下拼接子评论
|
|
|
+ for (StoreCommentVo storeCommentVo : commentList) {
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
|
|
|
+ childQueryWrapper.eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId());
|
|
|
+ List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
|
|
|
+ count.updateAndGet(v -> v + childCommentList.size());
|
|
|
+ //评价的评论的评论
|
|
|
+ childCommentList.forEach(child -> {
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
|
|
|
+ childQueryCommentWrapper
|
|
|
+// .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
|
|
|
+ .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
|
|
|
+ count.updateAndGet(v -> v + childComment2List.size());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (!commentList.isEmpty()) {
|
|
|
+ StoreCommentVo storeCommentVo = commentList.get(0);
|
|
|
+ storeCommentVo.setCommitCount(Integer.parseInt(String.valueOf(count)));
|
|
|
+ return storeCommentVo;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 评论/评价数量和评分
|
|
|
+ *
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @return Integer
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> getCommitCountAndScore(Integer businessId, Integer businessType, Integer storeId, String phoneId, Integer days) {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ AtomicReference<Integer> count = new AtomicReference<>(0);
|
|
|
+ QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq(null != businessId, "a.business_id", businessId);
|
|
|
+ queryWrapper.eq(null != businessType, "a.business_type", businessType);
|
|
|
+ queryWrapper.eq(null != storeId, "a.store_id", storeId);
|
|
|
+
|
|
|
+ if (null != days) {
|
|
|
+ Date date = DateUtils.calcDays(new Date(), -days);
|
|
|
+ queryWrapper.ge("a.created_time", DateUtils.formatDate(date, "yyyy-MM-dd"));
|
|
|
+ }
|
|
|
+
|
|
|
+ //通过当前登录人id 类型 查询举报业务id
|
|
|
+ List<LifeUserViolation> lifeUserViolations = new ArrayList<>();
|
|
|
+ if(businessType==2){
|
|
|
+ String userId;
|
|
|
+ if(phoneId!=null && !phoneId.equals("") && phoneId.startsWith("store_")){
|
|
|
+ userId = phoneId.substring("store_".length());
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getPhone,userId));
|
|
|
+ if(storeUser!=null){
|
|
|
+ LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,storeUser.getId());
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,1);
|
|
|
+ lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
|
|
|
+ lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
|
|
|
+ }
|
|
|
+ }else if(phoneId!=null && !phoneId.equals("") && phoneId.startsWith("user_")){
|
|
|
+ userId = phoneId.substring("user_".length());
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectOne(new LambdaQueryWrapper<LifeUser>().eq(LifeUser::getUserPhone,userId));
|
|
|
+ if(lifeUser!=null){
|
|
|
+ LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,lifeUser.getId());
|
|
|
+ lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,2);
|
|
|
+ lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
|
|
|
+ lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Integer> businessIds = lifeUserViolations.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(LifeUserViolation::getBusinessId)
|
|
|
+ .filter(id -> id != null && !id.toString().isEmpty())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if(businessIds!=null && businessIds.size()>0){
|
|
|
+ queryWrapper.notIn("a.id",businessIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ //先查询父级评论
|
|
|
+ queryWrapper.isNull(businessType != 1, "a.reply_id").eq("a.delete_flag", 0).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> storeCommentVoList = storeCommentMapper.getCommentList(queryWrapper);
|
|
|
+ count.updateAndGet(v -> v + storeCommentVoList.size());
|
|
|
+ //评分合计
|
|
|
+ Double sumScore = 0.0;
|
|
|
+ //父级评论下拼接子评论
|
|
|
+ for (StoreCommentVo storeCommentVo : storeCommentVoList) {
|
|
|
+ sumScore += storeCommentVo.getScore();
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
|
|
|
+ childQueryWrapper.eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId());
|
|
|
+ List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
|
|
|
+ count.updateAndGet(v -> v + childCommentList.size());
|
|
|
+ //评价的评论的评论
|
|
|
+ childCommentList.forEach(child -> {
|
|
|
+ QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
|
|
|
+ childQueryCommentWrapper
|
|
|
+// .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
|
|
|
+ .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
|
|
|
+ List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
|
|
|
+ count.updateAndGet(v -> v + childComment2List.size());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ map.put("commitCount", count.toString());
|
|
|
+ map.put("img", storeCommentVoList.stream().filter(i -> i.getScore() >= 4.5).map(StoreCommentVo::getUserImage).distinct().limit(6).collect(Collectors.toList()));
|
|
|
+ if (sumScore == 0 || storeCommentVoList.isEmpty()) {
|
|
|
+ map.put("score", "0");
|
|
|
+ } else {
|
|
|
+ BigDecimal score = new BigDecimal(sumScore).divide(new BigDecimal(storeCommentVoList.size()), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ map.put("score", score.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+// Map<String, Object> commentCountAndScore = storeCommentMapper.getCommentCountAndScore(businessId, businessType, storeId);
|
|
|
+// Object scoreObj = commentCountAndScore.get("score");
|
|
|
+// double scoreDouble = 0.0;
|
|
|
+// if (scoreObj != null) {
|
|
|
+// if (scoreObj instanceof Number) {
|
|
|
+// scoreDouble = ((Number) scoreObj).doubleValue();
|
|
|
+// } else if (scoreObj instanceof String) {
|
|
|
+// scoreDouble = Double.parseDouble((String) scoreObj);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (scoreDouble == 0) {
|
|
|
+// map.put("score", "0");
|
|
|
+// } else {
|
|
|
+// BigDecimal scoreBigDecimal = new BigDecimal(String.valueOf(scoreDouble)).divide(new BigDecimal(commentCountAndScore.get("rootCount").toString()), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+// map.put("score", scoreBigDecimal.toString());
|
|
|
+// }
|
|
|
+// map.put("commitCount", commentCountAndScore.get("count").toString());
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 评论
|
|
|
+ *
|
|
|
+ * @param multipartRequest 文件
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @param userId 用户id
|
|
|
+ * @param replyId 回复id
|
|
|
+ * @param commentContent 评价内容
|
|
|
+ * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Integer userComment(MultipartRequest multipartRequest, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent) {
|
|
|
+ try {
|
|
|
+ Map<String, String> checkText = TextCheckUtil.check(commentContent);
|
|
|
+ if (null == checkText || checkText.get("result").equals("1")) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+ StoreComment storeComment = new StoreComment();
|
|
|
+ storeComment.setStoreId(storeId);
|
|
|
+ storeComment.setUserId(userId);
|
|
|
+ storeComment.setCommentContent(commentContent);
|
|
|
+ storeComment.setReplyId(replyId);
|
|
|
+ storeComment.setBusinessId(businessId);
|
|
|
+ storeComment.setBusinessType(businessType);
|
|
|
+ List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
|
|
|
+ if (!fileNameSet.isEmpty()) {
|
|
|
+ StringBuilder imgId = new StringBuilder();
|
|
|
+ for (int i = 0; i < fileNameSet.size(); i++) {
|
|
|
+ MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
|
|
|
+ if (null != multipartFile) {
|
|
|
+ byte[] fileByte;
|
|
|
+ try {
|
|
|
+ fileByte = multipartFile.getBytes();
|
|
|
+ } catch (IOException e) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ String base64 = Base64.getEncoder().encodeToString(fileByte);
|
|
|
+ Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
|
|
|
+ if (checkImage != null && checkImage.get("result").equals("1")) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+ StoreImg storeImg = new StoreImg();
|
|
|
+ storeImg.setStoreId(storeComment.getStoreId());
|
|
|
+ storeImg.setImgType(8);
|
|
|
+ storeImg.setImgSort(i + 1);
|
|
|
+ storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
|
|
|
+ storeImgMapper.insert(storeImg);
|
|
|
+ imgId.append(storeImg.getId()).append(",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!imgId.toString().isEmpty()) {
|
|
|
+ storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ storeComment.setCreatedUserId(storeComment.getUserId());
|
|
|
+ return this.save(storeComment) ? 0 : 1;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增或修改评论/评价
|
|
|
+ *
|
|
|
+ * @param multipartRequest 文件
|
|
|
+ * @param id 主键
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @param userId 用户id
|
|
|
+ * @param replyId 回复id
|
|
|
+ * @param commentContent 评价内容
|
|
|
+ * @param score 评分
|
|
|
+ * @param otherScore 其他评分
|
|
|
+ * @param isAnonymous 是否匿名(0:否(默认), 1:是)
|
|
|
+ * @param evaluationTags 评价标签
|
|
|
+ * @param phoneId 用户id
|
|
|
+ * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
|
|
|
+ try {
|
|
|
+ List<String> servicesList = Lists.newArrayList();
|
|
|
+ servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
|
|
|
+ servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
|
|
|
+ TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
|
|
|
+ if ("high".equals(textCheckResult.getRiskLevel())) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
|
|
|
+ if (null == checkText || checkText.get("result").equals("1")) {
|
|
|
+ return 2;
|
|
|
+ }*/
|
|
|
+ StoreComment storeComment = new StoreComment();
|
|
|
+ storeComment.setId(id);
|
|
|
+ storeComment.setStoreId(storeId);
|
|
|
+ storeComment.setUserId(userId);
|
|
|
+ storeComment.setCommentContent(commentContent);
|
|
|
+ storeComment.setReplyId(replyId);
|
|
|
+ storeComment.setBusinessId(businessId);
|
|
|
+ storeComment.setBusinessType(businessType);
|
|
|
+ storeComment.setScore(score);
|
|
|
+
|
|
|
+ if (StringUtils.isNotEmpty(otherScore)) {
|
|
|
+ List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
|
|
|
+ lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
|
|
|
+ lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
|
|
|
+ lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
|
|
|
+ }
|
|
|
+ storeComment.setOtherScore(otherScore);
|
|
|
+ storeComment.setIsAnonymous(isAnonymous);
|
|
|
+ storeComment.setEvaluationTags(evaluationTags);
|
|
|
+ storeComment.setPhoneId(phoneId);
|
|
|
+ List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
|
|
|
+ if (!fileNameSet.isEmpty() && storeId != null) {
|
|
|
+ StringBuilder imgId = new StringBuilder();
|
|
|
+ for (int i = 0; i < fileNameSet.size(); i++) {
|
|
|
+ MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
|
|
|
+ //b
|
|
|
+ System.out.println(multipartFile.getSize());
|
|
|
+ //kb
|
|
|
+ System.out.println(multipartFile.getSize() / 1024);
|
|
|
+ if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
|
|
|
+ byte[] fileByte;
|
|
|
+ try {
|
|
|
+ fileByte = multipartFile.getBytes();
|
|
|
+ } catch (IOException e) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ String base64 = Base64.getEncoder().encodeToString(fileByte);
|
|
|
+ Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
|
|
|
+ if (checkImage != null && checkImage.get("result").equals("1")) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+ StoreImg storeImg = new StoreImg();
|
|
|
+ storeImg.setStoreId(storeComment.getStoreId());
|
|
|
+ storeImg.setImgType(8);
|
|
|
+ storeImg.setImgSort(i + 1);
|
|
|
+ storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
|
|
|
+ storeImgMapper.insert(storeImg);
|
|
|
+ imgId.append(storeImg.getId()).append(",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!imgId.toString().isEmpty()) {
|
|
|
+ storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ storeComment.setCreatedUserId(storeComment.getUserId());
|
|
|
+ int i = this.save(storeComment) ? 0 : 1;
|
|
|
+
|
|
|
+ //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
|
|
|
+ if(businessType == 5){
|
|
|
+ LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
|
|
|
+ lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
|
|
|
+ lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
|
|
|
+ }
|
|
|
+ StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
|
|
|
+ double total = storeInfoScoreVo.getTotal();
|
|
|
+ double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
|
|
|
+ double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
|
|
|
+ double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
|
|
|
+ double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
|
|
|
+ StoreInfo storeInfo = new StoreInfo();
|
|
|
+ storeInfo.setId(storeId);
|
|
|
+ storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setServiceScore(new BigDecimal(serviceScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfoMapper.updateById(storeInfo);
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
|
|
|
+
|
|
|
+ // 如果差评,则发送差评提醒
|
|
|
+ if(score != null && score >= 0.5 && score <= 2.5){
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String commonDate = simpleDateFormat.format(new Date());
|
|
|
+ LifeNotice lifeMessage = new LifeNotice();
|
|
|
+ lifeMessage.setReceiverId("store_" + storeUser.getPhone());
|
|
|
+ String text = "在"+commonDate+",您的店铺有一条差评记录,您可查看评价内容是否属实,如不属实,可向平台进行申诉。";
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ jsonObject.put("message", text);
|
|
|
+ lifeMessage.setContext(jsonObject.toJSONString());
|
|
|
+ lifeMessage.setTitle("差评通知");
|
|
|
+ lifeMessage.setSenderId("system");
|
|
|
+ lifeMessage.setIsRead(0);
|
|
|
+ lifeMessage.setNoticeType(1);
|
|
|
+ lifeNoticeMapper.insert(lifeMessage);
|
|
|
+
|
|
|
+ WebSocketVo websocketVo = new WebSocketVo();
|
|
|
+ websocketVo.setSenderId("system");
|
|
|
+ websocketVo.setReceiverId("store_" + storeUser.getPhone());
|
|
|
+ websocketVo.setCategory("notice");
|
|
|
+ websocketVo.setNoticeType("1");
|
|
|
+ websocketVo.setIsRead(0);
|
|
|
+ websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
|
|
|
+ webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
|
|
|
+ }
|
|
|
+ return i;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增或修改评论/评价
|
|
|
+ *
|
|
|
+ * @param multipartRequest 文件
|
|
|
+ * @param id 主键
|
|
|
+ * @param businessId 业务id
|
|
|
+ * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @param userId 用户id
|
|
|
+ * @param replyId 回复id
|
|
|
+ * @param commentContent 评价内容
|
|
|
+ * @param score 评分
|
|
|
+ * @param otherScore 其他评分
|
|
|
+ * @param isAnonymous 是否匿名(0:否(默认), 1:是)
|
|
|
+ * @param evaluationTags 评价标签
|
|
|
+ * @param phoneId 用户id
|
|
|
+ * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
|
|
|
+ try {
|
|
|
+ List<String> servicesList = Lists.newArrayList();
|
|
|
+ servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
|
|
|
+ servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
|
|
|
+ TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
|
|
|
+ if ("high".equals(textCheckResult.getRiskLevel())) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
|
|
|
+ if (null == checkText || checkText.get("result").equals("1")) {
|
|
|
+ return 2;
|
|
|
+ }*/
|
|
|
+ StoreComment storeComment = new StoreComment();
|
|
|
+ storeComment.setId(id);
|
|
|
+ storeComment.setStoreId(storeId);
|
|
|
+ storeComment.setUserId(userId);
|
|
|
+ storeComment.setCommentContent(commentContent);
|
|
|
+ storeComment.setReplyId(replyId);
|
|
|
+ storeComment.setBusinessId(businessId);
|
|
|
+ storeComment.setBusinessType(businessType);
|
|
|
+ storeComment.setScore(score);
|
|
|
+ storeComment.setLawyerId(lawyerId);
|
|
|
+ storeComment.setOrderId(orderId);
|
|
|
+
|
|
|
+ if (StringUtils.isNotEmpty(otherScore)) {
|
|
|
+ List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
|
|
|
+ lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
|
|
|
+ lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
|
|
|
+ lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
|
|
|
+ }
|
|
|
+ storeComment.setOtherScore(otherScore);
|
|
|
+ storeComment.setIsAnonymous(isAnonymous);
|
|
|
+ storeComment.setEvaluationTags(evaluationTags);
|
|
|
+ storeComment.setPhoneId(phoneId);
|
|
|
+ List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
|
|
|
+ if (!fileNameSet.isEmpty() && storeId != null) {
|
|
|
+ StringBuilder imgId = new StringBuilder();
|
|
|
+ for (int i = 0; i < fileNameSet.size(); i++) {
|
|
|
+ MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
|
|
|
+ //b
|
|
|
+ System.out.println(multipartFile.getSize());
|
|
|
+ //kb
|
|
|
+ System.out.println(multipartFile.getSize() / 1024);
|
|
|
+ if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
|
|
|
+ byte[] fileByte;
|
|
|
+ try {
|
|
|
+ fileByte = multipartFile.getBytes();
|
|
|
+ } catch (IOException e) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ String base64 = Base64.getEncoder().encodeToString(fileByte);
|
|
|
+ Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
|
|
|
+ if (checkImage != null && checkImage.get("result").equals("1")) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+ StoreImg storeImg = new StoreImg();
|
|
|
+ storeImg.setStoreId(storeComment.getStoreId());
|
|
|
+ storeImg.setImgType(8);
|
|
|
+ storeImg.setImgSort(i + 1);
|
|
|
+ storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
|
|
|
+ storeImgMapper.insert(storeImg);
|
|
|
+ imgId.append(storeImg.getId()).append(",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!imgId.toString().isEmpty()) {
|
|
|
+ storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ storeComment.setCreatedUserId(storeComment.getUserId());
|
|
|
+ int i = this.save(storeComment) ? 0 : 1;
|
|
|
+
|
|
|
+ //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
|
|
|
+ if(businessType == 5){
|
|
|
+ LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
|
|
|
+ lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
|
|
|
+ lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
|
|
|
+ }
|
|
|
+ StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
|
|
|
+ double total = storeInfoScoreVo.getTotal();
|
|
|
+ double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
|
|
|
+ double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
|
|
|
+ double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
|
|
|
+ double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
|
|
|
+ StoreInfo storeInfo = new StoreInfo();
|
|
|
+ storeInfo.setId(storeId);
|
|
|
+ storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfo.setServiceScore(new BigDecimal(serviceScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
|
|
+ storeInfoMapper.updateById(storeInfo);
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
|
|
|
+
|
|
|
+ // 如果差评,则发送差评提醒
|
|
|
+ if(score != null && score >= 0.5 && score <= 2.5){
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String commonDate = simpleDateFormat.format(new Date());
|
|
|
+ LifeNotice lifeMessage = new LifeNotice();
|
|
|
+ lifeMessage.setReceiverId("store_" + storeUser.getPhone());
|
|
|
+ String text = "在"+commonDate+",您的店铺有一条差评记录,您可查看评价内容是否属实,如不属实,可向平台进行申诉。";
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ jsonObject.put("message", text);
|
|
|
+ lifeMessage.setContext(jsonObject.toJSONString());
|
|
|
+ lifeMessage.setTitle("差评通知");
|
|
|
+ lifeMessage.setSenderId("system");
|
|
|
+ lifeMessage.setIsRead(0);
|
|
|
+ lifeMessage.setNoticeType(1);
|
|
|
+ lifeNoticeMapper.insert(lifeMessage);
|
|
|
+
|
|
|
+ WebSocketVo websocketVo = new WebSocketVo();
|
|
|
+ websocketVo.setSenderId("system");
|
|
|
+ websocketVo.setReceiverId("store_" + storeUser.getPhone());
|
|
|
+ websocketVo.setCategory("notice");
|
|
|
+ websocketVo.setNoticeType("1");
|
|
|
+ websocketVo.setIsRead(0);
|
|
|
+ websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
|
|
|
+ webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
|
|
|
+ }
|
|
|
+ return i;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 回复率, 评价比例
|
|
|
+ *
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @return StoreCommitPercentVo
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StoreCommitPercentVo getCommitPercent(Integer storeId) {
|
|
|
+ StoreCommitPercentVo storeCommit = storeCommentMapper.getCommentByStoreId(storeId);
|
|
|
+ if (storeCommit != null) {
|
|
|
+ if ("0".equals(storeCommit.getAllCommentCount())) {
|
|
|
+ storeCommit.setHighPercent("0%");
|
|
|
+ storeCommit.setMidPercent("0%");
|
|
|
+ storeCommit.setLowPercent("0%");
|
|
|
+ } else {
|
|
|
+ double highPercentDouble = Double.parseDouble(storeCommit.getHighCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
|
|
|
+ BigDecimal highPercent = BigDecimal.valueOf(highPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ //好评
|
|
|
+ storeCommit.setHighPercent(highPercent + "%");
|
|
|
+ double midPercentDouble = Double.parseDouble(storeCommit.getMidCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
|
|
|
+ BigDecimal midPercent = BigDecimal.valueOf(midPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ //中评
|
|
|
+ storeCommit.setMidPercent(midPercent + "%");
|
|
|
+ double lowPercentDouble = Double.parseDouble(storeCommit.getLowCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
|
|
|
+ BigDecimal lowPercent = BigDecimal.valueOf(lowPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ //差评
|
|
|
+ storeCommit.setLowPercent(lowPercent + "%");
|
|
|
+ }
|
|
|
+ if ("0".equals(storeCommit.getRootCommentCount())) {
|
|
|
+ storeCommit.setReplyPercent("0%");
|
|
|
+ } else {
|
|
|
+ double replyPercentDouble = Double.parseDouble(storeCommit.getCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
|
|
|
+ BigDecimal replyPercent = BigDecimal.valueOf(replyPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ //回复率
|
|
|
+ storeCommit.setReplyPercent(replyPercent + "%");
|
|
|
+ }
|
|
|
+ return storeCommit;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public IPage<LifeUserOrderCommentVo> getCommentOrderPage(Integer pageNum, Integer pageSize, Integer type, String userId) {
|
|
|
+ IPage<LifeUserOrderCommentVo> lifeUserOrderCommentVoIPage = new Page<>(pageNum, pageSize);
|
|
|
+ IPage<LifeUserOrderCommentVo> commentOrderPage;
|
|
|
+ //1.未评价 2.已评价
|
|
|
+ if (type == 1) {
|
|
|
+ commentOrderPage = storeCommentMapper.getCommentOrderWPJPage(lifeUserOrderCommentVoIPage, userId);
|
|
|
+ } else {
|
|
|
+ commentOrderPage = storeCommentMapper.getCommentOrderYPJPage(lifeUserOrderCommentVoIPage, userId);
|
|
|
+ }
|
|
|
+ List<String> collect = commentOrderPage.getRecords().stream().map(LifeUserOrderCommentVo::getGroupBuyImgId).collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (ObjectUtils.isNotEmpty(collect)) {
|
|
|
+ List<StoreImg> storeImgList = storeImgMapper.selectList(new QueryWrapper<StoreImg>().inSql("id", String.join(",", collect)));
|
|
|
+// commentOrderPage.getRecords().forEach(i ->
|
|
|
+// i.setGroupBuyImgUrl(storeImgList.stream().filter(j -> j.getId().toString().equals(i.getGroupBuyImgId()))
|
|
|
+// .findFirst().map(StoreImg::getImgUrl).orElse(null)));
|
|
|
+ // 2. 优化分组:id唯一,直接映射为 Map<Integer, StoreImg>(避免List处理)
|
|
|
+ Map<Integer, StoreImg> imgIdToImgMap = storeImgList.stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ StoreImg::getId, // 键:图片id
|
|
|
+ Function.identity(), // 值:图片对象本身
|
|
|
+ (existing, replacement) -> existing // 若有重复id(理论上不会),保留第一个
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 3. 遍历订单评论记录,处理图片URL拼接
|
|
|
+ for (LifeUserOrderCommentVo record : commentOrderPage.getRecords()) {
|
|
|
+ String groupBuyImgId = record.getGroupBuyImgId();
|
|
|
+ // 空指针防护:如果imgId为空,直接设为空字符串
|
|
|
+ if (groupBuyImgId == null || groupBuyImgId.trim().isEmpty()) {
|
|
|
+ record.setGroupBuyImgUrl("");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分割imgId并一次性转换为Integer(避免重复解析)
|
|
|
+ List<Integer> imgIds = Arrays.stream(groupBuyImgId.split(","))
|
|
|
+ .map(String::trim) // 处理可能的空格
|
|
|
+ .filter(idStr -> !idStr.isEmpty()) // 过滤空字符串(如连续逗号导致的)
|
|
|
+ .map(idStr -> {
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(idStr);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 处理非数字id的异常(如无效id)
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .filter(Objects::nonNull) // 过滤转换失败的null
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 拼接图片URL(使用StringBuilder高效拼接)
|
|
|
+ StringBuilder imgUrlBuilder = new StringBuilder();
|
|
|
+ for (Integer imgId : imgIds) {
|
|
|
+ StoreImg storeImg = imgIdToImgMap.get(imgId);
|
|
|
+ if (storeImg != null && storeImg.getImgUrl() != null) {
|
|
|
+ if (imgUrlBuilder.length() > 0) {
|
|
|
+ imgUrlBuilder.append(","); // 非第一个元素前加逗号
|
|
|
+ }
|
|
|
+ imgUrlBuilder.append(storeImg.getImgUrl());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置最终的图片URL字符串(去掉末尾可能的逗号,这里通过逻辑避免了)
|
|
|
+ record.setGroupBuyImgUrl(imgUrlBuilder.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ List<LifeUserOrderCommentVo> lifeUserOrderCommentVos = commentOrderPage.getRecords();
|
|
|
+ if(CollectionUtils.isEmpty(lifeUserOrderCommentVos)){
|
|
|
+ return commentOrderPage;
|
|
|
+ }
|
|
|
+ List<String> orderIds = lifeUserOrderCommentVos.stream().map(LifeUserOrderCommentVo::getId).collect(Collectors.toList());
|
|
|
+ List<StoreComment> storeCommentList = storeCommentMapper.selectList(new QueryWrapper<StoreComment>().inSql("business_id", String.join(",", orderIds)).eq("business_type", 5));
|
|
|
+ if(CollectionUtils.isEmpty(storeCommentList)){
|
|
|
+ return commentOrderPage;
|
|
|
+ }
|
|
|
+ Map<Integer, StoreComment> commentIdToMap = storeCommentList.stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ StoreComment::getBusinessId,
|
|
|
+ Function.identity(),
|
|
|
+ (existing, replacement) -> existing // 若有重复id(理论上不会),保留第一个
|
|
|
+ ));
|
|
|
+ if(CollectionUtils.isEmpty(commentIdToMap)){
|
|
|
+ return commentOrderPage;
|
|
|
+ }
|
|
|
+ for(LifeUserOrderCommentVo lifeUserOrderCommentVo : commentOrderPage.getRecords()){
|
|
|
+ Integer orderId = Integer.parseInt(lifeUserOrderCommentVo.getId());
|
|
|
+
|
|
|
+ if(commentIdToMap.containsKey(orderId)){
|
|
|
+ StoreComment storeComment = commentIdToMap.get(orderId);
|
|
|
+ lifeUserOrderCommentVo.setScore(storeComment.getScore().toString());
|
|
|
+ lifeUserOrderCommentVo.setCommentDate(storeComment.getCreatedTime());
|
|
|
+ String imgIds = storeComment.getImgId();
|
|
|
+
|
|
|
+ if(StringUtils.isNotEmpty(imgIds)){
|
|
|
+ LambdaQueryWrapper<StoreImg> storeImgLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ List<String> imgIdList = Arrays.stream(imgIds.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ storeImgLambdaQueryWrapper.in(StoreImg::getId, imgIdList);
|
|
|
+ List<StoreImg> storeImgList = storeImgMapper.selectList(storeImgLambdaQueryWrapper);
|
|
|
+ if(CollectionUtils.isNotEmpty(storeImgList)){
|
|
|
+ List<String> imgUrlList = storeImgList.stream() // 转换为 Stream
|
|
|
+ .map(StoreImg::getImgUrl) // 映射,提取 name 字段
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ lifeUserOrderCommentVo.setImgUrls(imgUrlList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return commentOrderPage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取店铺评价计数统计
|
|
|
+ *
|
|
|
+ * @param storeId 门店id
|
|
|
+ * @return StoreCommentCountVo
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StoreCommentCountVo getAppraiseCount(Integer storeId) {
|
|
|
+ StoreCommentCountVo countVo = new StoreCommentCountVo();
|
|
|
+
|
|
|
+ // 查询条件:只统计当前门店、根评论(reply_id为null)、未删除的评论
|
|
|
+ LambdaQueryWrapper<StoreComment> totalWrapper = buildBaseStoreCommentWrapper(storeId);
|
|
|
+ countVo.setTotalCount(storeCommentMapper.selectCount(totalWrapper));
|
|
|
+
|
|
|
+ // 2. 有图评论数(img_id不为空且不为空字符串)
|
|
|
+ LambdaQueryWrapper<StoreComment> imageWrapper = buildBaseStoreCommentWrapper(storeId);
|
|
|
+ imageWrapper.isNotNull(StoreComment::getImgId)
|
|
|
+ .apply("img_id != ''");
|
|
|
+ countVo.setImageCount(storeCommentMapper.selectCount(imageWrapper));
|
|
|
+
|
|
|
+ // 3. 好评数(score >= 4.5)
|
|
|
+ LambdaQueryWrapper<StoreComment> goodWrapper = buildBaseStoreCommentWrapper(storeId);
|
|
|
+ goodWrapper.ge(StoreComment::getScore, 4.5);
|
|
|
+ countVo.setGoodCount(storeCommentMapper.selectCount(goodWrapper));
|
|
|
+
|
|
|
+ // 4. 中评数(score >= 3 && score <= 4)
|
|
|
+ LambdaQueryWrapper<StoreComment> midWrapper = buildBaseStoreCommentWrapper(storeId);
|
|
|
+ midWrapper.ge(StoreComment::getScore, 3.0)
|
|
|
+ .le(StoreComment::getScore, 4.0);
|
|
|
+ countVo.setMidCount(storeCommentMapper.selectCount(midWrapper));
|
|
|
+
|
|
|
+ // 5. 差评数(score >= 0.5 && score <= 2.5)
|
|
|
+ LambdaQueryWrapper<StoreComment> badWrapper = buildBaseStoreCommentWrapper(storeId);
|
|
|
+ badWrapper.ge(StoreComment::getScore, 0.5)
|
|
|
+ .le(StoreComment::getScore, 2.5);
|
|
|
+ countVo.setBadCount(storeCommentMapper.selectCount(badWrapper));
|
|
|
+
|
|
|
+ return countVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建当前门店根评论的查询条件
|
|
|
+ */
|
|
|
+ private LambdaQueryWrapper<StoreComment> buildBaseStoreCommentWrapper(Integer storeId) {
|
|
|
+ return new LambdaQueryWrapper<StoreComment>()
|
|
|
+ .eq(StoreComment::getStoreId, storeId)
|
|
|
+ .gt(StoreComment::getScore,0 )
|
|
|
+ .eq(StoreComment::getBusinessType, 5)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 订单评价相关方法实现(迁移自 OrderReviewService)====================
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<StoreComment> createOrderReview(OrderReviewDto reviewDto) {
|
|
|
+ log.info("StoreCommentServiceImpl.createOrderReview?reviewDto={}", reviewDto);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (reviewDto == null) {
|
|
|
+ return R.fail("评价信息不能为空");
|
|
|
+ }
|
|
|
+ if (reviewDto.getOrderId() == null) {
|
|
|
+ return R.fail("订单ID不能为空");
|
|
|
+ }
|
|
|
+ Integer userId = reviewDto.getUserId();
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证订单是否存在且属于该用户
|
|
|
+ LawyerConsultationOrder order = lawyerConsultationOrderMapper.selectById(reviewDto.getOrderId());
|
|
|
+ if (order == null) {
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+ if (!order.getClientUserId().equals(userId)) {
|
|
|
+ return R.fail("只能评价自己的订单");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查订单是否已完成
|
|
|
+ if (order.getOrderStatus() == null || order.getOrderStatus() != 3) {
|
|
|
+ return R.fail("只能对已完成的订单进行评价");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否已经评价过(使用 store_comment 表,business_type=5)
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getOrderId, reviewDto.getOrderId())
|
|
|
+ .eq(StoreComment::getBusinessType, 5)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0);
|
|
|
+ StoreComment existingReview = this.getOne(queryWrapper);
|
|
|
+ if (existingReview != null) {
|
|
|
+ return R.success("该订单已经评价过了");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建评价(使用 store_comment 表)
|
|
|
+ StoreComment review = new StoreComment();
|
|
|
+ review.setOrderId(reviewDto.getOrderId());
|
|
|
+ review.setLawyerId(order.getLawyerUserId());
|
|
|
+ review.setUserId(userId);
|
|
|
+ review.setCommentContent(reviewDto.getReviewContent());
|
|
|
+ review.setScore(reviewDto.getOverallRating());
|
|
|
+ review.setBusinessId(reviewDto.getOrderId()); // 订单ID作为业务ID
|
|
|
+ review.setBusinessType(5); // 订单评价
|
|
|
+ review.setIsAnonymous(reviewDto.getIsAnonymous() != null ? reviewDto.getIsAnonymous() : 0);
|
|
|
+ review.setLikeCount(0);
|
|
|
+
|
|
|
+ // 处理评价图片:将JSON数组转换为img_id(这里需要根据实际情况处理)
|
|
|
+ if (reviewDto.getReviewImages() != null && !reviewDto.getReviewImages().isEmpty()) {
|
|
|
+ // 注意:这里需要将图片URL上传并获取img_id,暂时先不处理
|
|
|
+ // review.setImgId(...);
|
|
|
+ }
|
|
|
+
|
|
|
+ review.setCreatedUserId(userId);
|
|
|
+ review.setCreatedTime(new Date());
|
|
|
+
|
|
|
+ boolean success = this.save(review);
|
|
|
+ if (success) {
|
|
|
+ log.info("创建评价成功,评价ID={}", review.getId());
|
|
|
+ // 更新律师评分
|
|
|
+ updateLawyerServiceScore(order.getLawyerUserId());
|
|
|
+ return R.data(review, "提交成功");
|
|
|
+ } else {
|
|
|
+ log.error("创建评价失败");
|
|
|
+ return R.fail("创建评价失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新律师服务评分和好评/中评/差评数量
|
|
|
+ */
|
|
|
+ private void updateLawyerServiceScore(Integer lawyerUserId) {
|
|
|
+ if (lawyerUserId == null) {
|
|
|
+ log.warn("更新律师评分失败:律师ID为空");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 从 store_comment 表计算平均评分(business_type=5)
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getLawyerId, lawyerUserId)
|
|
|
+ .eq(StoreComment::getBusinessType, 5)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0)
|
|
|
+ .isNotNull(StoreComment::getScore);
|
|
|
+ List<StoreComment> reviews = this.list(queryWrapper);
|
|
|
+
|
|
|
+ Double averageRating = null;
|
|
|
+ if (!reviews.isEmpty()) {
|
|
|
+ double sum = reviews.stream()
|
|
|
+ .filter(r -> r.getScore() != null)
|
|
|
+ .mapToDouble(StoreComment::getScore)
|
|
|
+ .sum();
|
|
|
+ averageRating = sum / reviews.size();
|
|
|
+ }
|
|
|
+
|
|
|
+ Double serviceScore;
|
|
|
+ if (averageRating != null) {
|
|
|
+ serviceScore = Math.floor(averageRating * 10.0) / 10.0;
|
|
|
+ serviceScore = Math.max(0.0, Math.min(5.0, serviceScore));
|
|
|
+ } else {
|
|
|
+ serviceScore = 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计好评、中评、差评数量
|
|
|
+ long goodCount = reviews.stream()
|
|
|
+ .filter(r -> r.getScore() != null && r.getScore() >= 4.5 && r.getScore() <= 5)
|
|
|
+ .count();
|
|
|
+ long mediumCount = reviews.stream()
|
|
|
+ .filter(r -> r.getScore() != null && r.getScore() >= 3.0 && r.getScore() < 4.5)
|
|
|
+ .count();
|
|
|
+ long badCount = reviews.stream()
|
|
|
+ .filter(r -> r.getScore() != null && r.getScore() >= 0.5 && r.getScore() < 3.0)
|
|
|
+ .count();
|
|
|
+
|
|
|
+ // 更新律师评分
|
|
|
+ LambdaUpdateWrapper<LawyerUser> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(LawyerUser::getId, lawyerUserId);
|
|
|
+ updateWrapper.set(LawyerUser::getServiceScore, serviceScore);
|
|
|
+ updateWrapper.set(LawyerUser::getGoodReviewCount, (int) goodCount);
|
|
|
+ updateWrapper.set(LawyerUser::getMediumReviewCount, (int) mediumCount);
|
|
|
+ updateWrapper.set(LawyerUser::getBadReviewCount, (int) badCount);
|
|
|
+ int result = lawyerUserMapper.update(null, updateWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ log.info("更新律师评分成功,律师ID={}, 平均评分={}, 服务评分={}, 好评数={}, 中评数={}, 差评数={}",
|
|
|
+ lawyerUserId, averageRating, serviceScore, goodCount, mediumCount, badCount);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("更新律师评分异常,律师ID={}, 错误信息={}", lawyerUserId, e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<OrderReviewDetailVo> getOrderReviewDetail(Integer reviewId, Integer currentUserId) {
|
|
|
+ log.info("StoreCommentServiceImpl.getOrderReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
|
|
|
+
|
|
|
+ if (reviewId == null) {
|
|
|
+ return R.fail("评价ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询评价详情(从 store_comment 表,business_type=5)
|
|
|
+ StoreComment review = this.getById(reviewId);
|
|
|
+ if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
|
|
|
+ return R.fail("评价不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建 OrderReviewDetailVo(需要关联用户和律师信息)
|
|
|
+ OrderReviewDetailVo detailVo = new OrderReviewDetailVo();
|
|
|
+ // TODO: 需要从 store_comment 查询并关联用户、律师信息,构建完整的 OrderReviewDetailVo
|
|
|
+ // 这里需要根据实际的查询需求来实现,可能需要自定义SQL查询
|
|
|
+
|
|
|
+ // 查询评论列表(business_type=6,business_id=reviewId)
|
|
|
+ R<List<ReviewCommentVo>> commentsResult = getReviewCommentListByReviewId(reviewId, currentUserId);
|
|
|
+ if (commentsResult.getCode() == 200) {
|
|
|
+ detailVo.setComments(commentsResult.getData());
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data(detailVo);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> likeOrderReview(Integer reviewId, Integer userId) {
|
|
|
+ log.info("StoreCommentServiceImpl.likeOrderReview?reviewId={}, userId={}", reviewId, userId);
|
|
|
+
|
|
|
+ // 验证评价是否存在
|
|
|
+ StoreComment review = this.getById(reviewId);
|
|
|
+ if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
|
|
|
+ return R.fail("评价不存在或已删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否已点赞(type=7 表示订单评价点赞)
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeLikeRecord::getType, "7")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(reviewId))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 插入点赞记录
|
|
|
+ LifeLikeRecord likeRecord = new LifeLikeRecord();
|
|
|
+ likeRecord.setDianzanId(String.valueOf(userId));
|
|
|
+ likeRecord.setHuifuId(String.valueOf(reviewId));
|
|
|
+ likeRecord.setType("7");
|
|
|
+ likeRecord.setCreatedTime(new Date());
|
|
|
+ likeRecord.setCreatedUserId(userId);
|
|
|
+ lifeLikeRecordMapper.insert(likeRecord);
|
|
|
+
|
|
|
+ // 更新评价点赞数
|
|
|
+ LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(StoreComment::getId, reviewId);
|
|
|
+ updateWrapper.setSql("like_count = like_count + 1");
|
|
|
+ int result = storeCommentMapper.update(null, updateWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ return R.data(true, "点赞成功");
|
|
|
+ } else {
|
|
|
+ return R.fail("点赞失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return R.data(true, "已点赞");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> cancelLikeOrderReview(Integer reviewId, Integer userId) {
|
|
|
+ log.info("StoreCommentServiceImpl.cancelLikeOrderReview?reviewId={}, userId={}", reviewId, userId);
|
|
|
+
|
|
|
+ // 查询点赞记录
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeLikeRecord::getType, "7")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(reviewId))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ if (!CollectionUtils.isEmpty(records)) {
|
|
|
+ // 删除点赞记录(逻辑删除)
|
|
|
+ for (LifeLikeRecord record : records) {
|
|
|
+ lifeLikeRecordMapper.deleteById(record.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新评价点赞数
|
|
|
+ LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(StoreComment::getId, reviewId);
|
|
|
+ updateWrapper.setSql("like_count = GREATEST(0, like_count - 1)");
|
|
|
+ int result = storeCommentMapper.update(null, updateWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ return R.data(true, "取消点赞成功");
|
|
|
+ } else {
|
|
|
+ return R.fail("取消点赞失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return R.data(true, "未点赞");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<IPage<OrderReviewVo>> getOrderReviewList(int page, int size, Integer orderId, Integer lawyerUserId, Integer userId, Integer currentUserId) {
|
|
|
+ log.info("StoreCommentServiceImpl.getOrderReviewList?page={}, size={}, orderId={}, lawyerUserId={}, userId={}, currentUserId={}",
|
|
|
+ page, size, orderId, lawyerUserId, userId, currentUserId);
|
|
|
+
|
|
|
+ // 构建查询条件
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getBusinessType, 5)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0);
|
|
|
+
|
|
|
+ if (orderId != null) {
|
|
|
+ queryWrapper.eq(StoreComment::getOrderId, orderId);
|
|
|
+ }
|
|
|
+ if (lawyerUserId != null) {
|
|
|
+ queryWrapper.eq(StoreComment::getLawyerId, lawyerUserId);
|
|
|
+ }
|
|
|
+ if (userId != null) {
|
|
|
+ queryWrapper.eq(StoreComment::getUserId, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ queryWrapper.orderByDesc(StoreComment::getCreatedTime);
|
|
|
+
|
|
|
+ // 分页查询
|
|
|
+ Page<StoreComment> pageObj = new Page<>(page, size);
|
|
|
+ IPage<StoreComment> commentPage = this.page(pageObj, queryWrapper);
|
|
|
+
|
|
|
+ // 转换为 OrderReviewVo(需要关联用户和律师信息)
|
|
|
+ // TODO: 需要自定义查询或手动构建 OrderReviewVo,关联用户和律师信息
|
|
|
+ Page<OrderReviewVo> resultPage = new Page<>(page, size);
|
|
|
+ resultPage.setTotal(commentPage.getTotal());
|
|
|
+ resultPage.setPages(commentPage.getPages());
|
|
|
+
|
|
|
+ List<OrderReviewVo> voList = new ArrayList<>();
|
|
|
+ for (StoreComment comment : commentPage.getRecords()) {
|
|
|
+ OrderReviewVo vo = new OrderReviewVo();
|
|
|
+ vo.setId(comment.getId());
|
|
|
+ vo.setOrderId(comment.getOrderId());
|
|
|
+ vo.setUserId(comment.getUserId());
|
|
|
+ vo.setLawyerUserId(comment.getLawyerId());
|
|
|
+ vo.setOverallRating(comment.getScore());
|
|
|
+ vo.setReviewContent(comment.getCommentContent());
|
|
|
+ vo.setIsAnonymous(comment.getIsAnonymous());
|
|
|
+ vo.setLikeCount(comment.getLikeCount());
|
|
|
+ vo.setCreatedTime(comment.getCreatedTime());
|
|
|
+ // TODO: 需要查询并设置用户名称、头像、律师信息等
|
|
|
+ voList.add(vo);
|
|
|
+ }
|
|
|
+ resultPage.setRecords(voList);
|
|
|
+
|
|
|
+ return R.data(resultPage);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<OrderReviewVo> getOrderReviewByOrderId(Integer orderId, Integer currentUserId) {
|
|
|
+ log.info("StoreCommentServiceImpl.getOrderReviewByOrderId?orderId={}, currentUserId={}", orderId, currentUserId);
|
|
|
+
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getOrderId, orderId)
|
|
|
+ .eq(StoreComment::getBusinessType, 5)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0)
|
|
|
+ .orderByDesc(StoreComment::getCreatedTime)
|
|
|
+ .last("LIMIT 1");
|
|
|
+
|
|
|
+ StoreComment comment = this.getOne(queryWrapper);
|
|
|
+ if (comment == null) {
|
|
|
+ return R.fail("评价不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换为 OrderReviewVo
|
|
|
+ OrderReviewVo vo = new OrderReviewVo();
|
|
|
+ vo.setId(comment.getId());
|
|
|
+ vo.setOrderId(comment.getOrderId());
|
|
|
+ vo.setUserId(comment.getUserId());
|
|
|
+ vo.setLawyerUserId(comment.getLawyerId());
|
|
|
+ vo.setOverallRating(comment.getScore());
|
|
|
+ vo.setReviewContent(comment.getCommentContent());
|
|
|
+ vo.setIsAnonymous(comment.getIsAnonymous());
|
|
|
+ vo.setLikeCount(comment.getLikeCount());
|
|
|
+ vo.setCreatedTime(comment.getCreatedTime());
|
|
|
+ // TODO: 需要查询并设置用户名称、头像、律师信息等
|
|
|
+
|
|
|
+ return R.data(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 评价评论相关方法实现(迁移自 ReviewCommentService)====================
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<StoreComment> createReviewComment(StoreComment comment) {
|
|
|
+ log.info("StoreCommentServiceImpl.createReviewComment?comment={}", comment);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (comment == null) {
|
|
|
+ return R.fail("评论信息不能为空");
|
|
|
+ }
|
|
|
+ if (comment.getBusinessId() == null) {
|
|
|
+ return R.fail("评价ID不能为空");
|
|
|
+ }
|
|
|
+ if (comment.getCommentContent() == null || comment.getCommentContent().trim().isEmpty()) {
|
|
|
+ return R.fail("评论内容不能为空");
|
|
|
+ }
|
|
|
+ Integer userId = comment.getUserId();
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证评价是否存在(business_type=5)
|
|
|
+ StoreComment review = this.getById(comment.getBusinessId());
|
|
|
+ if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
|
|
|
+ return R.fail("评价不存在或已删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置评论属性
|
|
|
+ comment.setBusinessType(6); // 订单评价的评论
|
|
|
+ comment.setBusinessId(review.getId()); // 评价ID作为业务ID
|
|
|
+ comment.setOrderId(review.getOrderId()); // 从评价中获取订单ID
|
|
|
+ comment.setLawyerId(review.getLawyerId()); // 从评价中获取律师ID
|
|
|
+ comment.setLikeCount(0);
|
|
|
+ comment.setReplyId(null); // 首评没有reply_id
|
|
|
+ comment.setCreatedUserId(userId);
|
|
|
+ comment.setCreatedTime(new Date());
|
|
|
+
|
|
|
+ boolean success = this.save(comment);
|
|
|
+ if (success) {
|
|
|
+ log.info("创建评论成功,评论ID={}", comment.getId());
|
|
|
+ return R.data(comment, "评论成功");
|
|
|
+ } else {
|
|
|
+ log.error("创建评论失败");
|
|
|
+ return R.fail("创建评论失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<List<ReviewCommentVo>> getReviewCommentListByReviewId(Integer reviewId, Integer currentUserId) {
|
|
|
+ log.info("StoreCommentServiceImpl.getReviewCommentListByReviewId?reviewId={}, currentUserId={}", reviewId, currentUserId);
|
|
|
+
|
|
|
+ if (reviewId == null) {
|
|
|
+ return R.fail("评价ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询评论列表(business_type=6,business_id=reviewId,reply_id为null表示首评)
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getBusinessId, reviewId)
|
|
|
+ .eq(StoreComment::getBusinessType, 6)
|
|
|
+ .isNull(StoreComment::getReplyId) // 首评
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0)
|
|
|
+ .orderByDesc(StoreComment::getCreatedTime);
|
|
|
+
|
|
|
+ List<StoreComment> comments = this.list(queryWrapper);
|
|
|
+
|
|
|
+ // 转换为 ReviewCommentVo 并加载回复列表
|
|
|
+ List<ReviewCommentVo> voList = new ArrayList<>();
|
|
|
+ for (StoreComment comment : comments) {
|
|
|
+ ReviewCommentVo vo = new ReviewCommentVo();
|
|
|
+ vo.setId(comment.getId());
|
|
|
+ vo.setReviewId(comment.getBusinessId());
|
|
|
+ vo.setSendUserId(comment.getUserId());
|
|
|
+ vo.setCommentContent(comment.getCommentContent());
|
|
|
+ vo.setLikeCount(comment.getLikeCount());
|
|
|
+ vo.setCreatedTime(comment.getCreatedTime());
|
|
|
+ // TODO: 需要查询并设置用户名称、头像等
|
|
|
+
|
|
|
+ // 检查是否已点赞
|
|
|
+ if (currentUserId != null) {
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> likeWrapper = new LambdaQueryWrapper<>();
|
|
|
+ likeWrapper.eq(LifeLikeRecord::getType, "8")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(currentUserId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(comment.getId()))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ vo.setIsLiked(lifeLikeRecordMapper.selectCount(likeWrapper) > 0 ? 1 : 0);
|
|
|
+ } else {
|
|
|
+ vo.setIsLiked(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询回复列表
|
|
|
+ R<List<ReviewCommentVo>> repliesResult = getReviewReplyListByHeadId(comment.getId(), currentUserId);
|
|
|
+ if (repliesResult.getCode() == 200) {
|
|
|
+ vo.setReplies(repliesResult.getData());
|
|
|
+ }
|
|
|
+
|
|
|
+ voList.add(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data(voList);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> likeReviewComment(ReviewCommentRequestDto requestDto) {
|
|
|
+ log.info("StoreCommentServiceImpl.likeReviewComment?requestDto={}", requestDto);
|
|
|
+
|
|
|
+ Integer commentId = requestDto.getCommentId();
|
|
|
+ Integer userId = requestDto.getUserId();
|
|
|
+
|
|
|
+ if (commentId == null) {
|
|
|
+ return R.fail("评论ID不能为空");
|
|
|
+ }
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证评论是否存在
|
|
|
+ StoreComment comment = this.getById(commentId);
|
|
|
+ if (comment == null || comment.getDeleteFlag() == 1 || comment.getBusinessType() != 6) {
|
|
|
+ return R.fail("评论不存在或已删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否已点赞(type=8 表示评论点赞)
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeLikeRecord::getType, "8")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(commentId))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 插入点赞记录
|
|
|
+ LifeLikeRecord likeRecord = new LifeLikeRecord();
|
|
|
+ likeRecord.setDianzanId(String.valueOf(userId));
|
|
|
+ likeRecord.setHuifuId(String.valueOf(commentId));
|
|
|
+ likeRecord.setType("8");
|
|
|
+ likeRecord.setCreatedTime(new Date());
|
|
|
+ likeRecord.setCreatedUserId(userId);
|
|
|
+ lifeLikeRecordMapper.insert(likeRecord);
|
|
|
+
|
|
|
+ // 更新评论点赞数
|
|
|
+ LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(StoreComment::getId, commentId);
|
|
|
+ updateWrapper.setSql("like_count = like_count + 1");
|
|
|
+ int result = storeCommentMapper.update(null, updateWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ return R.data(true, "点赞成功");
|
|
|
+ } else {
|
|
|
+ return R.fail("点赞失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return R.data(true, "已点赞");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> cancelLikeReviewComment(ReviewCommentRequestDto requestDto) {
|
|
|
+ log.info("StoreCommentServiceImpl.cancelLikeReviewComment?requestDto={}", requestDto);
|
|
|
+
|
|
|
+ Integer commentId = requestDto.getCommentId();
|
|
|
+ Integer userId = requestDto.getUserId();
|
|
|
+ if (commentId == null) {
|
|
|
+ return R.fail("评论ID不能为空");
|
|
|
+ }
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询点赞记录
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeLikeRecord::getType, "8")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(commentId))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ if (!CollectionUtils.isEmpty(records)) {
|
|
|
+ // 删除点赞记录(逻辑删除)
|
|
|
+ for (LifeLikeRecord record : records) {
|
|
|
+ lifeLikeRecordMapper.deleteById(record.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新评论点赞数
|
|
|
+ LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(StoreComment::getId, commentId);
|
|
|
+ updateWrapper.setSql("like_count = GREATEST(0, like_count - 1)");
|
|
|
+ int result = storeCommentMapper.update(null, updateWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ return R.data(true, "取消点赞成功");
|
|
|
+ } else {
|
|
|
+ return R.fail("取消点赞失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return R.data(true, "未点赞");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<StoreComment> createReviewReply(ReviewReplyDto replyDto) {
|
|
|
+ log.info("StoreCommentServiceImpl.createReviewReply?replyDto={}", replyDto);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (replyDto == null) {
|
|
|
+ return R.fail("回复信息不能为空");
|
|
|
+ }
|
|
|
+ if (replyDto.getCommentId() == null) {
|
|
|
+ return R.fail("评论ID不能为空");
|
|
|
+ }
|
|
|
+ if (replyDto.getReplyContent() == null || replyDto.getReplyContent().trim().isEmpty()) {
|
|
|
+ return R.fail("回复内容不能为空");
|
|
|
+ }
|
|
|
+ Integer userId = replyDto.getUserId();
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证首评是否存在
|
|
|
+ StoreComment headComment = this.getById(replyDto.getCommentId());
|
|
|
+ if (headComment == null || headComment.getDeleteFlag() == 1 || headComment.getBusinessType() != 6) {
|
|
|
+ return R.fail("评论不存在或已删除");
|
|
|
+ }
|
|
|
+ // 验证是否为首评(reply_id为null表示首评)
|
|
|
+ if (headComment.getReplyId() != null) {
|
|
|
+ return R.fail("只能回复首评");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建回复
|
|
|
+ StoreComment reply = new StoreComment();
|
|
|
+ reply.setBusinessId(headComment.getBusinessId()); // 评价ID
|
|
|
+ reply.setBusinessType(6); // 订单评价的评论
|
|
|
+ reply.setUserId(userId);
|
|
|
+ reply.setCommentContent(replyDto.getReplyContent());
|
|
|
+ reply.setOrderId(headComment.getOrderId());
|
|
|
+ reply.setLawyerId(headComment.getLawyerId());
|
|
|
+ reply.setReplyId(replyDto.getCommentId()); // 指向首评ID
|
|
|
+ reply.setLikeCount(0);
|
|
|
+ reply.setCreatedUserId(userId);
|
|
|
+ reply.setCreatedTime(new Date());
|
|
|
+
|
|
|
+ boolean success = this.save(reply);
|
|
|
+ if (success) {
|
|
|
+ log.info("创建回复成功,回复ID={}", reply.getId());
|
|
|
+ return R.data(reply, "回复成功");
|
|
|
+ } else {
|
|
|
+ log.error("创建回复失败");
|
|
|
+ return R.fail("创建回复失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<List<ReviewCommentVo>> getReviewReplyListByHeadId(Integer headId, Integer currentUserId) {
|
|
|
+ log.info("StoreCommentServiceImpl.getReviewReplyListByHeadId?headId={}, currentUserId={}", headId, currentUserId);
|
|
|
+
|
|
|
+ if (headId == null) {
|
|
|
+ return R.fail("首评ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询回复列表(business_type=6,reply_id=headId)
|
|
|
+ LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(StoreComment::getReplyId, headId)
|
|
|
+ .eq(StoreComment::getBusinessType, 6)
|
|
|
+ .eq(StoreComment::getDeleteFlag, 0)
|
|
|
+ .orderByAsc(StoreComment::getCreatedTime);
|
|
|
+
|
|
|
+ List<StoreComment> replies = this.list(queryWrapper);
|
|
|
+
|
|
|
+ // 转换为 ReviewCommentVo
|
|
|
+ List<ReviewCommentVo> voList = new ArrayList<>();
|
|
|
+ for (StoreComment reply : replies) {
|
|
|
+ ReviewCommentVo vo = new ReviewCommentVo();
|
|
|
+ vo.setId(reply.getId());
|
|
|
+ vo.setReviewId(reply.getBusinessId());
|
|
|
+ vo.setSendUserId(reply.getUserId());
|
|
|
+ vo.setCommentContent(reply.getCommentContent());
|
|
|
+ vo.setLikeCount(reply.getLikeCount());
|
|
|
+ vo.setCreatedTime(reply.getCreatedTime());
|
|
|
+ // TODO: 需要查询并设置用户名称、头像等
|
|
|
+
|
|
|
+ // 检查是否已点赞
|
|
|
+ if (currentUserId != null) {
|
|
|
+ LambdaQueryWrapper<LifeLikeRecord> likeWrapper = new LambdaQueryWrapper<>();
|
|
|
+ likeWrapper.eq(LifeLikeRecord::getType, "8")
|
|
|
+ .eq(LifeLikeRecord::getDianzanId, String.valueOf(currentUserId))
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(reply.getId()))
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
+ vo.setIsLiked(lifeLikeRecordMapper.selectCount(likeWrapper) > 0 ? 1 : 0);
|
|
|
+ } else {
|
|
|
+ vo.setIsLiked(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ voList.add(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data(voList);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> deleteReviewReply(Integer replyId, Integer userId) {
|
|
|
+ log.info("StoreCommentServiceImpl.deleteReviewReply?replyId={}, userId={}", replyId, userId);
|
|
|
+
|
|
|
+ if (replyId == null) {
|
|
|
+ return R.fail("回复ID不能为空");
|
|
|
+ }
|
|
|
+ if (userId == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询回复
|
|
|
+ StoreComment reply = this.getById(replyId);
|
|
|
+ if (reply == null) {
|
|
|
+ return R.fail("回复不存在");
|
|
|
+ }
|
|
|
+ if (reply.getReplyId() == null) {
|
|
|
+ return R.fail("该记录不是回复");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证是否为回复用户
|
|
|
+ if (!reply.getUserId().equals(userId)) {
|
|
|
+ return R.fail("只能删除自己的回复");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除回复(逻辑删除)
|
|
|
+ boolean success = this.removeById(reply.getId());
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ log.info("删除回复成功,回复ID={}", replyId);
|
|
|
+ return R.data(true, "删除成功");
|
|
|
+ } else {
|
|
|
+ log.error("删除回复失败,回复ID={}", replyId);
|
|
|
+ return R.fail("删除回复失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|