Parcourir la source

bugfix:3777 (测试环境)账号信息页(提测0323):上传律师资格证没有做校验

刘云鑫 il y a 1 mois
Parent
commit
3561b1eb65

+ 19 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserServiceImpl.java

@@ -22,6 +22,7 @@ import shop.alien.lawyer.service.LawyerLegalProblemScenarioService;
 import shop.alien.lawyer.service.LawyerServiceAreaService;
 import shop.alien.lawyer.service.LawyerUserSearchHistoryService;
 import shop.alien.lawyer.service.LawyerUserService;
+import shop.alien.lawyer.util.ai.LawyerLicenseVerifyUtil;
 import shop.alien.mapper.*;
 import shop.alien.util.common.ListToPage;
 import shop.alien.util.excel.EasyExcelUtil;
@@ -54,6 +55,7 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
     private final LawFirmPaymentMapper lawFirmPaymentmapper;
     private final OrderReviewMapper orderReviewMapper;
     private final LifeNoticeMapper lifeNoticeMapper;
+    private final LawyerLicenseVerifyUtil lawyerLicenseVerifyUtil;
 
     @Override
     public R<IPage<LawyerUser>> getLawyerUserList(int pageNum, int pageSize, String name, String phone, Integer status) {
@@ -632,6 +634,12 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
             log.warn("更新律师用户信息失败:参数为空或律师ID为空");
             return R.fail("律师ID不能为空");
         }
+        LawyerUser existing = lawyerUserMapper.selectById(lawyerUserVo.getId());
+        if (existing == null || (existing.getDeleteFlag() != null && existing.getDeleteFlag() == 1)) {
+            log.warn("更新律师用户信息失败:律师不存在,律师ID={}", lawyerUserVo.getId());
+            return R.fail("律师不存在");
+        }
+
         LawyerUser lawyerUser = new LawyerUser();
         lawyerUser.setId(lawyerUserVo.getId());
 
@@ -719,6 +727,17 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
             hasUpdate = true;
         }
 
