Prechádzať zdrojové kódy

feat: 新增领取优惠券页面,优化领取流程,移除手机号输入弹窗

laiqi 1 rok pred
rodič
commit
93f559627f

+ 7 - 0
src/pages.json

@@ -84,6 +84,13 @@
       }
     },
     {
+      "path": "pages/form/formStep3a",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "领取优惠券"
+      }
+    },
+    {
       "path": "pages/form/formStep4",
       "type": "page",
       "style": {

+ 12 - 109
src/pages/form/formStep3.vue

@@ -77,7 +77,7 @@
       </view>
       <!-- 领取优惠劵 -->
       <view class="mt-4 px-2">
-        <wd-button type="primary" plain block @tap="showPhoneDialog">领取优惠劵</wd-button>
+        <wd-button type="primary" plain block @tap="navigateToReceiveCoupon">领取优惠劵</wd-button>
       </view>
     </view>
 
@@ -87,42 +87,7 @@
       <wd-button type="primary" block size="large" @tap="handleOrder">立即下单</wd-button>
     </view>
 
-    <!-- 手机号输入弹窗 -->
-    <wd-popup
-      v-model="phoneDialogVisible"
-      round
-      :closable="true"
-      title="请输入手机号"
-      custom-class="w-[80%]"
-    >
-      <view class="phone-dialog p-6">
-        <view class="text-center mb-5">
-          <view class="text-lg font-semibold text-gray-800 mb-2">请输入您的手机号码</view>
-          <view class="text-sm text-gray-500">领取优惠券需要验证您的手机号</view>
-        </view>
-        <wd-input
-          v-model="phone"
-          placeholder="请输入您的手机号码"
-          clearable
-          :error="phoneError"
-          :error-message="phoneErrorMsg"
-          @blur="validatePhone"
-          required
-          class="mb-4"
-        />
-        <view class="mt-6">
-          <wd-button
-            type="success"
-            block
-            @click="handleSubmit"
-            :loading="submitLoading"
-            :disabled="submitLoading"
-          >
-            确认领取
-          </wd-button>
-        </view>
-      </view>
-    </wd-popup>
+    <!-- 手机号输入弹窗 (已移除) -->
 
     <!-- loading -->
     <wd-overlay :show="overlayShow">
@@ -150,91 +115,29 @@ const overlayShow = ref(false) // 加载状态
 const coupons = ref<any[]>([]) // 可用优惠券列表
 const couponChoose = ref('') // 选择的优惠券ID
 const submitLoading = ref(false) // 提交订单loading
-const phoneDialogVisible = ref(false) // 手机号输入弹窗显示状态
-
-// 手机号相关
-const phone = ref('')
-const phoneError = ref(false)
-const phoneErrorMsg = ref('')
 
-// 显示手机号输入弹窗
-function showPhoneDialog() {
-  // 检查是否选择了优惠券
-  if (!couponChoose.value && coupons.value && coupons.value.length > 0) {
+// 跳转到领取优惠券页面
+function navigateToReceiveCoupon() {
+  if (!coupons.value || coupons.value.length === 0) {
     message.alert({
-      msg: '请选择优惠券',
+      msg: '暂无可用优惠券可领取',
       title: '提示',
     })
     return
   }
 
-  phoneDialogVisible.value = true
-}
-
-// 验证手机号
-function validatePhone() {
-  if (!phone.value) {
-    phoneError.value = true
-    phoneErrorMsg.value = '请输入手机号码'
-    return false
-  }
-
-  const phoneReg = /^1[3-9]\d{9}$/
-  if (!phoneReg.test(phone.value)) {
-    phoneError.value = true
-    phoneErrorMsg.value = '请输入正确的手机号码'
-    return false
-  }
-
-  phoneError.value = false
-  phoneErrorMsg.value = ''
-  return true
-}
-
-// 提交表单
-async function handleSubmit() {
-  // 验证手机号
-  if (!validatePhone()) {
-    return
-  }
-
-  submitLoading.value = true
-
-  // 获取选中的优惠券
-  const selectedCoupon = coupons.value.find((coupon) => coupon.couponid === couponChoose.value)
-
-  if (!selectedCoupon) {
+  if (!couponChoose.value) {
     message.alert({
-      msg: '请选择优惠券',
+      msg: '请选择一张优惠券',
       title: '提示',
     })
-    submitLoading.value = false
     return
   }
 
-  try {
-    // 调用领取优惠券API
-    await couponStore.receiveCoupon({
-      couponid: selectedCoupon.couponid,
-      coupon2phone: phone.value,
-      coupon2productids: productsid.value,
-    })
-
-    message.alert({
-      msg: '优惠券领取成功,请注意查收短信',
-      title: '提示',
-    })
-    phoneDialogVisible.value = false // 关闭弹窗
-
-    submitLoading.value = false
-  } catch (error) {
-    console.error('领取优惠券出错:', error)
-    message.alert({
-      msg: '操作失败',
-      title: '提示',
-    })
-    submitLoading.value = false
-  }
+  // 跳转到 formStep3a.vue 页面
+  uni.navigateTo({
+    url: `/pages/form/formStep3a?productsid=${productsid.value}&couponid=${couponChoose.value}`,
+  })
 }
 
 // 获取产品详情

+ 459 - 0
src/pages/form/formStep3a.vue

@@ -0,0 +1,459 @@
+<route lang="json5">
+{
+  style: {
+    navigationBarTitleText: '领取优惠券',
+  },
+}
+</route>
+
+<template>
+  <view class="bg-gray-100 min-h-screen pb-20">
+    <!-- 优惠券使用规则 -->
+    <view class="bg-white px-4 py-4 mb-3 shadow-sm">
+      <view class="flex items-center mb-3">
+        <view class="text-lg font-bold text-gray-800">优惠券使用规则</view>
+        <view class="ml-2 flex-1 h-px bg-gray-100"></view>
+      </view>
+      <view class="rules-text text-sm text-gray-600 space-y-1">
+        <view>1. 优惠券发放后,有效期为1个月,过期作废;</view>
+        <view>2. 个人购买者:享受消费优惠券同类型农机不超过2台;</view>
+        <view>3. 组织购买者:享受消费优惠券同类型农机不超过10台。</view>
+      </view>
+    </view>
+
+    <!-- 表单区域 -->
+    <view class="bg-white px-4 py-4 shadow-sm">
+      <view class="flex items-center mb-4">
+        <view class="text-lg font-bold text-gray-800">请填写信息</view>
+        <view class="ml-2 flex-1 h-px bg-gray-100"></view>
+      </view>
+      <wd-form ref="formRef" :model="formData">
+        <wd-cell-group border>
+          <!-- 用户类型 -->
+          <wd-cell
+            title="用户类型"
+            title-width="100px"
+            prop="userstype"
+            required
+            custom-class="custom-cell"
+          >
+            <wd-radio-group
+              v-model="formData.userstype"
+              @change="handleUserTypeChange"
+              inline
+              shape="dot"
+              :rules="[{ required: true, message: '请选择用户类型' }]"
+            >
+              <wd-radio value="个人">个人</wd-radio>
+              <wd-radio value="企业">企业</wd-radio>
+            </wd-radio-group>
+          </wd-cell>
+
+          <!-- 姓名/企业名称 -->
+          <wd-input
+            :label="usersnameLabel"
+            label-width="100px"
+            prop="usersname"
+            required
+            v-model="formData.usersname"
+            :placeholder="`请输入${usersnameLabel}`"
+            clearable
+            no-border
+            :rules="[{ required: true, message: `请输入${usersnameLabel}` }]"
+          />
+
+          <!-- 证件号 -->
+          <wd-input
+            :label="idNumberLabel"
+            label-width="100px"
+            prop="idNumber"
+            required
+            v-model="formData.idNumber"
+            :placeholder="`请输入${idNumberLabel}`"
+            clearable
+            no-border
+            :rules="[{ required: true, message: `请输入${idNumberLabel}` }]"
+          />
+
+          <!-- 证件照片上传 -->
+          <wd-cell
+            :title="idPhotoLabel"
+            title-width="100px"
+            prop="idPhotoIds"
+            required
+            custom-class="custom-cell"
+          >
+            <view class="flex-1">
+              <!-- 个人身份证上传 -->
+              <template v-if="formData.userstype === '个人'">
+                <UploadComponent
+                  v-model="formData.idCardFiles"
+                  v-model:fileIds="formData.idCardIds"
+                  :limit="1"
+                  attmodel="coupon_identity"
+                  attpath="/coupon_identity/"
+                  modelStats="idCardIds"
+                  message="请上传身份证照片"
+                  tips="请上传身份证正面照片"
+                />
+              </template>
+
+              <!-- 企业营业执照上传 -->
+              <template v-else>
+                <UploadComponent
+                  v-model="formData.businessLicenseFiles"
+                  v-model:fileIds="formData.businessLicenseIds"
+                  :limit="1"
+                  attmodel="coupon_identity"
+                  attpath="/coupon_identity/"
+                  modelStats="businessLicenseIds"
+                  message="请上传营业执照照片"
+                />
+              </template>
+            </view>
+          </wd-cell>
+
+          <!-- 手机号 -->
+          <wd-input
+            label="手机号"
+            label-width="100px"
+            prop="phone"
+            required
+            v-model="formData.phone"
+            placeholder="请输入您的手机号码"
+            clearable
+            no-border
+            :rules="[
+              { required: true, message: '请输入手机号码' },
+              { required: false, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' },
+            ]"
+            @blur="validatePhone"
+          />
+
+          <!-- 验证码 -->
+          <wd-cell
+            title="验证码"
+            title-width="100px"
+            prop="smsCode"
+            required
+            custom-class="custom-cell"
+            vertical-align="center"
+          >
+            <view class="flex items-center flex-1">
+              <wd-input
+                v-model="formData.smsCode"
+                placeholder="请输入验证码"
+                clearable
+                no-border
+                custom-style="flex:1;"
+                :rules="[{ required: true, message: '请输入验证码' }]"
+              />
+              <wd-button
+                size="small"
+                type="primary"
+                plain
+                @click="getSmsCode"
+                :disabled="smsCodeDisabled || !isPhoneValid"
+                custom-style="margin-left: 10px;"
+              >
+                {{ smsCodeButtonText }}
+              </wd-button>
+            </view>
+          </wd-cell>
+        </wd-cell-group>
+      </wd-form>
+    </view>
+
+    <!-- 提交按钮 -->
+    <view class="fixed-bottom bg-white p-4 border-t border-gray-100">
+      <wd-button type="primary" block size="large" @click="handleSubmit" :loading="submitLoading">
+        确认领取
+      </wd-button>
+    </view>
+
+    <!-- loading -->
+    <wd-overlay :show="overlayShow">
+      <view class="wrapper w-full h-full flex items-center justify-center">
+        <wd-loading />
+      </view>
+    </wd-overlay>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { reactive, ref, computed, onUnmounted, onMounted } from 'vue'
+import { useCouponStore } from '@/store/coupon'
+import { useMessage } from 'wot-design-uni'
+import { onLoad } from '@dcloudio/uni-app'
+import UploadComponent from '@/components/UploadComponent.vue'
+
+const couponStore = useCouponStore()
+const message = useMessage()
+
+const productsid = ref('')
+const couponid = ref('')
+
+const formRef = ref<any>()
+const formData = reactive({
+  userstype: '个人', // 用户类型,默认个人
+  usersname: '', // 姓名或企业名称
+  idNumber: '', // 证件号
+
+  // 移除旧的idPhoto字段,替换为文件上传相关字段
+  // idPhoto: '', // 证件照片
+
+  // 身份证照片(个人用户)
+  idCardFiles: [], // 身份证照片文件列表
+  idCardIds: [], // 身份证照片ID列表
+
+  // 营业执照(企业用户)
+  businessLicenseFiles: [], // 营业执照照片文件列表
+  businessLicenseIds: [], // 营业执照照片ID列表
+
+  phone: '', // 手机号
+  smsCode: '', // 短信验证码
+})
+
+const usersnameLabel = computed(() => (formData.userstype === '个人' ? '姓名' : '企业名称'))
+const idNumberLabel = computed(() =>
+  formData.userstype === '个人' ? '身份证号' : '统一社会信用代码',
+)
+const idPhotoLabel = computed(() => (formData.userstype === '个人' ? '身份证正面' : '营业执照'))
+
+const overlayShow = ref(false)
+const submitLoading = ref(false)
+
+// 手机号验证相关
+const isPhoneValid = ref(false)
+const phoneReg = /^1[3-9]\d{9}$/
+
+function validatePhone() {
+  if (!formData.phone) {
+    isPhoneValid.value = false
+    return
+  }
+  isPhoneValid.value = phoneReg.test(formData.phone)
+  if (!isPhoneValid.value && formData.phone) {
+    uni.showToast({ title: '请输入正确的手机号码', icon: 'none' })
+  }
+}
+
+// 短信验证码相关
+const smsCodeButtonText = ref('获取验证码')
+const smsCodeDisabled = ref(false)
+let countdownTimer: number | null = null
+
+async function getSmsCode() {
+  validatePhone()
+  if (!isPhoneValid.value) {
+    uni.showToast({ title: '请输入正确的手机号码', icon: 'none' })
+    return
+  }
+
+  uni.showToast({ title: '验证码已发送', icon: 'none' })
+  smsCodeDisabled.value = true
+  let countdown = 60
+  smsCodeButtonText.value = `${countdown}s后重试`
+
+  countdownTimer = setInterval(() => {
+    countdown--
+    if (countdown <= 0) {
+      if (countdownTimer) clearInterval(countdownTimer)
+      smsCodeButtonText.value = '获取验证码'
+      smsCodeDisabled.value = false
+    } else {
+      smsCodeButtonText.value = `${countdown}s后重试`
+    }
+  }, 1000)
+}
+
+// 用户类型切换
+function handleUserTypeChange() {
+  // 清空相关字段以便用户重新输入和校验
+  formData.usersname = ''
+  formData.idNumber = ''
+
+  // 清空证件照片上传
+  if (formData.userstype === '个人') {
+    formData.idCardFiles = []
+    formData.idCardIds = []
+    formData.businessLicenseFiles = []
+    formData.businessLicenseIds = []
+  } else {
+    formData.idCardFiles = []
+    formData.idCardIds = []
+    formData.businessLicenseFiles = []
+    formData.businessLicenseIds = []
+  }
+}
+
+// 提交表单
+async function handleSubmit() {
+  try {
+    const valid = await formRef.value.validate()
+    if (!valid) {
+      return
+    }
+
+    validatePhone()
+    if (!isPhoneValid.value) {
+      uni.showToast({ title: '请输入正确的手机号码', icon: 'none' })
+      return
+    }
+
+    // 验证证件照片上传
+    const hasUploadedFiles =
+      formData.userstype === '个人'
+        ? formData.idCardIds.length > 0
+        : formData.businessLicenseIds.length > 0
+
+    if (!hasUploadedFiles) {
+      uni.showToast({
+        title: `请上传${formData.userstype === '个人' ? '身份证照片' : '营业执照照片'}`,
+        icon: 'none',
+      })
+      return
+    }
+
+    submitLoading.value = true
+    overlayShow.value = true
+
+    // 获取证件照片IDs
+    const fileIds =
+      formData.userstype === '个人'
+        ? formData.idCardIds.map((item) => item.id).join(',')
+        : formData.businessLicenseIds.map((item) => item.id).join(',')
+
+    // 模拟API调用
+    await new Promise((resolve) => setTimeout(resolve, 1500))
+
+    // 调用领取优惠券API - 注意:这里的API参数需要根据您的实际接口调整
+    // await couponStore.receiveCoupon({
+    //   couponid: couponid.value,
+    //   coupon2phone: formData.phone,
+    //   coupon2productids: productsid.value,
+    //   userstype: formData.userstype,
+    //   usersname: formData.usersname,
+    //   idNumber: formData.idNumber,
+    //   fileIds: fileIds, // 上传的文件ID字符串
+    //   smsCode: formData.smsCode,
+    //   // ... 其他可能需要的参数
+    // })
+
+    message
+      .alert({
+        msg: '优惠券领取成功!',
+        title: '提示',
+        confirmButtonText: '确定',
+      })
+      .then(() => {
+        // 跳转回formStep3页面
+        // 注意:需要确保formStep3页面能够正确处理返回逻辑,比如刷新优惠券列表
+        uni.navigateBack()
+      })
+  } catch (error) {
+    console.error('领取优惠券出错:', error)
+    message.alert({
+      msg: '操作失败,请稍后重试',
+      title: '提示',
+    })
+  } finally {
+    submitLoading.value = false
+    overlayShow.value = false
+  }
+}
+
+onLoad(async (query: any) => {
+  productsid.value = query.productsid || ''
+  couponid.value = query.couponid || ''
+  // 可以根据 query 中的参数做一些初始化操作
+})
+onUnmounted(() => {
+  if (countdownTimer) {
+    clearInterval(countdownTimer)
+  }
+})
+
+// 表单校验规则
+const rules = {
+  userstype: [{ required: true, message: '请选择用户类型' }],
+  usersname: [{ required: true, message: '请输入名称/企业名称' }],
+  idNumber: [{ required: true, message: '请输入证件号' }],
+
+  // 移除旧的idPhoto验证规则
+  // idPhoto: [{ required: true, message: '请上传证件照片' }],
+
+  // 根据用户类型添加自定义验证规则
+  idCardIds: [
+    {
+      required: true,
+      validator: (val) => formData.userstype !== '个人' || (val && val.length > 0),
+      message: '请上传身份证照片',
+    },
+  ],
+  businessLicenseIds: [
+    {
+      required: true,
+      validator: (val) => formData.userstype !== '企业' || (val && val.length > 0),
+      message: '请上传营业执照照片',
+    },
+  ],
+
+  phone: [
+    { required: true, message: '请输入手机号码' },
+    { required: false, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' },
+  ],
+  smsCode: [{ required: true, message: '请输入验证码' }],
+}
+
+// 将校验规则绑定到form
+onMounted(() => {
+  // 初始化其他必要的操作
+})
+</script>
+
+<style lang="scss" scoped>
+.rules-text {
+  line-height: 1.6;
+}
+
+.fixed-bottom {
+  position: fixed;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 100;
+}
+
+// 针对 wd-field 内的 wd-input, wd-radio-group 等组件去除边框或调整样式
+:deep(.wd-cell-group .wd-input) {
+  // If they don't have a border by default or if no-border is not working as expected
+  // Example:
+  // border-bottom: 1px solid #eee;
+}
+:deep(.wd-cell-group .wd-input__inner) {
+  // If no-border was intended to remove internal padding/borders of wd-input for wd-field
+  // We might not need this if wd-input itself looks fine as a direct child of wd-cell-group.
+  // The no-border prop on wd-input might be sufficient.
+}
+
+// For wd-cell containing radio group or other custom layouts
+:deep(.custom-cell .wd-cell__value) {
+  flex: 1; // Allow radio group or other content to take full width
+}
+:deep(.custom-cell .wd-radio-group) {
+  // specific styles for radio group if needed
+}
+
+// 调整获取验证码按钮的样式,如果需要
+// :deep(.wd-button--small) {
+//   // padding: 0 8px;
+// }
+
+.wrapper {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+}
+</style>

+ 1 - 0
src/types/uni-pages.d.ts

@@ -10,6 +10,7 @@ interface NavigateToOptions {
        "/pages/form/formStep1" |
        "/pages/form/formStep2" |
        "/pages/form/formStep3" |
+       "/pages/form/formStep3a" |
        "/pages/form/formStep4" |
        "/pages/merchant/index" |
        "/pages/mine/index" |