Переглянути джерело

feat: 批量付款付款方UID自动带出与授权页回溯 - 不再手填,进入页面展示已有授权链接并支持重新生成

- BatchPayAuthorize: UID 改只读自动带出(企业自身 UID);onMounted 拉最新授权记录,AUTHING 回溯展示链接+二维码+单号,AUTHED 展示已授权(隐藏生成入口);已有未完成授权时按钮变「重新生成授权链接」并确认后调 /authorize/rebind
- BatchPayCreate: 付款方 UID 改只读自动带出,去必填校验,提交以 enterprise_id 为 payer_uid
- batch.ts: 新增 authorizeRebind API
alphaH 6 днів тому
батько
коміт
328d04a841

+ 9 - 0
frontend/src/api/module_payment/batch.ts

@@ -85,6 +85,15 @@ export const BatchPayAPI = {
     });
   },
 
+  /** 制单授权重新生成:作废当前 AUTHING 申请(旧链接失效),换新 out_biz_no 重新申请 */
+  authorizeRebind(enterpriseId: string) {
+    return request<ApiResponse<{ authorize_link: string; out_biz_no: string; status: string }>>({
+      url: `${API_PATH}/authorize/rebind`,
+      method: "post",
+      data: { enterprise_id: enterpriseId },
+    });
+  },
+
   /** 查询制单授权状态(AUTHED 时回写协议号) */
   queryAuthorize(enterpriseId: string, outBizNo: string) {
     return request<ApiResponse<{ agreement_no: string; status: string }>>({

+ 74 - 18
frontend/src/views/module_payment/account/components/BatchPayAuthorize.vue

@@ -8,19 +8,32 @@
     <el-form label-width="160px">
       <el-form-item label="付款方支付宝UID">
         <el-input
-          v-model="participantId"
-          placeholder="企业财务的支付宝 UID(2088 开头)"
+          :model-value="enterpriseId ?? ''"
+          readonly
           style="max-width: 420px"
+          placeholder="2088 开头"
         />
+        <div class="form-item-tip">企业自己的支付宝 UID,系统自动带出</div>
       </el-form-item>
       <el-form-item>
         <el-button
+          v-if="!isAuthed"
           v-hasPerm="['module_payment:account:authorize']"
           type="primary"
           :loading="applying"
           @click="handleApply"
         >
-          生成授权链接
+          {{ existingAuthing ? "重新生成授权链接" : "生成授权链接" }}
+        </el-button>
+        <el-button
+          v-if="outBizNo"
+          v-hasPerm="['module_payment:account:authorize']"
+          size="small"
+          style="margin-left: 12px"
+          :loading="querying"
+          @click="handleQuery"
+        >
+          刷新状态
         </el-button>
       </el-form-item>
       <el-form-item v-if="link" label="授权链接(PC 浏览器打开)">
@@ -38,35 +51,27 @@
       </el-form-item>
       <el-form-item v-if="outBizNo" label="授权单号 / 状态">
         <span>{{ outBizNo }} / {{ statusText }}</span>
-        <el-button
-          v-hasPerm="['module_payment:account:authorize']"
-          size="small"
-          style="margin-left: 12px"
-          :loading="querying"
-          @click="handleQuery"
-        >
-          刷新状态
-        </el-button>
       </el-form-item>
     </el-form>
   </el-card>
 </template>
 
 <script setup lang="ts">
-import { computed, nextTick, ref } from "vue";
+import { computed, nextTick, onMounted, ref } from "vue";
 import BatchPayAPI from "@/api/module_payment/batch";
 import { useEnterpriseStore } from "@/store";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
 import QRCode from "qrcode";
 
 const enterpriseStore = useEnterpriseStore();
 const enterpriseId = computed(() => enterpriseStore.getCurrentEnterprise?.enterprise_id);
 
-const participantId = ref("");
 const link = ref("");
 const outBizNo = ref("");
 const agreementNo = ref("");
 const status = ref("");
+/** 最新记录已 AUTHED(永久生效授权)→ 不再提供生成入口,仅展示状态 */
+const isAuthed = ref(false);
 const applying = ref(false);
 const querying = ref(false);
 const qrcodeCanvas = ref<HTMLCanvasElement>();
@@ -82,19 +87,69 @@ const statusText = computed(() => {
   return agreementNo.value ? `${s}(协议号 ${agreementNo.value})` : s;
 });
 
+const existingAuthing = computed(() => status.value === "AUTHING");
+
+/** 进入页面时拉取该企业最新授权记录:AUTHING → 回溯展示链接,AUTHED → 展示已授权,UNBIND/无记录 → 初始空态 */
+async function loadLatest() {
+  if (!enterpriseId.value) return;
+  try {
+    const res = await BatchPayAPI.authorizeList({
+      enterprise_id: enterpriseId.value,
+      page_no: 1,
+      page_size: 1,
+    });
+    const rows = (res.data.data?.items ?? res.data.data?.list) || [];
+    const latest = rows[0];
+    if (!latest) return;
+    if (latest.status === "AUTHING") {
+      link.value = latest.authorize_link || "";
+      outBizNo.value = latest.out_biz_no;
+      status.value = "AUTHING";
+      agreementNo.value = "";
+      if (link.value) nextTick(() => drawQRCode());
+    } else if (latest.status === "AUTHED") {
+      outBizNo.value = latest.out_biz_no;
+      status.value = "AUTHED";
+      agreementNo.value = latest.agreement_no || "";
+      isAuthed.value = true;
+    }
+    // UNBIND → 保持初始空态(可正常生成新链接)
+  } catch (err) {
+    console.error("加载授权记录失败:", err);
+  }
+}
+
+onMounted(loadLatest);
+
 async function handleApply() {
-  if (!enterpriseId.value || !participantId.value) {
-    ElMessage.warning("请选择企业并填写付款方支付宝 UID");
+  if (!enterpriseId.value) {
+    ElMessage.warning("请选择企业");
     return;
   }
+  // 已有未完成授权申请:确认后作废旧链接重新生成(后端 /authorize/rebind)
+  if (existingAuthing.value) {
+    try {
+      await ElMessageBox.confirm(
+        "当前存在未完成的授权申请,重新生成将作废旧授权链接。是否继续?",
+        "重新生成授权链接",
+        { type: "warning", confirmButtonText: "重新生成", cancelButtonText: "取消" }
+      );
+    } catch {
+      return;
+    }
+  }
   applying.value = true;
   try {
-    const res = await BatchPayAPI.authorizeApply(enterpriseId.value, participantId.value);
+    const res = existingAuthing.value
+      ? await BatchPayAPI.authorizeRebind(enterpriseId.value)
+      : await BatchPayAPI.authorizeApply(enterpriseId.value, enterpriseId.value);
     link.value = res.data.data.authorize_link;
     outBizNo.value = res.data.data.out_biz_no;
     status.value = res.data.data.status;
     agreementNo.value = "";
+    isAuthed.value = false;
     nextTick(() => drawQRCode());
+    ElMessage.success("授权链接已生成,请尽快完成授权");
   } finally {
     applying.value = false;
   }
@@ -117,6 +172,7 @@ async function handleQuery() {
     const res = await BatchPayAPI.queryAuthorize(enterpriseId.value, outBizNo.value);
     status.value = res.data.data.status;
     agreementNo.value = res.data.data.agreement_no || "";
+    if (status.value === "AUTHED") isAuthed.value = true;
   } finally {
     querying.value = false;
   }

+ 9 - 5
frontend/src/views/module_payment/account/components/BatchPayCreate.vue

@@ -13,8 +13,14 @@
           style="max-width: 420px"
         />
       </el-form-item>
-      <el-form-item label="付款方支付宝UID" prop="payer_uid">
-        <el-input v-model="form.payer_uid" placeholder="2088 开头" style="max-width: 420px" />
+      <el-form-item label="付款方支付宝UID">
+        <el-input
+          :model-value="enterpriseId ?? ''"
+          readonly
+          style="max-width: 420px"
+          placeholder="2088 开头"
+        />
+        <div class="form-item-tip">企业自己的支付宝 UID,系统自动带出</div>
       </el-form-item>
       <el-form-item label="协议号">
         <el-input
@@ -198,7 +204,6 @@ const createdResult = ref<{
 
 const form = reactive({
   order_title: "",
-  payer_uid: "",
   agreement_no: "",
   transfer_scene_name: "",
   time_expire: "",
@@ -207,7 +212,6 @@ const form = reactive({
 
 const rules: FormRules = {
   order_title: [{ required: true, message: "请输入批次标题", trigger: "blur" }],
-  payer_uid: [{ required: true, message: "请输入付款方支付宝 UID", trigger: "blur" }],
   // I3: 26 年新接入商户必传转账场景(后端 DTO 同步 @NotBlank 校验)
   transfer_scene_name: [{ required: true, message: "请选择转账场景", trigger: "change" }],
 };
@@ -437,7 +441,7 @@ async function handleSubmit() {
     const res = await BatchPayAPI.batchCreate({
       enterprise_id: enterpriseId.value,
       order_title: form.order_title,
-      payer_uid: form.payer_uid,
+      payer_uid: enterpriseId.value,
       agreement_no: form.agreement_no || undefined,
       transfer_scene_name: form.transfer_scene_name || undefined,
       transfer_scene_report_infos: sceneReportInfos.length ? sceneReportInfos : undefined,