Bläddra i källkod

@
feat: 签约→查询→自动填入 agreement_no 完整闭环

- authorizeApply 改用确定性 external_agreement_no,返回给前端
- 新增 queryAgreement(enterpriseId, externalAgreementNo): alipay.user.agreement.query
- Controller 新增 GET /payment/account/agreement/query
- queryAgreement 查到后自动写入 AccountEntity.agreementNo + signStatus
- 前端 handleAuthorize 保存 external_agreement_no
- 前端新增 handleQueryAgreement 按钮逻辑 + 自动填入 createForm.agreement_no
- AccountAPI 新增 queryAgreement 方法
@

alphaH 2 dagar sedan
förälder
incheckning
33529da03e

+ 9 - 1
frontend/src/api/module_payment/account.ts

@@ -44,13 +44,21 @@ export const AccountAPI = {
   },
 
   authorizeApply(data: { enterprise_id: string }) {
-    return request<ApiResponse<{ sign_url: string }>>({
+    return request<ApiResponse<{ sign_url: string; external_agreement_no: string }>>({
       url: `${API_PATH}/authorize/apply`,
       method: "post",
       data,
     });
   },
 
+  queryAgreement(enterpriseId: string, externalAgreementNo: string) {
+    return request<ApiResponse<{ agreement_no: string; status: string }>>({
+      url: `${API_PATH}/agreement/query`,
+      method: "get",
+      params: { enterprise_id: enterpriseId, external_agreement_no: externalAgreementNo },
+    });
+  },
+
   create(data: {
     enterprise_id: string;
     agreement_no?: string;  // 安全发: 签约协议号

+ 33 - 0
frontend/src/views/module_payment/account/index.vue

@@ -778,6 +778,9 @@ const authorizeRules: FormRules = {
 
 const authorizeResult = reactive({
   sign_url: "",
+  external_agreement_no: "",
+  agreement_no: "",
+  queryLoading: false,
 });
 
 const createForm = reactive({
@@ -1240,18 +1243,48 @@ async function handleAuthorize() {
       enterprise_id: currentEnterpriseId.value!,
     });
     const signHtml = res.data.data?.sign_url || "";
+    const externalAgreementNo = res.data.data?.external_agreement_no || "";
     authorizeResult.sign_url = signHtml;
+    authorizeResult.external_agreement_no = externalAgreementNo;
     // pageExecute 返回 HTML 表单,通过 Blob URL 跳转到支付宝签约页
     const blob = new Blob([signHtml], { type: "text/html" });
     window.open(URL.createObjectURL(blob), "_blank");
+    // 提示用户完成签约后查询结果
+    ElMessage.success("请在支付宝中完成签约,然后点击「查询签约结果」获取协议号");
   } finally {
     authorizeLoading.value = false;
   }
 }
 
+async function handleQueryAgreement() {
+  if (!authorizeResult.external_agreement_no) {
+    ElMessage.warning("请先申请签约");
+    return;
+  }
+  authorizeResult.queryLoading = true;
+  try {
+    const res = await AccountAPI.queryAgreement(
+      currentEnterpriseId.value!,
+      authorizeResult.external_agreement_no,
+    );
+    const agreementNo = res.data.data?.agreement_no || "";
+    if (agreementNo) {
+      authorizeResult.agreement_no = agreementNo;
+      createForm.agreement_no = agreementNo;
+      ElMessage.success("签约协议号已获取: " + agreementNo);
+    } else {
+      ElMessage.warning("尚未完成签约,请在支付宝中完成签约后再查询");
+    }
+  } finally {
+    authorizeResult.queryLoading = false;
+  }
+}
+
 function handleAuthorizeReset() {
   authorizeFormRef.value?.resetFields();
   authorizeResult.sign_url = "";
+  authorizeResult.external_agreement_no = "";
+  authorizeResult.agreement_no = "";
 }
 
 async function handleCreate() {

+ 8 - 0
java/src/main/java/com/payment/platform/module/payment/account/controller/AccountController.java

@@ -108,6 +108,14 @@ public class AccountController {
         return Result.ok(alipayTransferService.authorizeApply((String) b.get("enterprise_id")));
     }
 
+    @PreAuthorize("@perm.hasAny('module_payment:account:authorize')")
+    @GetMapping("/agreement/query")
+    public Result<Map<String, String>> queryAgreement(
+            @RequestParam(name = "enterprise_id") String enterpriseId,
+            @RequestParam(name = "external_agreement_no") String externalAgreementNo) {
+        return Result.ok(alipayTransferService.queryAgreement(enterpriseId, externalAgreementNo));
+    }
+
     @PreAuthorize("@perm.hasAny('module_payment:account:create')")
     @PostMapping
     public Result<Map<String, String>> create(@RequestBody Map<String, Object> b) {

+ 56 - 2
java/src/main/java/com/payment/platform/module/payment/account/service/AlipayTransferService.java

@@ -9,6 +9,7 @@ import com.alipay.api.domain.AlipayFundTransCommonQueryModel;
 import com.alipay.api.domain.AlipayFundTransPagePayModel;
 import com.alipay.api.domain.AlipayFundTransUniTransferModel;
 import com.alipay.api.domain.AlipayUserAgreementPageSignModel;
+import com.alipay.api.domain.AlipayUserAgreementQueryModel;
 import com.alipay.api.domain.BankcardExtInfo;
 import com.alipay.api.domain.Participant;
 import com.alipay.api.request.AlipayFundAccountbookCreateRequest;
@@ -17,12 +18,14 @@ import com.alipay.api.request.AlipayFundTransCommonQueryRequest;
 import com.alipay.api.request.AlipayFundTransPagePayRequest;
 import com.alipay.api.request.AlipayFundTransUniTransferRequest;
 import com.alipay.api.request.AlipayUserAgreementPageSignRequest;
+import com.alipay.api.request.AlipayUserAgreementQueryRequest;
 import com.alipay.api.response.AlipayFundAccountbookCreateResponse;
 import com.alipay.api.response.AlipayFundAccountbookQueryResponse;
 import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
 import com.alipay.api.response.AlipayFundTransPagePayResponse;
 import com.alipay.api.response.AlipayFundTransUniTransferResponse;
 import com.alipay.api.response.AlipayUserAgreementPageSignResponse;
+import com.alipay.api.response.AlipayUserAgreementQueryResponse;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.payment.platform.common.exception.BusinessException;
 import com.payment.platform.common.utils.RedisLockUtil;
@@ -105,14 +108,17 @@ public class AlipayTransferService {
     /**
      * alipay.user.agreement.page.sign — 页面跳转接口
      * 必填: personal_product_code, product_code, sign_scene, access_params
+     * 返回 sign_url + external_agreement_no(供后续 queryAgreement 反查)
      */
     public Map<String, String> authorizeApply(String enterpriseId) {
+        // 确定性签约号,便于后续反查 — 不拼时间戳
+        String externalAgreementNo = enterpriseId + "_agreement";
         try {
             AlipayUserAgreementPageSignModel model = new AlipayUserAgreementPageSignModel();
             model.setPersonalProductCode("GENERAL_WITHHOLDING_P");
             model.setProductCode("GENERAL_WITHHOLDING");
             model.setSignScene("DEFAULT|DEFAULT");
-            model.setExternalAgreementNo(enterpriseId + "_" + System.currentTimeMillis());
+            model.setExternalAgreementNo(externalAgreementNo);
             AccessParams accessParams = new AccessParams();
             accessParams.setChannel("ALIPAYAPP");
             model.setAccessParams(accessParams);
@@ -127,12 +133,60 @@ public class AlipayTransferService {
                 throw new BusinessException(400, "申请签约失败: 无响应");
 
             String body = response.getBody();
-            return Map.of("sign_url", body != null ? body : "");
+            return Map.of("sign_url", body != null ? body : "",
+                    "external_agreement_no", externalAgreementNo);
         } catch (AlipayApiException e) {
             throw new BusinessException(400, "申请签约失败: " + e.getMessage());
         }
     }
 
+    // ==================== 1b. 查询签约结果 ====================
+
+    /**
+     * alipay.user.agreement.query — 通过 external_agreement_no 反查签约协议号
+     * 用户完成签约后调用,获取支付宝侧的 agreement_no
+     */
+    public Map<String, String> queryAgreement(String enterpriseId, String externalAgreementNo) {
+        try {
+            AlipayUserAgreementQueryModel model = new AlipayUserAgreementQueryModel();
+            model.setExternalAgreementNo(externalAgreementNo);
+            model.setPersonalProductCode("GENERAL_WITHHOLDING_P");
+            model.setSignScene("DEFAULT|DEFAULT");
+            model.setThirdPartyType("PARTNER");
+
+            AlipayUserAgreementQueryRequest request = new AlipayUserAgreementQueryRequest();
+            request.setBizModel(model);
+
+            AlipayUserAgreementQueryResponse response =
+                    alipayClientFactory.getClient(enterpriseId).execute(request);
+
+            if (!response.isSuccess())
+                throw new BusinessException(400, "查询签约状态失败: " + response.getMsg());
+
+            // 写入本地 account 记录(如果有的话)
+            String agreementNo = response.getAgreementNo();
+            if (agreementNo != null && !agreementNo.isBlank()) {
+                var accounts = accountMapper.selectList(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AccountEntity>()
+                                .eq(AccountEntity::getEnterpriseId, enterpriseId));
+                for (AccountEntity acc : accounts) {
+                    if (acc.getAgreementNo() == null || acc.getAgreementNo().isBlank()) {
+                        acc.setAgreementNo(agreementNo);
+                        acc.setSignStatus("SIGNED");
+                        accountMapper.updateById(acc);
+                    }
+                }
+            }
+
+            return Map.of(
+                    "agreement_no", agreementNo != null ? agreementNo : "",
+                    "status", response.getStatus() != null ? response.getStatus() : "PENDING",
+                    "external_agreement_no", externalAgreementNo);
+        } catch (AlipayApiException e) {
+            return Map.of("status", "PENDING", "error", e.getMessage());
+        }
+    }
+
     // ==================== 2. 开通记账本 ====================
 
     /**