ソースを参照

feat: 站点信息联动下拉 + 前后端必填校验

- onboardRules: scene_code/ scene_directions 红*必填
- SITE_TYPE_OPTIONS: 网站/APP/公众号/小程序/H5/其它 checkbox联动
- 选中后动态展示对应输入框,提交时构建 sites JSON
- 后端: scene_code/scene_directions/scene_image 空值校验
alphaH 1 日 前
コミット
07cbd5b1bd

+ 69 - 41
frontend/src/views/module_payment/account/index.vue

@@ -114,25 +114,30 @@
                 <el-tag v-else type="warning">待审核</el-tag>
               </div>
             </template>
-            <el-form ref="onboardFormRef" :model="onboardForm" label-width="140px">
-              <el-form-item label="场景码" prop="scene_code">
+            <el-form ref="onboardFormRef" :model="onboardForm" :rules="onboardRules" label-width="140px">
+              <el-form-item label="场景码" prop="scene_code" required>
                 <el-select v-model="onboardForm.scene_code" placeholder="请选择转账场景">
                   <el-option v-for="s in ONBOARD_SCENE_OPTIONS" :key="s.value" :label="s.label" :value="s.value" />
                 </el-select>
               </el-form-item>
-              <el-form-item label="场景说明" prop="scene_directions">
+              <el-form-item label="场景说明" prop="scene_directions" required>
                 <el-input v-model="onboardForm.scene_directions" type="textarea" :rows="3"
                   placeholder="谁/通过什么媒介(APP/web/小程序)/主要为谁提供什么服务/用于在什么场景给什么人群转账" maxlength="1024" show-word-limit />
               </el-form-item>
-              <el-form-item label="场景截图" prop="scene_image">
+              <el-form-item label="场景截图" prop="scene_image" required>
                 <el-upload ref="uploadRef" :action="''" :auto-upload="false"
                   :file-list="onboardFiles" :on-change="handleOnboardFileChange" :limit="5"
                   list-type="picture-card" accept="image/*,.pdf">
                   <el-icon><Plus /></el-icon>
                 </el-upload>
               </el-form-item>
-              <el-form-item label="站点信息(选填)">
-                <el-input v-model="onboardForm.sites" placeholder='如 {"WEBSITE":"www.test.com","APP":"test"}' />
+              <el-form-item label="站点信息">
+                <el-checkbox-group v-model="onboardSiteTypes">
+                  <el-checkbox v-for="s in SITE_TYPE_OPTIONS" :key="s.value" :label="s.value">{{ s.label }}</el-checkbox>
+                </el-checkbox-group>
+                <div v-for="st in onboardSiteTypes" :key="st" style="margin-top: 8px">
+                  <el-input v-model="onboardSites[st]" :placeholder="'请输入' + st + '地址'" style="width: 300px" />
+                </div>
               </el-form-item>
               <el-form-item>
                 <el-button type="primary" :loading="onboardLoading" @click="handleOnboardSubmit">提交进件</el-button>
@@ -841,66 +846,89 @@ const ONBOARD_SCENE_OPTIONS = [
   { value: "ZHUANZHANG_QITA", label: "其他场景" },
 ];
 
+const SITE_TYPE_OPTIONS = [
+  { value: "WEBSITE", label: "网站" },
+  { value: "APP", label: "APP" },
+  { value: "GONGZH", label: "公众号" },
+  { value: "XCHENGXU_ZHI", label: "支付宝小程序" },
+  { value: "WEB", label: "手机网站/H5" },
+  { value: "QITA", label: "其它" },
+];
+
 const onboardFormRef = ref<FormInstance>();
 const onboardLoading = ref(false);
 const onboardFiles = ref<any[]>([]);
 const uploadRef = ref();
+const onboardSiteTypes = ref<string[]>([]);
+const onboardSites = reactive<Record<string, string>>({});
 
 const onboardForm = reactive({
   scene_code: "YONGJIN_BAOCHOU",
   scene_directions: "",
   scene_image: "",
-  sites: "",
 });
 