+        // 修改执业证、姓名或头像时,先走 AI 执业证核验(与库中数据合并后校验)
+        if (lawyerUserVo.getCertificateImage() != null || lawyerUserVo.getName() != null || lawyerUserVo.getHeadImg() != null) {
+            String certUrl = lawyerUserVo.getCertificateImage() != null ? lawyerUserVo.getCertificateImage() : existing.getCertificateImage();
+            String name = lawyerUserVo.getName() != null ? lawyerUserVo.getName() : existing.getName();
+            String headUrl = lawyerUserVo.getHeadImg() != null ? lawyerUserVo.getHeadImg() : existing.getHeadImg();
+            LawyerLicenseVerifyUtil.VerifyResult licenseResult = lawyerLicenseVerifyUtil.verify(certUrl, name, headUrl);
+            if (!licenseResult.isPassed()) {
+                return R.fail("执业证核验失败");
+            }
+        }
+
 // 只有当有字段需要更新时才执行更新操作
         if (hasUpdate) {
 

+ 164 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/util/ai/LawyerLicenseVerifyUtil.java

@@ -0,0 +1,164 @@
+package shop.alien.lawyer.util.ai;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Objects;
+
+/**
+ * 律师执业证/资格证 AI 核验(入驻时调用)
+ */
+@Slf4j
+@Component
+@RefreshScope
+@RequiredArgsConstructor
+public class LawyerLicenseVerifyUtil {
+
+    private final RestTemplate restTemplate;
+    private final AiAuthTokenUtil aiAuthTokenUtil;
+
+    @Value("${ai.service.lawyer-license-verify-url:http://124.93.18.180:9000/ai/multimodal-services/api/v1/lawyer-license/verify}")
+    private String lawyerLicenseVerifyUrl;
+
+    public static class VerifyResult {
+        private final boolean passed;
+        private final String message;
+
+        public VerifyResult(boolean passed, String message) {
+            this.passed = passed;
+            this.message = message;
+        }
+
+        public boolean isPassed() {
+            return passed;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+    }
+
+    /**
+     * 核验执业证照片、姓名与头像是否与证件一致
+     *
+     * @param certificateImageUrl 执业证照片 URL
+     * @param realName            待核验姓名
+     * @param userAvatarUrl       律师头像 URL
+     */
+    public VerifyResult verify(String certificateImageUrl, String realName, String userAvatarUrl) {
+        if (!StringUtils.hasText(certificateImageUrl) || !StringUtils.hasText(realName) || !StringUtils.hasText(userAvatarUrl)) {
+            return new VerifyResult(false, "请完整上传律师执业证照片、本人头像,并填写与证件一致的真实姓名。");
+        }
+        try {
+            String accessToken = aiAuthTokenUtil.getAccessToken();
+            if (!StringUtils.hasText(accessToken)) {
+                log.error("律师执业证核验失败:无法获取 AI 服务访问令牌");
+                return new VerifyResult(false, "执业证核验服务暂不可用,请稍后重试。如多次失败请联系平台客服。");
+            }
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            headers.set("Authorization", "Bearer " + accessToken);
+
+            JSONObject body = new JSONObject();
+            body.put("image_url", certificateImageUrl.trim());
+            body.put("text", realName.trim());
+            body.put("user_avatar_url", userAvatarUrl.trim());
+
+            String json = Objects.requireNonNull(body.toJSONString());
+            HttpEntity<String> entity = new HttpEntity<>(json, headers);
+
+            log.info("调用律师执业证核验接口:url={}", lawyerLicenseVerifyUrl);
+            ResponseEntity<String> response = restTemplate.postForEntity(lawyerLicenseVerifyUrl, entity, String.class);
+
+            if (response.getStatusCode() != HttpStatus.OK || !StringUtils.hasText(response.getBody())) {
+                log.error("律师执业证核验 HTTP 异常:status={}", response.getStatusCode());
+                return new VerifyResult(false, "执业证核验服务响应异常,请稍后重试。");
+            }
+
+            JSONObject root = JSONObject.parseObject(response.getBody());
+            return parseResult(root);
+
+        } catch (Exception e) {
+            log.error("律师执业证核验调用异常", e);
+            return new VerifyResult(false, "执业证核验服务暂时不可用,请稍后重试。");
+        }
+    }
+
+    private VerifyResult parseResult(JSONObject root) {
+        Integer code = root.getInteger("code");
+        if (code == null || code != 0) {
+            String msg = root.getString("message");
+            log.warn("律师执业证核验接口业务错误:code={}, message={}", code, msg);
+            if (code != null && code == 422) {
+                return new VerifyResult(false, "提交资料不完整或格式有误,请检查执业证照片、头像与姓名后重试。");
+            }
+            if (StringUtils.hasText(msg)) {
+                return new VerifyResult(false, "执业证核验未通过:" + msg);
+            }
+            return new VerifyResult(false, "执业证核验未通过,请稍后重试。");
+        }
+
+        JSONObject data = root.getJSONObject("data");
+        if (data == null) {
+            log.warn("律师执业证核验返回 data 为空");
+            return new VerifyResult(false, "执业证核验结果异常,请稍后重试。");
+        }
+
+        if (isPass(data)) {
+            log.info("律师执业证核验通过");
+            return new VerifyResult(true, null);
+        }
+
+        String userMessage = buildUserFacingFailure(data);
+        log.warn("律师执业证核验未通过:{}", userMessage);
+        return new VerifyResult(false, userMessage);
+    }
+
+    private static boolean isPass(JSONObject data) {
+        Integer i = data.getInteger("is_pass");
+        if (i != null) {
+            return i == 1;
+        }
+        return Boolean.TRUE.equals(data.getBoolean("is_pass"));
+    }
+
+    /**
+     * 面向用户的失败说明(结合接口 reason 与分项标志)
+     */
+    private String buildUserFacingFailure(JSONObject data) {
+        String reason = data.getString("reason");
+        Boolean isLawyerLicense = data.getBoolean("is_lawyer_license");
+        Boolean nameMatch = data.getBoolean("name_match");
+        Boolean faceMatch = data.getBoolean("face_match");
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("律师执业证核验未通过。");
+
+        if (Boolean.FALSE.equals(isLawyerLicense)) {
+            sb.append("上传图片未能识别为有效的律师执业证或律师资格证,请拍摄证件原件清晰、四角完整的照片后重新上传。");
+        } else if (Boolean.FALSE.equals(nameMatch)) {
+            sb.append("证件所载姓名与您填写的姓名不一致,请填写与证件完全一致的真实姓名。");
+        } else if (Boolean.FALSE.equals(faceMatch)) {
+            sb.append("本人头像与证件照人像不一致,请使用本人近期清晰正面头像。");
+        } else {
+            sb.append("请确保证件信息清晰可辨,且姓名、头像与执业证记载一致。");
+        }
+
+        if (StringUtils.hasText(reason)) {
+            sb.append("(").append(reason.trim()).append(")");
+        }
+        return sb.toString();
+    }
+}