|
@@ -0,0 +1,499 @@
|
|
|
|
|
+package shop.alien.store.service;
|
|
|
|
|
+
|
|
|
|
|
+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 lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.collections4.map.HashedMap;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
+import org.springframework.http.HttpEntity;
|
|
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
|
|
+import org.springframework.http.MediaType;
|
|
|
|
|
+import org.springframework.http.ResponseEntity;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.util.LinkedMultiValueMap;
|
|
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
|
|
+import shop.alien.entity.result.R;
|
|
|
|
|
+import shop.alien.entity.store.*;
|
|
|
|
|
+import shop.alien.mapper.*;
|
|
|
|
|
+import shop.alien.util.common.constant.CommentSourceTypeEnum;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 评论申诉-用户补充 AI 分析任务服务
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class StoreCommentAppealSupplementJobService {
|
|
|
|
|
+
|
|
|
|
|
+ private final RestTemplate restTemplate;
|
|
|
|
|
+ private final StoreCommentAppealMapper storeCommentAppealMapper;
|
|
|
|
|
+ private final StoreCommentAppealSupplementMapper storeCommentAppealSupplementMapper;
|
|
|
|
|
+ private final StoreUserMapper storeUserMapper;
|
|
|
|
|
+ private final LifeUserMapper lifeUserMapper;
|
|
|
|
|
+ private final LifeNoticeMapper lifeNoticeMapper;
|
|
|
|
|
+ private final CommonRatingMapper commonRatingMapper;
|
|
|
|
|
+ private final CommonCommentMapper commonCommentMapper;
|
|
|
|
|
+ private final LifeLikeRecordMapper lifeLikeRecordMapper;
|
|
|
|
|
+ private final StoreInfoMapper storeInfoMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${third-party-user-name.base-url}")
|
|
|
|
|
+ private String userName;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${third-party-pass-word.base-url}")
|
|
|
|
|
+ private String passWord;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${third-party-login.base-url}")
|
|
|
|
|
+ private String loginUrl;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${third-party-ai-analyze.base-url}")
|
|
|
|
|
+ private String analyzeUrl;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${third-party-ai-resultUrl.base-url}")
|
|
|
|
|
+ private String resultUrl;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 提交待处理申诉至 AI 分析
|
|
|
|
|
+ */
|
|
|
|
|
+ public R<String> submitAppealAnalyze() {
|
|
|
|
|
+ log.info("【用户补充申诉】开始执行 AI 差评申诉分析提交任务");
|
|
|
|
|
+ return invokeAnalyzeTask();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 轮询 AI 分析完成结果
|
|
|
|
|
+ */
|
|
|
|
|
+ public R<String> pollCompletedResult() {
|
|
|
|
|
+ log.info("【用户补充申诉】开始查询 AI 分析结果");
|
|
|
|
|
+ return pollAppealCompletedResult();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private R<String> pollAppealCompletedResult() {
|
|
|
|
|
+ List<StoreCommentAppeal> pendingAppeals = storeCommentAppealMapper.getSupplementPendingAppeals();
|
|
|
|
|
+ if (pendingAppeals == null || pendingAppeals.isEmpty()) {
|
|
|
|
|
+ log.info("【用户补充申诉】没有待轮询的分析结果");
|
|
|
|
|
+ return R.success("没有待轮询的分析结果");
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("【用户补充申诉】本次轮询申述数量(上限10条): {}", pendingAppeals.size());
|
|
|
|
|
+
|
|
|
|
|
+ RestTemplate restTemplateWithAuth = new RestTemplate();
|
|
|
|
|
+
|
|
|
|
|
+ for (StoreCommentAppeal appeal : pendingAppeals) {
|
|
|
|
|
+ String completedUrl = buildCompletedUrl(appeal.getRecordId());
|
|
|
|
|
+ try {
|
|
|
|
|
+ ResponseEntity<String> analyzeResp = restTemplateWithAuth.getForEntity(completedUrl, String.class);
|
|
|
|
|
+ if (analyzeResp == null || analyzeResp.getStatusCodeValue() != 200) {
|
|
|
|
|
+ if (analyzeResp != null) {
|
|
|
|
|
+ log.error("【用户补充申诉】查询分析结果失败, http状态: {}", analyzeResp.getStatusCode());
|
|
|
|
|
+ }
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String analyzeBody = analyzeResp.getBody();
|
|
|
|
|
+ log.info("【用户补充申诉】查询分析结果, 申诉ID: {}, 返回: {}", appeal.getId(), analyzeBody);
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
|
|
|
|
|
+ Integer respCode = analyzeJson.getInteger("code");
|
|
|
|
|
+ JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
|
|
|
|
|
+
|
|
|
|
|
+ if (respCode != null && respCode == 202) {
|
|
|
|
|
+ JSONObject detailsObj = analyzeJson.getJSONObject("details");
|
|
|
|
|
+ String status = detailsObj != null ? detailsObj.getString("analysis_status") : "unknown";
|
|
|
|
|
+ log.info("【用户补充申诉】分析尚未完成(code=202),申诉ID: {},recordId: {},状态: {}",
|
|
|
|
|
+ appeal.getId(), appeal.getRecordId(), status);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (respCode == null || respCode != 200) {
|
|
|
|
|
+ log.warn("【用户补充申诉】分析返回非200,申诉ID: {},code: {},message: {}",
|
|
|
|
|
+ appeal.getId(), respCode, analyzeJson.getString("message"));
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (dataJsonObj == null) {
|
|
|
|
|
+ log.error("【用户补充申诉】分析返回数据为空,申诉ID: {}", appeal.getId());
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String analysisStatus = dataJsonObj.getString("analysis_status");
|
|
|
|
|
+ if (!"completed".equals(analysisStatus)) {
|
|
|
|
|
+ log.info("【用户补充申诉】分析尚未完成,申诉ID: {},recordId: {},状态: {}",
|
|
|
|
|
+ appeal.getId(), appeal.getRecordId(), analysisStatus);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Double userConfidence = dataJsonObj.getDouble("user_confidence");
|
|
|
|
|
+ Double merchantConfidence = dataJsonObj.getDouble("merchant_confidence");
|
|
|
|
|
+ if (userConfidence == null || merchantConfidence == null) {
|
|
|
|
|
+ log.error("【用户补充申诉】置信度为空,申诉ID: {},user_confidence: {},merchant_confidence: {}",
|
|
|
|
|
+ appeal.getId(), userConfidence, merchantConfidence);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("【用户补充申诉】分析结果,申诉ID: {},user_confidence: {},merchant_confidence: {}",
|
|
|
|
|
+ appeal.getId(), userConfidence, merchantConfidence);
|
|
|
|
|
+
|
|
|
|
|
+ StoreCommentAppeal updateAppeal = new StoreCommentAppeal();
|
|
|
|
|
+ updateAppeal.setRecordId(appeal.getRecordId());
|
|
|
|
|
+ updateAppeal.setAppealAiApproval(dataJsonObj.toJSONString());
|
|
|
|
|
+
|
|
|
|
|
+ if (merchantConfidence > userConfidence) {
|
|
|
|
|
+ updateAppeal.setAppealStatus(2);
|
|
|
|
|
+ updateAppeal.setFinalResult("已同意");
|
|
|
|
|
+ log.info("【用户补充申诉】商家赢,申诉通过,申诉ID: {}", appeal.getId());
|
|
|
|
|
+ Integer ratingId = appeal.getCommentId();
|
|
|
|
|
+ if (ratingId != null) {
|
|
|
|
|
+ deleteRatingAndComments(ratingId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ updateAppeal.setAppealStatus(1);
|
|
|
|
|
+ updateAppeal.setFinalResult("已驳回");
|
|
|
|
|
+ log.info("【用户补充申诉】用户赢,申诉驳回,申诉ID: {}", appeal.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ storeCommentAppealMapper.updateByRecordId(appeal.getRecordId(),
|
|
|
|
|
+ updateAppeal.getAppealStatus(), updateAppeal.getFinalResult());
|
|
|
|
|
+ boolean merchantWins = merchantConfidence > userConfidence;
|
|
|
|
|
+ sendAppealResultNotifications(appeal, merchantWins);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】查询分析结果异常,申诉ID: {}", appeal.getId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return R.success("【用户补充申诉】查询 AI 分析结果完成");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void sendAppealResultNotifications(StoreCommentAppeal appeal, boolean merchantWins) {
|
|
|
|
|
+ sendAppealResultNoticeToUser(appeal, merchantWins);
|
|
|
|
|
+ sendAppealResultNoticeToStore(appeal, merchantWins);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void sendAppealResultNoticeToUser(StoreCommentAppeal appeal, boolean merchantWins) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ CommonRating rating = commonRatingMapper.selectById(appeal.getCommentId());
|
|
|
|
|
+ if (rating == null || rating.getUserId() == null) {
|
|
|
|
|
+ log.warn("【用户补充申诉】用户通知跳过:评价不存在或无用户,appealId={}", appeal.getId());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectById(rating.getUserId().intValue());
|
|
|
|
|
+ if (lifeUser == null || !StringUtils.hasText(lifeUser.getUserPhone())) {
|
|
|
|
|
+ log.warn("【用户补充申诉】用户通知跳过:用户不存在或手机号为空,appealId={}", appeal.getId());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String message = merchantWins
|
|
|
|
|
+ ? "商家对你的评价申诉已通过审核,该条评价已删除。"
|
|
|
|
|
+ : "商家对你的评价申诉未通过审核,你的评价将继续展示。";
|
|
|
|
|
+
|
|
|
|
|
+ String receiverId = "user_" + lifeUser.getUserPhone();
|
|
|
|
|
+ JSONObject contextJson = new JSONObject();
|
|
|
|
|
+ contextJson.put("message", message);
|
|
|
|
|
+ contextJson.put("appealId", appeal.getId());
|
|
|
|
|
+ contextJson.put("commentId", appeal.getCommentId());
|
|
|
|
|
+ insertSystemNotice(receiverId, appeal.getId(), "商家申诉通知", contextJson.toJSONString());
|
|
|
|
|
+ log.info("【用户补充申诉】用户申诉结果通知发送成功,appealId={}, merchantWins={}", appeal.getId(), merchantWins);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】用户申诉结果通知发送失败,appealId={}", appeal.getId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void sendAppealResultNoticeToStore(StoreCommentAppeal appeal, boolean merchantWins) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ StoreUser storeUser = storeUserMapper.selectOne(
|
|
|
|
|
+ new QueryWrapper<StoreUser>().eq("store_id", appeal.getStoreId()).eq("delete_flag", 0));
|
|
|
|
|
+ if (storeUser == null || !StringUtils.hasText(storeUser.getPhone())) {
|
|
|
|
|
+ log.warn("【用户补充申诉】商家通知跳过:未找到店铺用户,appealId={}", appeal.getId());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ CommonRating rating = commonRatingMapper.selectById(appeal.getCommentId());
|
|
|
|
|
+ LifeUser ratingUser = null;
|
|
|
|
|
+ if (rating != null && rating.getUserId() != null) {
|
|
|
|
|
+ ratingUser = lifeUserMapper.selectById(rating.getUserId().intValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ String maskedNickName = desensitizeUserNickName(rating, ratingUser);
|
|
|
|
|
+
|
|
|
|
|
+ String message = merchantWins
|
|
|
|
|
+ ? "你对 " + maskedNickName + " 的评价申诉已通过,该评价已下架。"
|
|
|
|
|
+ : "你对 " + maskedNickName + " 的评价申诉未通过,评价将继续展示。";
|
|
|
|
|
+
|
|
|
|
|
+ String receiverId = "store_" + storeUser.getPhone();
|
|
|
|
|
+ JSONObject contextJson = new JSONObject();
|
|
|
|
|
+ contextJson.put("message", message);
|
|
|
|
|
+ contextJson.put("appealId", appeal.getId());
|
|
|
|
|
+ contextJson.put("commentId", appeal.getCommentId());
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ String title = merchantWins
|
|
|
|
|
+ ? "申诉通过"
|
|
|
|
|
+ : "申诉驳回";
|
|
|
|
|
+
|
|
|
|
|
+ insertSystemNotice(receiverId, appeal.getId(), title, contextJson.toJSONString());
|
|
|
|
|
+ log.info("【用户补充申诉】商家申诉结果通知发送成功,appealId={}, merchantWins={}", appeal.getId(), merchantWins);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】商家申诉结果通知发送失败,appealId={}", appeal.getId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void insertSystemNotice(String receiverId, Integer businessId, String title, String context) {
|
|
|
|
|
+ LifeNotice lifeNotice = new LifeNotice();
|
|
|
|
|
+ lifeNotice.setSenderId("system");
|
|
|
|
|
+ lifeNotice.setReceiverId(receiverId);
|
|
|
|
|
+ lifeNotice.setBusinessId(businessId);
|
|
|
|
|
+ lifeNotice.setTitle(title);
|
|
|
|
|
+ lifeNotice.setContext(context);
|
|
|
|
|
+ lifeNotice.setNoticeType(1);
|
|
|
|
|
+ lifeNotice.setIsRead(0);
|
|
|
|
|
+ lifeNoticeMapper.insert(lifeNotice);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String desensitizeUserNickName(CommonRating rating, LifeUser lifeUser) {
|
|
|
|
|
+ if (rating != null && rating.getIsAnonymous() != null && rating.getIsAnonymous() == 1) {
|
|
|
|
|
+ return "匿名用户";
|
|
|
|
|
+ }
|
|
|
|
|
+ String nick = lifeUser != null ? lifeUser.getUserName() : null;
|
|
|
|
|
+ if (!StringUtils.hasText(nick)) {
|
|
|
|
|
+ return "用户";
|
|
|
|
|
+ }
|
|
|
|
|
+ nick = nick.trim();
|
|
|
|
|
+ if (nick.length() == 1) {
|
|
|
|
|
+ return nick.charAt(0) + "*";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (nick.length() == 2) {
|
|
|
|
|
+ return nick.charAt(0) + "*";
|
|
|
|
|
+ }
|
|
|
|
|
+ return nick.charAt(0) + "**" + nick.charAt(nick.length() - 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private R<String> invokeAnalyzeTask() {
|
|
|
|
|
+ log.info("【用户补充申诉】开始调用差评申述置信度分析接口, url: {}", analyzeUrl);
|
|
|
|
|
+
|
|
|
|
|
+ HttpHeaders analyzeHeaders = new HttpHeaders();
|
|
|
|
|
+ analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
|
+
|
|
|
|
|
+ List<Map<String, Object>> appealList = storeCommentAppealMapper.getAppealListBetween45And72Hours();
|
|
|
|
|
+ if (appealList == null || appealList.isEmpty()) {
|
|
|
|
|
+ log.info("【用户补充申诉】没有申诉时间在45~72小时内的待处理申述");
|
|
|
|
|
+ return R.success("没有申诉时间在45~72小时内的待处理申述");
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("【用户补充申诉】本次处理申述数量(申诉45~72小时,上限10条): {}", appealList.size());
|
|
|
|
|
+
|
|
|
|
|
+ for (Map<String, Object> storeCommentAppeal : appealList) {
|
|
|
|
|
+ Map<String, Object> analyzeRequest = new HashedMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ analyzeRequest.put("merchant_material",
|
|
|
|
|
+ storeCommentAppeal.get("appeal_reason") == null ? "" : storeCommentAppeal.get("appeal_reason").toString());
|
|
|
|
|
+ analyzeRequest.put("user_material",
|
|
|
|
|
+ storeCommentAppeal.get("comment_content") == null ? "" : storeCommentAppeal.get("comment_content").toString());
|
|
|
|
|
+ Integer appealId = (Integer) storeCommentAppeal.get("id");
|
|
|
|
|
+ analyzeRequest.put("user_review", buildUserReviewFromSupplement(appealId));
|
|
|
|
|
+
|
|
|
|
|
+ List<String> merchantImages = new ArrayList<>();
|
|
|
|
|
+ String imgUrls = storeCommentAppeal.get("img_url") == null ? "" : storeCommentAppeal.get("img_url").toString();
|
|
|
|
|
+ if (StringUtils.hasText(imgUrls)) {
|
|
|
|
|
+ for (String imageUrl : imgUrls.split(",")) {
|
|
|
|
|
+ merchantImages.add(imageUrl.trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ analyzeRequest.put("merchant_images", merchantImages);
|
|
|
|
|
+
|
|
|
|
|
+ List<String> userImages = new ArrayList<>();
|
|
|
|
|
+ String userImgUrls = storeCommentAppeal.get("user_img_url") == null ? "" : storeCommentAppeal.get("user_img_url").toString();
|
|
|
|
|
+ if (StringUtils.hasText(userImgUrls)) {
|
|
|
|
|
+ for (String imageUrl : userImgUrls.split(",")) {
|
|
|
|
|
+ userImages.add(imageUrl.trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ analyzeRequest.put("user_images", userImages);
|
|
|
|
|
+
|
|
|
|
|
+ analyzeRequest.put("case_id", storeCommentAppeal.get("comment_id") == null ? "" : storeCommentAppeal.get("comment_id").toString());
|
|
|
|
|
+ analyzeRequest.put("order_id", storeCommentAppeal.get("business_id") == null ? "" : storeCommentAppeal.get("business_id").toString());
|
|
|
|
|
+
|
|
|
|
|
+ HttpEntity<Map<String, Object>> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
|
|
|
|
|
+
|
|
|
|
|
+ ResponseEntity<String> analyzeResp;
|
|
|
|
|
+ try {
|
|
|
|
|
+ analyzeResp = restTemplate.postForEntity(analyzeUrl, analyzeEntity, String.class);
|
|
|
|
|
+ } catch (org.springframework.web.client.HttpServerErrorException.ServiceUnavailable e) {
|
|
|
|
|
+ log.error("【用户补充申诉】调用分析接口返回503: {}", e.getResponseBodyAsString());
|
|
|
|
|
+ continue;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】调用分析接口异常", e);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (analyzeResp == null || analyzeResp.getStatusCodeValue() != 200) {
|
|
|
|
|
+ if (analyzeResp != null) {
|
|
|
|
|
+ log.error("【用户补充申诉】调用分析接口失败, http状态: {}", analyzeResp.getStatusCode());
|
|
|
|
|
+ }
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String analyzeBody = analyzeResp.getBody();
|
|
|
|
|
+ log.info("【用户补充申诉】分析提交成功, 返回: {}", analyzeBody);
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
|
|
|
|
|
+ JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
|
|
|
|
|
+ if (dataJsonObj == null) {
|
|
|
|
|
+ log.error("【用户补充申诉】分析返回数据为空");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Integer recordId = dataJsonObj.getInteger("record_id");
|
|
|
|
|
+ if (recordId == null) {
|
|
|
|
|
+ log.error("【用户补充申诉】分析返回 record_id 为空");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ StoreCommentAppeal sCommentAppeal = new StoreCommentAppeal();
|
|
|
|
|
+ sCommentAppeal.setId((Integer) storeCommentAppeal.get("id"));
|
|
|
|
|
+ sCommentAppeal.setAppealStatus(3);
|
|
|
|
|
+ sCommentAppeal.setRecordId(recordId);
|
|
|
|
|
+ storeCommentAppealMapper.updateById(sCommentAppeal);
|
|
|
|
|
+ }
|
|
|
|
|
+ return R.success("【用户补充申诉】调用差评申述置信度分析接口完成");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String buildUserReviewFromSupplement(Integer appealId) {
|
|
|
|
|
+ if (appealId == null) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ List<StoreCommentAppealSupplement> supplements = storeCommentAppealSupplementMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<StoreCommentAppealSupplement>()
|
|
|
|
|
+ .eq(StoreCommentAppealSupplement::getAppealId, appealId)
|
|
|
|
|
+ .eq(StoreCommentAppealSupplement::getDeleteFlag, 0)
|
|
|
|
|
+ .orderByAsc(StoreCommentAppealSupplement::getCreatedTime));
|
|
|
|
|
+ return supplements.stream()
|
|
|
|
|
+ .map(StoreCommentAppealSupplement::getSupplementContent)
|
|
|
|
|
+ .filter(StringUtils::hasText)
|
|
|
|
|
+ .collect(Collectors.joining("\n"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String buildCompletedUrl(Integer recordId) {
|
|
|
|
|
+ String baseUrl = resultUrl;
|
|
|
|
|
+ if (!StringUtils.hasText(baseUrl)) {
|
|
|
|
|
+ throw new IllegalStateException("【用户补充申诉】分析结果接口地址未配置");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return baseUrl + "/" + recordId + "/completed";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void deleteRatingAndComments(Integer ratingId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ CommonRating rating = commonRatingMapper.selectById(ratingId);
|
|
|
|
|
+ if (rating != null) {
|
|
|
|
|
+ int rows = commonRatingMapper.logicDeleteById(ratingId);
|
|
|
|
|
+ log.info("【用户补充申诉】删除评价,ratingId={},影响行数={}", ratingId, rows);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LambdaQueryWrapper<CommonComment> commentQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ commentQueryWrapper.eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
|
|
|
|
|
+ .eq(CommonComment::getSourceId, ratingId)
|
|
|
|
|
+ .eq(CommonComment::getDeleteFlag, 0);
|
|
|
|
|
+ List<CommonComment> comments = commonCommentMapper.selectList(commentQueryWrapper);
|
|
|
|
|
+ List<Long> commentIds = comments.stream().map(CommonComment::getId).collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ int commentRows = commonCommentMapper.logicDeleteBySourceId(
|
|
|
|
|
+ CommentSourceTypeEnum.STORE_COMMENT.getType(), ratingId);
|
|
|
|
|
+ log.info("【用户补充申诉】删除评价下评论,ratingId={},影响行数={}", ratingId, commentRows);
|
|
|
|
|
+
|
|
|
|
|
+ LambdaUpdateWrapper<LifeLikeRecord> ratingLikeWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ ratingLikeWrapper.eq(LifeLikeRecord::getType, "7")
|
|
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(ratingId))
|
|
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
|
|
+ ratingLikeWrapper.set(LifeLikeRecord::getDeleteFlag, 1);
|
|
|
|
|
+ ratingLikeWrapper.set(LifeLikeRecord::getUpdatedTime, new java.util.Date());
|
|
|
|
|
+ lifeLikeRecordMapper.update(null, ratingLikeWrapper);
|
|
|
|
|
+
|
|
|
|
|
+ if (!commentIds.isEmpty()) {
|
|
|
|
|
+ for (Long commentId : commentIds) {
|
|
|
|
|
+ LambdaUpdateWrapper<LifeLikeRecord> commentLikeWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ commentLikeWrapper.eq(LifeLikeRecord::getType, "1")
|
|
|
|
|
+ .eq(LifeLikeRecord::getHuifuId, String.valueOf(commentId))
|
|
|
|
|
+ .eq(LifeLikeRecord::getDeleteFlag, 0);
|
|
|
|
|
+ commentLikeWrapper.set(LifeLikeRecord::getDeleteFlag, 1);
|
|
|
|
|
+ commentLikeWrapper.set(LifeLikeRecord::getUpdatedTime, new java.util.Date());
|
|
|
|
|
+ lifeLikeRecordMapper.update(null, commentLikeWrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (rating != null && rating.getBusinessType() == 1) {
|
|
|
|
|
+ updateStoreScore(rating.getBusinessId());
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】删除评价和评论异常,ratingId={}", ratingId, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateStoreScore(Integer businessId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(CommonRating::getBusinessType, 1)
|
|
|
|
|
+ .eq(CommonRating::getBusinessId, businessId)
|
|
|
|
|
+ .eq(CommonRating::getDeleteFlag, 0)
|
|
|
|
|
+ .eq(CommonRating::getIsShow, 1)
|
|
|
|
|
+ .eq(CommonRating::getAuditStatus, 1);
|
|
|
|
|
+ List<CommonRating> ratings = commonRatingMapper.selectList(wrapper);
|
|
|
|
|
+
|
|
|
|
|
+ int total = ratings.size();
|
|
|
|
|
+ if (total == 0) {
|
|
|
|
|
+ StoreInfo storeInfo = new StoreInfo();
|
|
|
|
|
+ storeInfo.setId(businessId);
|
|
|
|
|
+ storeInfo.setScoreAvg(5.0);
|
|
|
|
|
+ storeInfo.setScoreOne(0.0);
|
|
|
|
|
+ storeInfo.setScoreTwo(0.0);
|
|
|
|
|
+ storeInfo.setScoreThree(0.0);
|
|
|
|
|
+ storeInfoMapper.updateById(storeInfo);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ double scoreSum = ratings.stream().mapToDouble(r -> r.getScore() != null ? r.getScore() : 0.0).sum();
|
|
|
|
|
+ double scoreOneSum = ratings.stream().mapToDouble(r -> r.getScoreOne() != null ? r.getScoreOne() : 0.0).sum();
|
|
|
|
|
+ double scoreTwoSum = ratings.stream().mapToDouble(r -> r.getScoreTwo() != null ? r.getScoreTwo() : 0.0).sum();
|
|
|
|
|
+ double scoreThreeSum = ratings.stream().mapToDouble(r -> r.getScoreThree() != null ? r.getScoreThree() : 0.0).sum();
|
|
|
|
|
+
|
|
|
|
|
+ StoreInfo storeInfo = new StoreInfo();
|
|
|
|
|
+ storeInfo.setId(businessId);
|
|
|
|
|
+ storeInfo.setScoreAvg(Math.round((scoreSum / total) * 100.0) / 100.0);
|
|
|
|
|
+ storeInfo.setScoreOne(Math.round((scoreOneSum / total) * 100.0) / 100.0);
|
|
|
|
|
+ storeInfo.setScoreTwo(Math.round((scoreTwoSum / total) * 100.0) / 100.0);
|
|
|
|
|
+ storeInfo.setScoreThree(Math.round((scoreThreeSum / total) * 100.0) / 100.0);
|
|
|
|
|
+ storeInfoMapper.updateById(storeInfo);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】更新店铺评分失败,businessId={}", businessId, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @SuppressWarnings("unused")
|
|
|
|
|
+ private String fetchAiServiceToken() {
|
|
|
|
|
+ log.info("【用户补充申诉】登录 AI 服务获取 token, url: {}", loginUrl);
|
|
|
|
|
+ MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
|
|
|
|
+ formData.add("username", userName);
|
|
|
|
|
+ formData.add("password", passWord);
|
|
|
|
|
+
|
|
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
|
|
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
|
|
|
+ HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ ResponseEntity<String> response = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
|
|
|
|
|
+ if (response != null && response.getStatusCodeValue() == 200 && response.getBody() != null) {
|
|
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(response.getBody());
|
|
|
|
|
+ JSONObject dataJson = jsonObject.getJSONObject("data");
|
|
|
|
|
+ return dataJson != null ? dataJson.getString("access_token") : null;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.error("【用户补充申诉】登录接口失败, http状态: {}", response != null ? response.getStatusCode() : null);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("【用户补充申诉】登录接口异常", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|