consumer-app/pages/profile/realNameAuth.vue

580 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="real-name-auth-page">
<!-- 头部区域 -->
<NavHeader title="实名认证" />
<!-- 表单内容区 -->
<scroll-view class="form-content" scroll-y="true">
<!-- 基本信息 -->
<view class="form-section">
<view class="section-title">基本信息</view>
<!-- 真实姓名 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">真实姓名</text>
<input
class="input-field"
type="text"
v-model="formData.realName"
placeholder="请输入真实姓名"
maxlength="20"
/>
</view>
</view>
<!-- 证件类型 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">证件类型</text>
<picker
mode="selector"
:range="idTypeOptions"
range-key="label"
:value="idTypeIndex"
@change="handleIdTypeChange"
>
<view class="picker-view">
<text :class="['picker-text', !formData.idType ? 'placeholder' : '']">
{{ formData.idType ? idTypeOptions.find(item => item.value === formData.idType)?.label : '请选择证件类型' }}
</text>
</view>
</picker>
</view>
</view>
<!-- 证件号码 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">证件号码</text>
<input
class="input-field"
type="text"
v-model="formData.idNumber"
placeholder="请输入证件号码"
maxlength="30"
/>
</view>
</view>
</view>
<!-- 身份证照片 -->
<view class="form-section">
<view class="section-title">身份证照片</view>
<!-- 身份证正面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">身份证正面</text>
<view class="upload-box" @click="chooseImage('idFrontImg')">
<image
v-if="formData.idFrontImg"
class="uploaded-image"
:src="formData.idFrontImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
<!-- 身份证背面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">身份证背面</text>
<view class="upload-box" @click="chooseImage('idBackImg')">
<image
v-if="formData.idBackImg"
class="uploaded-image"
:src="formData.idBackImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
</view>
<!-- 驾驶证照片 -->
<view class="form-section">
<view class="section-title">驾驶证照片</view>
<!-- 驾驶证正面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">驾驶证正面</text>
<view class="upload-box" @click="chooseImage('driverLicenseFrontImg')">
<image
v-if="formData.driverLicenseFrontImg"
class="uploaded-image"
:src="formData.driverLicenseFrontImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
<!-- 驾驶证背面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">驾驶证背面</text>
<view class="upload-box" @click="chooseImage('driverLicenseBackImg')">
<image
v-if="formData.driverLicenseBackImg"
class="uploaded-image"
:src="formData.driverLicenseBackImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
</view>
<!-- 行驶证照片 -->
<view class="form-section">
<view class="section-title">行驶证照片</view>
<!-- 行驶证正面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">行驶证正面</text>
<view class="upload-box" @click="chooseImage('vehicleLicenseFrontImg')">
<image
v-if="formData.vehicleLicenseFrontImg"
class="uploaded-image"
:src="formData.vehicleLicenseFrontImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
<!-- 行驶证背面 -->
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">行驶证背面</text>
<view class="upload-box" @click="chooseImage('vehicleLicenseBackImg')">
<image
v-if="formData.vehicleLicenseBackImg"
class="uploaded-image"
:src="formData.vehicleLicenseBackImg"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传</text>
</view>
</view>
</view>
</view>
</view>
<!-- 备注信息 -->
<view class="form-section">
<view class="section-title">备注信息</view>
<view class="form-item">
<view class="textarea-wrapper">
<textarea
class="textarea-field"
v-model="formData.imgVerifyRemark"
placeholder="请输入备注信息(选填)"
maxlength="200"
:auto-height="true"
></textarea>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button
class="submit-btn"
:class="{ disabled: loading }"
:disabled="loading"
@click="handleSubmit"
>
{{ loading ? '提交中...' : '提交认证' }}
</button>
</view>
</scroll-view>
</view>
</template>
<script>
import { createRealNameInfo } from '@/api/profile.js'
import NavHeader from "@/components/NavHeader/NavHeader.vue";
export default {
components: {
NavHeader
},
data() {
return {
loading: false,
idTypeIndex: 0,
idTypeOptions: [
{ label: '身份证', value: 1 },
{ label: '其他', value: 2 }
],
formData: {
realName: '',
idType: null,
idNumber: '',
idFrontImg: '',
idBackImg: '',
driverLicenseFrontImg: '',
driverLicenseBackImg: '',
vehicleLicenseFrontImg: '',
vehicleLicenseBackImg: '',
imgVerifyRemark: ''
}
}
},
onLoad() {
},
methods: {
// 证件类型选择
handleIdTypeChange(e) {
this.idTypeIndex = e.detail.value
this.formData.idType = this.idTypeOptions[e.detail.value].value
},
// 选择图片
chooseImage(field) {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0]
// 先显示本地预览
this.formData[field] = tempFilePath
// 上传图片到服务器
this.uploadImage(tempFilePath, field)
},
fail: (err) => {
console.error('选择图片失败:', err)
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
// 上传图片
uploadImage(filePath, field) {
uni.showLoading({
title: '上传中...',
mask: true
})
// 获取token
const token = uni.getStorageSync('token')
const BASE_URL = 'https://siji.chenjuncn.top'
uni.uploadFile({
url: `${BASE_URL}/app-api/infra/file/upload`,
filePath: filePath,
name: 'file',
header: {
'Authorization': `Bearer ${token}`,
'tenant-id': '1'
},
success: (res) => {
uni.hideLoading()
try {
const data = JSON.parse(res.data)
if (data.code === 200 || data.code === 0) {
// 上传成功保存图片URL
const imageUrl = data.data?.url || data.data || data.url
if (imageUrl) {
this.formData[field] = imageUrl
uni.showToast({
title: '上传成功',
icon: 'success',
duration: 1500
})
} else {
throw new Error('上传成功但未返回图片地址')
}
} else {
throw new Error(data.message || data.msg || '上传失败')
}
} catch (error) {
console.error('解析上传结果失败:', error)
uni.showToast({
title: '上传失败,请重试',
icon: 'none'
})
// 上传失败,清除预览
this.formData[field] = ''
}
},
fail: (err) => {
uni.hideLoading()
console.error('上传图片失败:', err)
uni.showToast({
title: '上传失败,请检查网络',
icon: 'none'
})
// 上传失败,清除预览
this.formData[field] = ''
}
})
},
// 提交表单
async handleSubmit() {
// 基本验证
if (!this.formData.realName || !this.formData.realName.trim()) {
uni.showToast({
title: '请输入真实姓名',
icon: 'none'
})
return
}
if (!this.formData.idType) {
uni.showToast({
title: '请选择证件类型',
icon: 'none'
})
return
}
if (!this.formData.idNumber || !this.formData.idNumber.trim()) {
uni.showToast({
title: '请输入证件号码',
icon: 'none'
})
return
}
this.loading = true
try {
// 构建提交数据,只包含有值的字段
const submitData = {}
if (this.formData.realName) submitData.realName = this.formData.realName.trim()
if (this.formData.idType !== null) submitData.idType = this.formData.idType
if (this.formData.idNumber) submitData.idNumber = this.formData.idNumber.trim()
if (this.formData.idFrontImg) submitData.idFrontImg = this.formData.idFrontImg
if (this.formData.idBackImg) submitData.idBackImg = this.formData.idBackImg
if (this.formData.driverLicenseFrontImg) submitData.driverLicenseFrontImg = this.formData.driverLicenseFrontImg
if (this.formData.driverLicenseBackImg) submitData.driverLicenseBackImg = this.formData.driverLicenseBackImg
if (this.formData.vehicleLicenseFrontImg) submitData.vehicleLicenseFrontImg = this.formData.vehicleLicenseFrontImg
if (this.formData.vehicleLicenseBackImg) submitData.vehicleLicenseBackImg = this.formData.vehicleLicenseBackImg
if (this.formData.imgVerifyRemark) submitData.imgVerifyRemark = this.formData.imgVerifyRemark.trim()
await createRealNameInfo(submitData)
uni.showToast({
title: '提交成功',
icon: 'success'
})
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('提交失败:', error)
// 错误信息已在request中统一处理
} finally {
this.loading = false
}
}
}
}
</script>
<style lang="scss" scoped>
.real-name-auth-page {
min-height: 100vh;
background: #e2e8f1;
}
.form-content {
height: calc(100vh - 120rpx);
padding: 0 30rpx 40rpx;
box-sizing: border-box;
}
.form-section {
margin-bottom: 40rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
margin-bottom: 24rpx;
padding-left: 10rpx;
}
}
.form-item {
margin-bottom: 30rpx;
.input-wrapper {
position: relative;
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
display: flex;
align-items: center;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.input-label {
width: 160rpx;
font-size: 28rpx;
color: #333333;
font-weight: 500;
flex-shrink: 0;
}
.input-field {
flex: 1;
font-size: 28rpx;
color: #1a1819;
}
.picker-view {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.picker-text {
font-size: 28rpx;
color: #1a1819;
&.placeholder {
color: #999999;
}
}
.picker-arrow {
font-size: 40rpx;
color: #cccccc;
line-height: 1;
}
}
}
.upload-wrapper {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.upload-label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
margin-bottom: 20rpx;
}
.upload-box {
width: 100%;
height: 300rpx;
border: 2rpx dashed #d0d0d0;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fafafa;
position: relative;
overflow: hidden;
.uploaded-image {
width: 100%;
height: 100%;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16rpx;
.upload-icon {
font-size: 60rpx;
color: #999999;
line-height: 1;
}
.upload-text {
font-size: 24rpx;
color: #999999;
}
}
}
}
.textarea-wrapper {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.textarea-field {
width: 100%;
min-height: 200rpx;
font-size: 28rpx;
color: #1a1819;
line-height: 1.6;
}
}
}
.submit-section {
margin-top: 40rpx;
padding-bottom: 40rpx;
.submit-btn {
width: 100%;
height: 88rpx;
background: linear-gradient(135deg, #004294 0%, #0066cc 100%);
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
display: flex;
align-items: center;
justify-content: center;
&::after {
border: none;
}
&.disabled {
background: #cccccc;
color: #999999;
}
}
}
</style>