feat: 新增确认送达弹框组件、添加安卓打包测试证书、骑手配送流程接口对接

This commit is contained in:
admin
2026-02-24 11:58:30 +08:00
parent b85833690f
commit bc1833ec89
25 changed files with 2982 additions and 1205 deletions

View File

@@ -3,23 +3,26 @@
<view class="page">
<up-form ref="acctForm" :model="form" :rules="rules" labelPosition="left" labelWidth="120">
<up-form-item label="开户行城市" prop="bankCity" :required="true">
<up-input readonly v-model="bankCityLabel" placeholder="省-市" @tap="regionShow = true" />
<up-input readonly v-model="bankCityLabel" placeholder="省-市-区" @tap="regionShow = true" />
</up-form-item>
<up-form-item label="开户行" prop="bankName" :required="true">
<up-picker hasInput :columns="bankOptions" v-model="bankNameLabel" @confirm="onBankConfirm">
<template #trigger>
<up-input readonly v-model="bankNameLabel" placeholder="请选择开户行" />
</template>
</up-picker>
<up-form-item label="开户行" prop="bankName" :required="true">
<!-- 点击打开银行选择弹框 -->
<view class="bank-selector" @click="openBankPopup">
<up-input readonly v-model="bankNameLabel" placeholder="请选择开户行" disabled disabledColor="#fff" />
<view class="selector-arrow">
<up-icon name="arrow-down" size="14" color="#999"></up-icon>
</view>
</view>
</up-form-item>
<up-form-item label="开户行网点名称" prop="bankBranch" :required="true">
<up-picker hasInput :columns="branchOptions" v-model="bankBranchLabel" @confirm="onBranchConfirm">
<!-- <up-picker hasInput :columns="branchOptions" v-model="bankBranchLabel" @confirm="onBranchConfirm">
<template #trigger>
<up-input readonly v-model="bankBranchLabel" placeholder="请选择网点名称" />
</template>
</up-picker>
</up-picker> -->
<up-input v-model="form.bankBranch" placeholder="请输入网点名称" />
</up-form-item>
<up-form-item label="银行卡号" prop="cardNo" :required="true">
@@ -40,8 +43,8 @@
<up-input v-model="form.phone" placeholder="预留手机号码" type="number" maxlength="11" />
</view>
<view style="width:160rpx;margin-left:10rpx;">
<up-button :disabled="countdown > 0" plain @click="sendCode">
{{ countdown > 0 ? countdown + 's' : '获取验证码' }}
<up-button :disabled="countdown > 0" plain @click="handleGetSmsCode">
{{ smsBtnText }}
</up-button>
</view>
</view>
@@ -61,163 +64,457 @@
</view>
</up-form>
</view>
<su-region-picker level="2" :show="regionShow" @confirm="onRegionConfirm" @cancel="regionShow = false" />
<su-region-picker level="3" :show="regionShow" @confirm="onRegionConfirm" @cancel="regionShow = false" />
<!-- 银行选择弹框 -->
<up-popup :show="bankPopupShow" mode="bottom" @close="closeBankPopup" :round="16" safeAreaInsetBottom>
<view class="bank-popup">
<view class="bank-popup-header">
<text class="bank-popup-title">选择开户行</text>
<view class="bank-popup-close" @click="closeBankPopup">
<up-icon name="close" size="20" color="#999"></up-icon>
</view>
</view>
<!-- 搜索框 -->
<view class="bank-search-box">
<view class="bank-search-input-wrap">
<up-icon name="search" size="16" color="#999"></up-icon>
<input class="bank-search-input" v-model="bankSearchKeyword" placeholder="搜索银行名称" @input="onBankSearch" />
</view>
</view>
<!-- 银行列表 -->
<scroll-view class="bank-list" scroll-y="true">
<view v-for="(bankName, bankCode) in filteredBankList" :key="bankCode" class="bank-item"
@click="onSelectBank(bankCode, bankName)">
<text class="bank-item-name">{{ bankName }}</text>
<up-icon v-if="form.bankCode === bankCode" name="checkmark" size="16" color="#09aaff"></up-icon>
</view>
<view v-if="filteredBankList.length === 0" class="bank-empty">
<text>未找到相关银行</text>
</view>
</scroll-view>
</view>
</up-popup>
</s-layout>
</template>
<script setup>
import { reactive, ref, onBeforeMount } from 'vue'
import {
reactive,
ref,
computed,
onBeforeMount
} from 'vue'
import bankListData from './bankList.json';
import DeliveryApi from '@/sheep/api/member/delivery';
import {
getSmsCode,
getSmsTimer
} from '@/sheep/hooks/useModal';
const form = reactive({
bankCity: '',
bankName: '',
bankBranch: '',
cardNo: '',
cardHolder: '',
bankCode: '',
phone: '',
captcha: '',
})
const form = reactive({
bankCity: '',
bankName: '',
bankBranch: '',
cardNo: '',
cardHolder: '',
bankCode: '',
phone: '',
captcha: '',
})
const rules = {
bankCity: [{ required: true, message: '请选择开户城市' }],
bankName: [{ required: true, message: '请选择开户行别' }],
bankBranch: [{ required: true, message: '请选择网点名称' }],
cardNo: [{ required: true, message: '请输入银行卡号' }],
cardHolder: [{ required: true, message: '请输入持卡人姓名' }],
phone: [
{ required: true, message: '请输入手机号' },
{ pattern: /^1\d{10}$/, message: '请输入正确的手机号码' },
],
captcha: [{ required: true, message: '请输入验证码' }],
}
const acctForm = ref(null)
const regionShow = ref(false)
const bankOptions = [
['中国工商银行', '中国建设银行', '中国农业银行', '中国银行', '交通银行', '招商银行']
]
const branchOptions = [
['请选择网点']
]
const bankNameLabel = ref([])
const bankBranchLabel = ref([])
const bankCityLabel = ref('')
const countdown = ref(0)
let timer = null
const agree = ref(false)
function onBankConfirm(selected) {
const first = Array.isArray(selected) ? selected[0] : selected
bankNameLabel.value = first?.value || first || ''
form.bankName = bankNameLabel.value
// 模拟获取分支列表,根据银行设置简单示例
branchOptions[0] = bankNameLabel.value ? [`${bankNameLabel.value} 总行`, `${bankNameLabel.value} 广州分行`, `${bankNameLabel.value} 天河支行`] : ['请选择网点']
}
function onBranchConfirm(selected) {
const first = Array.isArray(selected) ? selected[0] : selected
bankBranchLabel.value = first?.value || first || ''
form.bankBranch = bankBranchLabel.value
}
function onRegionConfirm(result) {
console.log("result", result);
form.bankCity = result
bankCityLabel.value = `${result.province_name || ''} ${result.city_name || ''}`.trim()
regionShow.value = false
}
function sendCode() {
// 简单校验手机号
if (!/^1\d{10}$/.test(form.phone)) {
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
return
const rules = {
bankCity: [{
required: true,
message: '请选择开户城市'
}],
bankName: [{
required: true,
message: '请选择开户行别'
}],
bankBranch: [{
required: true,
message: '请选择网点名称'
}],
cardNo: [{
required: true,
message: '请输入银行卡号'
}],
cardHolder: [{
required: true,
message: '请输入持卡人姓名'
}],
phone: [{
required: true,
message: '请输入手机号'
},
{
pattern: /^1\d{10}$/,
message: '请输入正确的手机号码'
},
],
captcha: [{
required: true,
message: '请输入验证码'
}],
}
if (countdown.value > 0) return
// 触发发送(此处模拟)
uni.showToast({ title: '验证码已发送', icon: 'none' })
countdown.value = 60
timer = setInterval(() => {
if (countdown.value <= 1) {
clearInterval(timer)
countdown.value = 0
timer = null
} else {
countdown.value -= 1
}
}, 1000)
}
async function onSubmitAccount() {
try {
await acctForm.value.validate()
if (!agree.value) {
uni.showToast({ title: '请先同意骑手协议', icon: 'none' })
const acctForm = ref(null)
const regionShow = ref(false)
const bankPopupShow = ref(false)
const bankSearchKeyword = ref('')
const bankOptions = [
['中国工商银行', '中国建设银行', '中国农业银行', '中国银行', '交通银行', '招商银行']
]
const branchOptions = [
['请选择网点']
]
const bankNameLabel = ref([])
const bankBranchLabel = ref([])
const bankCityLabel = ref('')
const countdown = ref(0)
let timer = null
const agree = ref(false)
// 获取验证码按钮文本
const smsBtnText = computed(() => {
return getSmsTimer('accountInfo', form.phone)
})
// 获取验证码
function handleGetSmsCode() {
if (!form.phone) {
uni.showToast({
title: '请输入手机号',
icon: 'none'
})
return
}
// 提交逻辑(示例):打印并提示
console.log('结算表单', JSON.parse(JSON.stringify(form)))
uni.showToast({ title: '提交申请成功', icon: 'none' })
// 跳转到审核中页面
setTimeout(() => {
uni.navigateTo({ url: '/pages/registered/audit' })
}, 600)
} catch (e) {
console.warn('结算表单校验未通过', e)
}
}
onBeforeMount(() => {
// 尝试从注册页恢复部分信息(如持卡人姓名)
try {
const saved = uni.getStorageSync('riderFormData') || null
if (saved) {
form.cardHolder = saved.realName || ''
// 调用 getSmsCode 发送验证码
getSmsCode('registerDelivery', form.phone)
}
// 银行列表数据
const bankList = bankListData
// 筛选后的银行列表(带搜索功能)
const filteredBankList = computed(() => {
if (!bankSearchKeyword.value.trim()) {
return bankList
}
} catch (err) {
// ignore
}
})
const keyword = bankSearchKeyword.value.trim().toLowerCase()
const result = {}
for (const [code, name] of Object.entries(bankList)) {
if (name.toLowerCase().includes(keyword)) {
result[code] = name
}
}
return result
})
// 打开银行选择弹框
function openBankPopup() {
bankPopupShow.value = true
bankSearchKeyword.value = ''
}
// 关闭银行选择弹框
function closeBankPopup() {
bankPopupShow.value = false
}
// 搜索银行
function onBankSearch() {
// 搜索逻辑由 computed 属性 filteredBankList 自动处理
}
// 选择银行
function onSelectBank(bankCode, bankName) {
console.log("银行名称:", bankName);
form.bankCode = bankCode
form.bankName = bankName
bankNameLabel.value = bankName
closeBankPopup()
}
function onBranchConfirm(selected) {
const first = Array.isArray(selected) ? selected[0] : selected
bankBranchLabel.value = first?.value || first || ''
form.bankBranch = bankBranchLabel.value
}
function onRegionConfirm(result) {
console.log("result", result);
form.bankCity = result
bankCityLabel.value = `${result.province_name || ''} ${result.city_name || ''} ${result.district_name || ''}`.trim()
regionShow.value = false
}
function sendCode() {
// 简单校验手机号
if (!/^1\d{10}$/.test(form.phone)) {
uni.showToast({
title: '请输入正确手机号',
icon: 'none'
})
return
}
if (countdown.value > 0) return
// 触发发送(此处模拟)
uni.showToast({
title: '验证码已发送',
icon: 'none'
})
countdown.value = 60
timer = setInterval(() => {
if (countdown.value <= 1) {
clearInterval(timer)
countdown.value = 0
timer = null
} else {
countdown.value -= 1
}
}, 1000)
}
async function onSubmitAccount() {
try {
await acctForm.value.validate()
if (!agree.value) {
uni.showToast({
title: '请先同意骑手协议',
icon: 'none'
})
return
}
// 从缓存读取上一个页面的数据
let savedData = {}
try {
savedData = JSON.parse(uni.getStorageSync('riderRegisterData')) || {}
console.log("上一个页面数据:", savedData);
} catch (err) {
console.warn('读取缓存数据失败', err)
}
// 获取地区信息form.bankCity 存储的是地区选择结果对象)
const regionData = form.bankCity || {}
// 构建提交数据
const submitData = {
// 第一个页面的数据
username: savedData.username || '',
idNumber: savedData.idNumber || '',
idStartTime: savedData.idStartTime || '',
idEndTime: savedData.idEndTime || '',
idValidType: savedData.idValidType || 2,
gender: savedData.gender || 1,
emergencyContactName: savedData.emergencyContactName || '',
emergencyContactPhone: savedData.emergencyContactPhone || '',
idFrontUrl: savedData.idFrontUrl || '',
idBackUrl: savedData.idBackUrl || '',
occupationType: savedData.occupationType || 1,
employmentType: savedData.employmentType || 1,
partTimePeriods: savedData.partTimePeriods || [],
healthCertificateUrl: savedData.healthCertificateUrl || '',
healthCertificateNo: savedData.healthCertificateNo || '',
healthCertificateType: savedData.healthCertificateType || 1,
healthCertificateStartTime: savedData.healthCertificateStartTime || '',
healthCertificateEndTime: savedData.healthCertificateEndTime || '',
// 第二个页面的数据
bankAccountPhone: form.phone || '',
bankCardNumber: form.cardNo || '',
bankCity: regionData.city_name || '',
bankCityCode: regionData.city_id || '',
bankDistrict: regionData.district_name || '',
bankDistrictCode: regionData.district_id || '',
bankProvince: regionData.province_name || '',
bankProvinceCode: regionData.province_id || '',
cardholderName: form.cardHolder || '',
code: form.captcha || '',
}
console.log('提交数据给后端:', submitData)
// 调用后端API注册骑手
uni.showLoading({ title: '提交中...' })
const res = await DeliveryApi.registerRider(submitData)
uni.hideLoading()
if (res.code === 0 && res.data === true) {
await sheep.$store('user').getInfo();
// // 提交成功,清除缓存
// try {
// uni.removeStorageSync('riderRegisterData')
// } catch (e) {
// console.warn('清除缓存失败', e)
// }
uni.showToast({ title: '提交申请成功', icon: 'success' })
// 跳转到审核中页面
setTimeout(() => {
uni.reLaunch({ url: '/pages/registered/audit' })
}, 1500)
} else {
uni.showToast({ title: res.msg || '提交失败,请重试', icon: 'none' })
}
} catch (e) {
uni.hideLoading()
console.error('提交骑手注册申请异常:', e)
uni.showToast({ title: '提交失败,请重试', icon: 'none' })
}
}
onBeforeMount(() => {
// 尝试从注册页恢复部分信息(如持卡人姓名)
try {
const saved = uni.getStorageSync('riderRegisterData') || null
console.log("上一个页面数据:", saved);
} catch (err) {
// ignore
}
})
</script>
<style lang="scss" scoped>
.page {
padding: 38rpx;
background: #fff;
}
.code-row {
display: flex;
// gap: 12px;
align-items: center;
}
.agree-row {
display: flex;
align-items: center;
padding: 20rpx 0;
gap: 12rpx;
color: #999;
}
.checkbox {
width: 28rpx;
height: 28rpx;
border: 1px solid #ccc;
border-radius: 50%;
}
.checkbox.checked {
background: #09aaff;
border-color: #09aaff;
}
.agree-text {
font-size: 24rpx;
color: #999;
}
.link {
color: #09aaff;
}
.submit-row {
margin-top: 20px;
}
.page {
padding: 38rpx;
background: #fff;
}
</style>
.code-row {
display: flex;
// gap: 12px;
align-items: center;
}
.agree-row {
display: flex;
align-items: center;
padding: 20rpx 0;
gap: 12rpx;
color: #999;
}
.checkbox {
width: 28rpx;
height: 28rpx;
border: 1px solid #ccc;
border-radius: 50%;
}
.checkbox.checked {
background: #09aaff;
border-color: #09aaff;
}
.agree-text {
font-size: 24rpx;
color: #999;
}
.link {
color: #09aaff;
}
.submit-row {
margin-top: 20px;
}
/* 银行选择器样式 */
.bank-selector {
display: flex;
align-items: center;
background: #fff;
// border: 1rpx solid #e6e6e6;
border: none;
border-radius: 6rpx;
padding: 0 12rpx;
}
.bank-selector .uni-input {
flex: 1;
border: none;
padding: 0;
}
.selector-arrow {
margin-left: 8rpx;
}
/* 银行选择弹框样式 */
.bank-popup {
max-height: 70vh;
display: flex;
flex-direction: column;
}
.bank-popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.bank-popup-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.bank-popup-close {
padding: 10rpx;
margin-right: -10rpx;
}
.bank-search-box {
padding: 20rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.bank-search-input-wrap {
display: flex;
align-items: center;
background: #f5f5f5;
border-radius: 8rpx;
padding: 16rpx 20rpx;
gap: 12rpx;
}
.bank-search-input {
flex: 1;
font-size: 28rpx;
background: transparent;
border: none;
outline: none;
}
.bank-list {
max-height: 60vh;
padding: 0 20rpx;
}
.bank-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28rpx 20rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.bank-item-name {
font-size: 28rpx;
color: #333;
}
.bank-empty {
padding: 60rpx 0;
text-align: center;
color: #999;
font-size: 28rpx;
}
</style>