+const onboardRules: FormRules = {
+  scene_code: [{ required: true, message: "请选择场景码", trigger: "change" }],
+  scene_directions: [{ required: true, message: "请填写场景说明", trigger: "blur" }],
+};
+
 function handleOnboardFileChange(file: any) {
   onboardFiles.value.push(file);
 }
 
 async function handleOnboardSubmit() {
-  if (!onboardForm.scene_directions) {
-    ElMessage.warning("请填写场景说明");
-    return;
-  }
-  onboardLoading.value = true;
-  try {
-    // 1. 上传所有图片
-    const imageIds: string[] = [];
-    for (const f of onboardFiles.value) {
-      const res = await AccountAPI.uploadImage(f.raw, currentEnterpriseId.value!);
-      const id = res.data.data?.image_id;
-      if (id) imageIds.push(id);
-    }
-    if (imageIds.length === 0) {
+  if (!onboardFormRef.value) return;
+  await onboardFormRef.value.validate(async (valid) => {
+    if (!valid) return;
+    if (onboardFiles.value.length === 0) {
       ElMessage.warning("请上传场景截图");
       return;
     }
-    // 2. 创建进件单
-    const res = await AccountAPI.createOnboard({
-      enterprise_id: currentEnterpriseId.value!,
-      scene_code: onboardForm.scene_code,
-      scene_directions: onboardForm.scene_directions,
-      scene_image: imageIds.join(","),
-      sites: onboardForm.sites || undefined,
-      alipay_user_id: enterpriseStore.getCurrentEnterprise?.identity || "",
-    });
-    const data = res.data.data;
-    if (data?.order_id) {
-      ElMessage.success("进件单已提交,支付宝审核中");
-      accountInfo.value.onboard_status = "PENDING";
-      overviewRef.value?.refresh();
+    onboardLoading.value = true;
+    try {
+      const imageIds: string[] = [];
+      for (const f of onboardFiles.value) {
+        const res = await AccountAPI.uploadImage(f.raw, currentEnterpriseId.value!);
+        const id = res.data.data?.image_id;
+        if (id) imageIds.push(id);
+      }
+      // 构建 sites JSON
+      let sites: string | undefined;
+      if (onboardSiteTypes.value.length > 0) {
+        const obj: Record<string, string> = {};
+        for (const st of onboardSiteTypes.value) {
+          if (onboardSites[st]) obj[st] = onboardSites[st];
+        }
+        if (Object.keys(obj).length > 0) sites = JSON.stringify(obj);
+      }
+      const res = await AccountAPI.createOnboard({
+        enterprise_id: currentEnterpriseId.value!,
+        scene_code: onboardForm.scene_code,
+        scene_directions: onboardForm.scene_directions,
+        scene_image: imageIds.join(","),
+        sites,
+        alipay_user_id: enterpriseStore.getCurrentEnterprise?.identity || "",
+      });
+      const data = res.data.data;
+      if (data?.order_id) {
+        ElMessage.success("进件单已提交,支付宝审核中");
+        accountInfo.value.onboard_status = "PENDING";
+        overviewRef.value?.refresh();
+      }
+    } catch (e: any) {
+      ElMessage.error(e?.message || "提交进件失败");
+    } finally {
+      onboardLoading.value = false;
     }
-  } catch (e: any) {
-    ElMessage.error(e?.message || "提交进件失败");
-  } finally {
-    onboardLoading.value = false;
-  }
+  });
 }
 
 function handleOnboardReset() {
   onboardFormRef.value?.resetFields();
   onboardFiles.value = [];
-  onboardForm.scene_image = "";
+  onboardSiteTypes.value = [];
+  Object.keys(onboardSites).forEach(k => delete onboardSites[k]);
 }
 
 const createRules: FormRules = {

+ 6 - 0
java/src/main/java/com/payment/platform/module/payment/account/service/AlipayTransferService.java

@@ -242,6 +242,12 @@ public class AlipayTransferService {
     public Map<String, String> createOnboard(String enterpriseId, String sceneCode,
                                               String sceneDirections, String sceneImageKeys,
                                               String sites, String alipayUserId) {
+        if (sceneCode == null || sceneCode.isBlank())
+            throw new BusinessException(400, "场景码不能为空");
+        if (sceneDirections == null || sceneDirections.isBlank())
+            throw new BusinessException(400, "场景说明不能为空");
+        if (sceneImageKeys == null || sceneImageKeys.isBlank())
+            throw new BusinessException(400, "场景截图不能为空");
         String outBizNo = SnowflakeIdGenerator.nextIdStr();
         try {
             AlipayFundExpandindirectCreateModel model = new AlipayFundExpandindirectCreateModel();

+ 3 - 0
logs/payment-platform.log

@@ -1729,3 +1729,6 @@ Caused by: java.io.EOFException: null
 2026-07-15 14:20:29.157 [main] INFO  c.p.platform.PaymentApplication - Started PaymentApplication in 6.157 seconds (process running for 7.305)
 2026-07-15 14:20:31.011 [main] INFO  c.p.p.core.config.AppStartupRunner - 系统配置缓存初始化完成
 2026-07-15 14:20:31.906 [main] INFO  c.p.p.core.config.AppStartupRunner - 数据字典缓存初始化完成 (10 个字典类型)
+2026-07-15 14:21:41.842 [tomcat-handler-0] INFO  o.a.c.c.C.[.[localhost].[/api/v1] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2026-07-15 14:21:41.842 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2026-07-15 14:21:41.845 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms