|
|
@@ -0,0 +1,194 @@
|
|
|
+package shop.alien.job.second;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.xxl.job.core.handler.annotation.XxlJob;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+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.Component;
|
|
|
+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.LifeNotice;
|
|
|
+import shop.alien.entity.store.LifeUser;
|
|
|
+import shop.alien.entity.store.LifeUserViolation;
|
|
|
+import shop.alien.mapper.LifeNoticeMapper;
|
|
|
+import shop.alien.mapper.LifeUserMapper;
|
|
|
+import shop.alien.mapper.LifeUserViolationMapper;
|
|
|
+
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 商品举报AI审核结果查询定时任务
|
|
|
+ * <p>
|
|
|
+ * 定时轮询待处理的商品举报任务,调用AI接口 POST /ai/auto-review/api/v1/product_complaint_record/result 查询审核结果,
|
|
|
+ * 并更新本地状态、发送通知。
|
|
|
+ * </p>
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class AiProductComplaintJob {
|
|
|
+
|
|
|
+ private final RestTemplate restTemplate;
|
|
|
+ private final LifeUserViolationMapper lifeUserViolationMapper;
|
|
|
+ private final LifeUserMapper lifeUserMapper;
|
|
|
+ private final LifeNoticeMapper lifeNoticeMapper;
|
|
|
+
|
|
|
+ @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;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 商品举报审核结果查询接口地址,例如: http://xxx/ai/auto-review/api/v1/product_complaint_record/result
|
|
|
+ */
|
|
|
+ @Value("${third-party-aiProductComplaintResultUrl.base-url}")
|
|
|
+ private String aiProductComplaintResultUrl;
|
|
|
+
|
|
|
+ @XxlJob("getAiProductComplaintResult")
|
|
|
+ public R<String> getAiProductComplaintResult() {
|
|
|
+ String accessToken = fetchAiServiceToken();
|
|
|
+ if (!StringUtils.hasText(accessToken)) {
|
|
|
+ return R.fail("调用AI商品举报审核系统登录接口失败");
|
|
|
+ }
|
|
|
+ return getAiProductComplaintCheck(accessToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String fetchAiServiceToken() {
|
|
|
+ log.info("登录Ai服务获取token...{}", 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("请求AI商品举报审核系统登录接口失败 http状态:{}", response != null ? response.getStatusCode() : null);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("调用AI商品举报审核系统登录接口异常", e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private R<String> getAiProductComplaintCheck(String accessToken) {
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+ headers.set("Authorization", "Bearer " + accessToken);
|
|
|
+
|
|
|
+ // 查询所有状态为处理中的商品举报(report_context_type=4 表示二手商品举报)
|
|
|
+ List<LifeUserViolation> pendingTasks = lifeUserViolationMapper.selectList(
|
|
|
+ new QueryWrapper<LifeUserViolation>()
|
|
|
+ .eq("report_context_type", "4")
|
|
|
+ .eq("processing_status", "0")
|
|
|
+ .isNotNull("ai_task_id")
|
|
|
+ .ne("ai_task_id", "")
|
|
|
+ );
|
|
|
+
|
|
|
+ for (LifeUserViolation task : pendingTasks) {
|
|
|
+ Map<String, String> body = new HashMap<>();
|
|
|
+ body.put("task_id", task.getAiTaskId());
|
|
|
+
|
|
|
+ HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(body, headers);
|
|
|
+
|
|
|
+ try {
|
|
|
+ ResponseEntity<String> response = restTemplate.postForEntity(aiProductComplaintResultUrl, requestEntity, String.class);
|
|
|
+
|
|
|
+ if (response == null || response.getStatusCodeValue() != 200 || response.getBody() == null) {
|
|
|
+ if (response != null) {
|
|
|
+ log.error("调用AI商品举报审核结果接口失败, http状态: {}", response.getStatusCode());
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String responseBody = response.getBody();
|
|
|
+ log.info("AI商品举报审核结果接口返回: {}", responseBody);
|
|
|
+
|
|
|
+ JSONObject json = JSONObject.parseObject(responseBody);
|
|
|
+ JSONObject dataJson = json.getJSONObject("data");
|
|
|
+
|
|
|
+ if (dataJson == null) {
|
|
|
+ log.error("AI商品举报审核返回数据为空, task_id={}", task.getAiTaskId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String status = dataJson.getString("status");
|
|
|
+ if ("pending".equals(status)) {
|
|
|
+ log.debug("任务尚未完成, task_id={}", task.getAiTaskId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!"completed".equals(status)) {
|
|
|
+ log.warn("未知状态 status={}, task_id={}", status, task.getAiTaskId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ LifeUserViolation update = new LifeUserViolation();
|
|
|
+ String isValid = dataJson.getString("is_valid");
|
|
|
+ String decisionReason = dataJson.getString("decision_reason");
|
|
|
+ if ("true".equals(isValid)) {
|
|
|
+ update.setProcessingStatus("1");
|
|
|
+ update.setReportResult(decisionReason);
|
|
|
+ } else {
|
|
|
+ update.setProcessingStatus("2");
|
|
|
+ update.setReportResult(decisionReason);
|
|
|
+ }
|
|
|
+ update.setProcessingTime(new Date());
|
|
|
+
|
|
|
+ QueryWrapper<LifeUserViolation> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("ai_task_id", task.getAiTaskId());
|
|
|
+ LifeUserViolation existing = lifeUserViolationMapper.selectOne(queryWrapper);
|
|
|
+ if (existing == null) {
|
|
|
+ log.error("AI商品举报记录不存在, ai_task_id={}", task.getAiTaskId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lifeUserViolationMapper.update(update, queryWrapper);
|
|
|
+
|
|
|
+ // 发送通知
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectById(task.getReportingUserId());
|
|
|
+ if (lifeUser != null) {
|
|
|
+ LifeNotice lifeMessage = new LifeNotice();
|
|
|
+ lifeMessage.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
+ String text = "您的举报商品结果为" + ("1".equals(update.getProcessingStatus()) ? "违规" : "未违规");
|
|
|
+ com.alibaba.fastjson.JSONObject lifeMessageJson = new com.alibaba.fastjson.JSONObject();
|
|
|
+ lifeMessageJson.put("title", "平台已受理");
|
|
|
+ lifeMessageJson.put("message", text);
|
|
|
+ lifeMessage.setContext(lifeMessageJson.toJSONString());
|
|
|
+ lifeMessage.setTitle("举报通知");
|
|
|
+ lifeMessage.setBusinessId(task.getId());
|
|
|
+ lifeMessage.setSenderId("system");
|
|
|
+ lifeMessage.setIsRead(0);
|
|
|
+ lifeMessage.setNoticeType(1);
|
|
|
+ lifeNoticeMapper.insert(lifeMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("调用AI商品举报审核结果接口异常, task_id={}", task.getAiTaskId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.success("调用AI商品举报审核结果接口完成");
|
|
|
+ }
|
|
|
+}
|