zdtap-uniapp-main/pages/index/registration.vue

979 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<view class="page-content">
<!-- 步骤条 -->
<view class="step-bar">
<view class="step-icons flex align-center">
<view><image src="@/static/one.png" class="step-icon" mode="aspectFit"></image></view>
<view><image src="@/static/arrow-right.png" class="step-arrow" mode="aspectFit"></image></view>
<view><image src="@/static/two.png" class="step-icon" mode="aspectFit"></image></view>
<view><image src="@/static/arrow-right.png" class="step-arrow" mode="aspectFit"></image></view>
<view><image src="@/static/three.png" class="step-icon" mode="aspectFit"></image></view>
</view>
<view class="step-labels flex align-center">
<view>提交申请</view>
<view>平台审核</view>
<view>享受返利</view>
</view>
</view>
<!-- 咨询入口 -->
<view class="consult-box flex align-center justify-between">
<text class="consult-text">入驻助手帮你解决入驻问题快速上手赢取品牌返利</text>
<button class="consult-btn" @click="handleConsult">咨询</button>
</view>
<!-- 所需材料说明 -->
<view class="materials-box">
<view class="section-title">所需材料</view>
<view class="material-item">
<view class="material-info">
<text class="material-name">1.营业执照</text>
<text class="material-desc">需提供有效期内商家本人的与门头照片相符合的营业执照</text>
</view>
<image src="@/static/bg/bgs.png" mode="aspectFit" class="material-image"></image>
</view>
<view class="material-item">
<view class="material-info">
<text class="material-name">2.门头照片</text>
<text class="material-desc">需提供营业执照对应的门店门头照片一张</text>
</view>
<image src="@/static/bg/bgs.png" mode="aspectFit" class="material-image"></image>
</view>
</view>
<!-- 门店资料表单 -->
<view class="store-form">
<view class="section-title">门店资料</view>
<!-- 所在地区 -->
<view class="form-item">
<input
v-model="displayArea"
placeholder="所在地区"
readonly
disabled
@click.stop="handleShowAreaPicker"
class="form-input location-input"
/>
</view>
<!-- 门店地址 -->
<view class="form-item">
<view class="location-picker" @click="getMyLocation">
<text class="location-text" :class="{ 'is-placeholder': !form.address }">
{{ form.address || '门店地址' }}
</text>
<text class="cuIcon-locationfill location-icon"></text>
</view>
</view>
<!-- 门店名称 -->
<view class="form-item">
<input
v-model="form.bar_name"
placeholder="门店名称"
class="form-input"
/>
</view>
<!-- 联系电话 -->
<view class="form-item">
<input
v-model="form.bar_contact_phone"
placeholder="联系电话"
type="number"
maxlength="11"
@input="validatePhone"
class="form-input"
/>
</view>
<!-- 营业执照上传 -->
<view class="form-item">
<view class="upload-container">
<view class="upload-title">营业执照</view>
<view class="upload-box" @click="handleUpload('business_license')">
<image v-if="previewImages.business_license"
:src="previewImages.business_license"
mode="aspectFill"
class="preview-image">
</image>
<view v-else class="upload-placeholder">
<text class="cuIcon-camerafill"></text>
<text class="upload-text">上传营业执照</text>
<text class="upload-hint">需提供有效期内的营业执照</text>
</view>
<view v-if="uploadStatus.business_license === 'uploading'" class="upload-mask">
<view class="upload-loading">上传中...</view>
</view>
</view>
</view>
</view>
<!-- 门店照片上传 -->
<view class="form-item">
<view class="upload-container">
<view class="upload-title">门店照片</view>
<view class="upload-box" @click="handleUpload('storefront_photo')">
<image v-if="previewImages.storefront_photo"
:src="previewImages.storefront_photo"
mode="aspectFill"
class="preview-image">
</image>
<view v-else class="upload-placeholder">
<text class="cuIcon-camerafill"></text>
<text class="upload-text">上传门店照片</text>
<text class="upload-hint">需提供清晰的门头照片</text>
</view>
<view v-if="uploadStatus.storefront_photo === 'uploading'" class="upload-mask">
<view class="upload-loading">上传中...</view>
</view>
</view>
</view>
</view>
</view>
<!-- 地区选择器组件 -->
<regionPicker
:show.sync="showPopup"
@selected="onAreaSelected"
@close="handlePopupClose"
/>
<!-- 咨询弹窗 -->
<uni-popup ref="consultRefs" type="center" :is-mask-click="false">
<view class="consult-popup">
<view class="popup-close" @click="consultClick">
<image src="@/static/icons/cencels.svg" mode="aspectFit" class="close-icon"></image>
</view>
<view class="popup-content"></view>
</view>
</uni-popup>
<!-- 成功提示弹窗 -->
<uni-popup ref="successRef" type="center" :is-mask-click="false">
<view class="success-popup">
<image src="@/static/cg.png" mode="aspectFit" class="success-icon"></image>
<text class="success-text">提交成功等待审核</text>
<button class="success-btn" @click="toHome">进入首页</button>
</view>
</uni-popup>
</view>
<!-- 底部提交按钮 -->
<view class="submit-bar">
<button
class="submit-btn"
:disabled="!isFormValid"
@click="submitForm"
>
提交入驻
</button>
</view>
</view>
</template>
<script>
import regionPicker from '@/components/regionPicker.vue'
import { barRegister } from '@/api/login.js'
import { base_url } from '@/api/config.js'
export default {
name: 'Registration',
components: {
regionPicker
},
data() {
return {
// 表单数据
form: {
bar_name: '', // 酒吧名称必填最大255
bar_contact_phone: '', // 联系电话最大20
province: '', // 所在省最大20
city: '', // 所在城市最大20
district: '', // 所在区最大50
address: '', // 详细地址最大255
business_license: '', // 营业执照最大255
storefront_photo: '', // 门头照片最大255
latitude: '', // 纬度
longitude: '', // 经度
openId: '', // 用户openId
auth_state: 0, // 认证状态0待审核
},
// 用于显示的完整地区文本
displayArea: '',
// 图片预览
previewImages: {
business_license: '',
storefront_photo: ''
},
// 上传状态
uploadStatus: {
business_license: '',
storefront_photo: ''
},
// 地区选择
showPopup: false,
// 用户信息
userInfo: {},
}
},
computed: {
// 表单验证
isFormValid() {
// 添加日志输出,方便调试
console.log('表单验证状态:', {
bar_name: !!this.form.bar_name,
bar_contact_phone: !!this.form.bar_contact_phone,
phone_format: this.checkPhoneFormat(),
province: !!this.form.province,
city: !!this.form.city,
district: !!this.form.district,
address: !!this.form.address,
latitude: !!this.form.latitude,
longitude: !!this.form.longitude,
business_license: !!this.form.business_license,
storefront_photo: !!this.form.storefront_photo
});
return Boolean(
this.form.bar_name && // 酒吧名称
this.form.bar_contact_phone && // 联系电话
this.checkPhoneFormat() && // 手机号格式
this.form.province && // 省
this.form.city && // 市
this.form.district && // 区
this.form.address && // 详细地址
this.form.latitude && // 纬度
this.form.longitude && // 经度
this.form.business_license && // 营业执照
this.form.storefront_photo // 门头照片
);
}
},
watch: {
showPopup(newVal) {
if (!newVal) {
// 检查是否已有省市区数据
if (!this.form.province || !this.form.city || !this.form.district) {
this.form.province = '';
this.form.city = '';
this.form.district = '';
this.displayArea = '';
}
}
}
},
onLoad({ openId }) {
this.form.openId = openId
},
onHide() {
uni.hideLoading()
},
methods: {
// 防抖函数
debounce(fn, delay = 500) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
},
// 地区选择相关方法
handleShowAreaPicker() {
if (this.showPopup) return
this.showPopup = true
},
// 地区选择回调
onAreaSelected(province, city, area) {
try {
console.log('地区选择数据:', { province, city, area });
if (province?.label && city?.label && area?.label) {
// 分别存储省市区
this.form.province = province.label;
this.form.city = city.label;
this.form.district = area.label;
// 更新显示文本
this.displayArea = `${province.label} ${city.label} ${area.label}`.trim();
console.log('更新后的地区数据:', {
province: this.form.province,
city: this.form.city,
district: this.form.district,
displayArea: this.displayArea
});
this.showPopup = false;
} else {
throw new Error('地区信息不完整');
}
} catch (error) {
console.error('地区选择错误:', error);
uni.showToast({
title: error.message || '请选择完整的地区信息',
icon: 'none'
});
}
},
handlePopupClose() {
this.showPopup = false
},
// 位置选择相关方法
getMyLocation() {
uni.authorize({
scope: 'scope.userLocation',
success: () => {
this.handleChooseLocation()
},
fail: () => {
uni.showModal({
title: '位置权限',
content: '需要获取您的地理位置,请确认授权',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (settingRes) => {
if (settingRes.authSetting['scope.userLocation']) {
this.handleChooseLocation()
}
}
})
}
}
})
}
})
},
// 位置选择方法
handleChooseLocation() {
uni.chooseLocation({
success: (res) => {
console.log('位置选择结果:', res);
if (res.address && res.latitude && res.longitude) {
// 更新地址和经纬度
this.form.address = res.address;
this.form.latitude = res.latitude;
this.form.longitude = res.longitude;
// 尝试从地址中解析省市区
const addressParts = res.address.split(' ');
if (addressParts.length >= 3) {
this.form.province = addressParts[0];
this.form.city = addressParts[1];
this.form.district = addressParts[2];
// 更新显示文本
this.displayArea = `${this.form.province} ${this.form.city} ${this.form.district}`.trim();
console.log('解析后的地区数据:', {
province: this.form.province,
city: this.form.city,
district: this.form.district,
displayArea: this.displayArea
});
}
} else {
uni.showToast({
title: '请选择具体的位置信息',
icon: 'none'
});
}
},
fail: (err) => {
console.error('位置选择失败:', err);
if (err.errMsg !== 'chooseLocation:fail cancel') {
uni.showToast({
title: '获取位置失败',
icon: 'none'
});
}
}
});
},
// 手机号验证相关方法
validatePhone(e) {
const phone = e.target.value
const formatted = phone.replace(/\D/g, '').slice(0, 11)
// 确保不超过数据库字段长度
this.form.bar_contact_phone = formatted.slice(0, 20)
},
checkPhoneFormat() {
const phone = this.form.bar_contact_phone;
const isValid = /^1[3-9]\d{9}$/.test(phone);
console.log('手机号验证:', { phone, isValid });
return isValid;
},
// 图片上传相关方法
async handleUpload(key) {
try {
// 1. 选择图片
const [error, res] = await uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera']
}).then(res => [null, res]).catch(err => [err, null]);
if (error) {
throw new Error('选择图片失败');
}
const tempFilePath = res.tempFilePaths[0];
// 2. 获取图片信息
const [infoError, imageInfo] = await uni.getImageInfo({
src: tempFilePath
}).then(res => [null, res]).catch(err => [err, null]);
if (infoError) {
throw new Error('获取图片信息失败');
}
// 3. 验证图片大小限制5MB
if (imageInfo.size > 5 * 1024 * 1024) {
throw new Error('图片大小不能超过5MB');
}
// 4. 更新预览和状态
this.previewImages[key] = tempFilePath;
this.uploadStatus[key] = 'uploading';
// 5. 上传图片
const uploadUrl = base_url.endsWith('/') ? base_url + 'api/bar/common/upload' : base_url + '/api/bar/common/upload';
console.log('开始上传图片:', {
url: uploadUrl,
filePath: tempFilePath
});
const [uploadError, uploadRes] = await new Promise((resolve) => {
uni.uploadFile({
url: uploadUrl,
filePath: tempFilePath,
name: 'file',
formData: {
type: 'image'
},
success: (res) => {
try {
console.log('上传响应数据:', res.data);
const result = JSON.parse(res.data);
if (result.code === 200) {
if (result.url) {
resolve([null, result]);
} else {
resolve([new Error('上传成功但未返回图片地址'), null]);
}
} else {
resolve([new Error(result.msg || '上传失败'), null]);
}
} catch (error) {
console.error('解析响应失败:', error, '原始数据:', res.data);
resolve([new Error('解析响应失败'), null]);
}
},
fail: (err) => {
console.error('上传请求失败:', err);
resolve([err, null]);
}
});
});
if (uploadError) {
console.error('上传错误:', uploadError);
throw uploadError;
}
// 6. 更新表单数据
if (uploadRes.url) {
this.form[key] = uploadRes.url; // 确保更新到form对象中
this.previewImages[key] = uploadRes.url; // 更新预览图
this.uploadStatus[key] = 'success';
console.log('图片上传成功,更新表单数据:', {
key,
url: uploadRes.url,
form: this.form[key]
});
uni.showToast({
title: '上传成功',
icon: 'success'
});
} else {
throw new Error('未获取到图片地址');
}
} catch (error) {
console.error('图片上传失败:', error);
this.previewImages[key] = '';
this.uploadStatus[key] = 'error';
uni.showToast({
title: error.message || '上传失败',
icon: 'none'
});
}
},
// 表单提交相关方法
async submitForm() {
if (!this.isFormValid || !this.validateForm()) {
return;
}
// 显示加载提示
uni.showLoading({
title: '提交中',
mask: true
});
try {
// 构建提交数据
const submitData = {
...this.form,
auth_state: 0 // 设置默认认证状态
};
const res = await barRegister(submitData);
if (res.code === 200) {
this.userInfo = res.data.register;
uni.setStorageSync('token', res.data.token);
uni.setStorageSync('userInfo', this.userInfo);
// 隐藏加载提示
uni.hideLoading();
// 显示成功提示
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 1500
});
// 延迟跳转,让用户看到成功提示
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
});
}, 1500);
} else {
throw new Error(res.msg || '注册失败');
}
} catch (error) {
// 隐藏加载提示
uni.hideLoading();
// 显示错误提示
uni.showToast({
title: error.message || '提交失败',
icon: 'none',
duration: 2000
});
}
},
// 其他方法
toHome() {
uni.setStorageSync('userInfo', this.userInfo)
uni.reLaunch({
url: '/pages/index/index'
})
},
handleConsult() {
uni.navigateTo({
url: '/pagesMy/addAiad'
})
},
consultClick() {
this.$refs.consultRefs.close()
},
// 字段验证方法
validateField(value, maxLength) {
if (!value) return false
return String(value).length <= maxLength
},
// 表单验证方法
validateForm() {
// 字段长度验证
const validations = {
bar_name: { value: this.form.bar_name, maxLength: 255, label: '酒吧名称' },
bar_contact_phone: { value: this.form.bar_contact_phone, maxLength: 20, label: '联系电话' },
province: { value: this.form.province, maxLength: 20, label: '所在省' },
city: { value: this.form.city, maxLength: 20, label: '所在城市' },
district: { value: this.form.district, maxLength: 50, label: '所在区' },
address: { value: this.form.address, maxLength: 255, label: '详细地址' },
business_license: { value: this.form.business_license, maxLength: 255, label: '营业执照' },
storefront_photo: { value: this.form.storefront_photo, maxLength: 255, label: '门头照片' }
}
for (const [field, config] of Object.entries(validations)) {
if (!this.validateField(config.value, config.maxLength)) {
uni.showToast({
title: `${config.label}超出长度限制`,
icon: 'none'
})
return false
}
}
return true
}
}
}
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background-color: #F7F8FA;
}
.page-content {
padding: 24rpx 24rpx 200rpx;
box-sizing: border-box;
}
// 步骤条样式
.step-bar {
background: #FFFFFF;
padding: 42rpx 66rpx;
border-radius: 12rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
.step-icons {
justify-content: space-between;
margin-bottom: 18rpx;
.step-icon {
width: 94rpx;
height: 72rpx;
}
.step-arrow {
width: 44rpx;
height: 44rpx;
}
}
.step-labels {
justify-content: space-between;
font-size: 24rpx;
font-weight: 600;
color: #333;
}
}
// 咨询入口样式
.consult-box {
margin-top: 32rpx;
padding: 24rpx;
background: #FFF;
border-radius: 12rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
.consult-text {
width: 52%;
font-size: 24rpx;
color: #333;
}
.consult-btn {
width: 124rpx;
height: 48rpx;
margin-left: 180rpx;
line-height: 48rpx;
background: #D42E78;
color: #FFF;
font-size: 24rpx;
border-radius: 12rpx;
}
}
// 材料说明样式
.materials-box {
margin-top: 32rpx;
padding: 24rpx;
background: #FFF;
border-radius: 12rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
.material-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 28rpx;
.material-info {
width: 60%;
.material-name {
display: block;
font-size: 28rpx;
color: #3D3D3D;
margin-bottom: 8rpx;
}
.material-desc {
font-size: 24rpx;
color: #666;
}
}
.material-image {
width: 166rpx;
height: 112rpx;
}
}
}
// 表单样式
.store-form {
margin-top: 32rpx;
padding: 24rpx;
background: #FFF;
border-radius: 12rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
.form-item {
margin-bottom: 16rpx;
}
.form-input {
width: 100%;
height: 96rpx;
padding: 0 30rpx;
background: #FFF;
border: 1px solid #E5E5E5;
border-radius: 16rpx;
font-size: 28rpx;
color: #333;
transition: all 0.3s;
&:focus {
border-color: #4E63E0;
box-shadow: 0 0 0 2px rgba(78, 99, 224, 0.1);
}
&[readonly] {
background: #F5F5F5;
cursor: not-allowed;
}
}
}
// 位置选择器样式
.location-picker {
display: flex;
align-items: center;
justify-content: space-between;
height: 96rpx;
padding: 0 30rpx;
background: #FFF;
border: 1px solid #E5E5E5;
border-radius: 16rpx;
.location-text {
flex: 1;
font-size: 28rpx;
color: #333;
&.is-placeholder {
color: #999;
}
}
.location-icon {
color: #4E63E0;
font-size: 42rpx;
}
}
// 上传组件样式
.upload-container {
margin-bottom: 32rpx;
.upload-title {
font-size: 28rpx;
color: #333;
margin-bottom: 16rpx;
}
.upload-box {
width: 100%;
height: 300rpx;
background: #F7F7F7;
border-radius: 16rpx;
overflow: hidden;
position: relative;
.preview-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.upload-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.cuIcon-camerafill {
font-size: 48rpx;
color: #999;
margin-bottom: 16rpx;
}
.upload-text {
font-size: 28rpx;
color: #666;
margin-bottom: 8rpx;
}
.upload-hint {
font-size: 24rpx;
color: #999;
}
}
.upload-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
.upload-loading {
color: #FFFFFF;
font-size: 28rpx;
}
}
}
}
// 底部提交按钮样式
.submit-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 32rpx 48rpx 24rpx;
background: #FFF;
box-shadow: 0 -1rpx 3rpx rgba(0, 0, 0, 0.1);
.submit-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(135deg, #19367A, #2C4C99);
border-radius: 44rpx;
color: #FFF;
font-size: 32rpx;
font-weight: 600;
transition: all 0.3s;
&:active {
transform: scale(0.98);
}
&[disabled] {
opacity: 0.6;
background: #999;
}
}
}
// 弹窗样式
.consult-popup {
position: relative;
width: 676rpx;
background: #FFF;
border-radius: 12rpx;
.popup-close {
position: absolute;
top: 10rpx;
right: 20rpx;
padding: 10rpx;
.close-icon {
width: 48rpx;
height: 48rpx;
}
}
}
.success-popup {
width: 676rpx;
height: 596rpx;
background: #FFF;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.success-icon {
width: 376rpx;
height: 262rpx;
margin-bottom: 32rpx;
}
.success-text {
font-size: 28rpx;
color: #333;
margin-bottom: 32rpx;
}
.success-btn {
width: 314rpx;
height: 76rpx;
line-height: 76rpx;
background: #4E63E0;
color: #FFF;
font-size: 28rpx;
border-radius: 38rpx;
}
}
// 通用样式
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 28rpx;
}
</style>