mrr.sj.front/pages/ruzhu/qualification_sj.vue

1751 lines
58 KiB
Vue
Raw Permalink 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="qualification-page">
<view class="section">
<view class="section-title">
<view class="title-bar"></view>
<text class="title-text">门店信息</text>
</view>
<view class="form-item-one box-cont">
<view class="label-wrapper">
<text class="label required">店铺名称</text>
<image class="label-icon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/25bd7f38-1a3e-4282-84ea-190d7f820108"
mode="aspectFit" @click="showTipPopup('name')"></image>
</view>
<input type="text" v-model="formData.name" placeholder="请输入营业执照的店铺名称" placeholder-class="placeholder"
class="input" @input="saveFormDataToLocalDebounce" />
</view>
<view class="form-item-two box-cont" @click="showLocationPopup">
<text class="label required">门店所在地</text>
<view class="picker-content">
<text :class="formData.dependency ? 'picker-value' : 'placeholder'">
{{ formData.dependency || '请选择' }}
</text>
<image
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/dccc4513-377c-4bfa-9fd2-a5cfdb9798f3"
class="arrow-right" mode="aspectFit"></image>
</view>
</view>
<view class="form-item-two box-cont" @click="getAddressInfo">
<text class="label required">门店详细地址</text>
<view class="picker-content">
<text :class="formData.address ? 'picker-value' : 'placeholder'">
{{ formData.address || '请选择' }}
</text>
<image
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/dccc4513-377c-4bfa-9fd2-a5cfdb9798f3"
class="arrow-right" mode="aspectFit"></image>
</view>
</view>
</view>
<view class="section">
<view class="section-title">
<view class="title-bar"></view>
<text class="title-text">联系人信息</text>
</view>
<view class="form-item box-cont">
<text class="label required">您的身份</text>
<view class="radio-group">
<view class="radio-item" @click="setContactType('1')">
<view class="radio" :class="{ checked: formData.contact_type === '1' }">
<image v-if="formData.contact_type === '1'" src="/static/images/agree_y.png"
class="radio-icon-image" mode="aspectFit"></image>
</view>
<text class="radio-label">法人</text>
</view>
<view class="radio-item" @click="setContactType('2')">
<view class="radio" :class="{ checked: formData.contact_type === '2' }">
<image v-if="formData.contact_type === '2'" src="/static/images/agree_y.png"
class="radio-icon-image" mode="aspectFit"></image>
</view>
<text class="radio-label">其他</text>
</view>
</view>
</view>
<view class="form-item-one box-cont">
<text class="label required">联系人</text>
<input type="text" v-model="formData.contact_name" placeholder="请输入" placeholder-class="placeholder"
class="input" @input="saveFormDataToLocalDebounce" />
</view>
<view class="form-item-one box-cont">
<text class="label required">联系人电话</text>
<input type="number" v-model="formData.contact_phone" placeholder="请输入联系电话"
placeholder-class="placeholder" class="input" @input="saveFormDataToLocalDebounce" />
</view>
<view class="form-item-one box-cont">
<text class="label">备用联系人电话</text>
<input type="number" v-model="formData.backup_phone" placeholder="请输入备用联系电话"
placeholder-class="placeholder" class="input" @input="saveFormDataToLocalDebounce" />
</view>
</view>
<view class="form-item-one-yqr box-cont invite-code-container">
<view class="invite-code-top">
<view class="label-wrapper">
<text class="label required">邀请码</text>
</view>
<input type="text" v-model="formData.invite_code_other" placeholder="请输入邀请码"
placeholder-class="placeholder" class="input" @input="handleInviteCodeInput" />
</view>
<!-- 分割线 -->
<view class="divider"></view>
<!-- 邀请人信息 -->
<view class="invite-info-container">
<!-- 默认提示 -->
<text v-if="!formData.invite_code_other" class="invite-tip">
请填写邀请人的邀请码若没有邀请人请填写13131313
</text>
<!-- 验证中 -->
<view v-else-if="inviteCodeValidating" class="invite-validating">
<text>验证中...</text>
</view>
<!-- 验证失败 -->
<view v-else-if="inviteCodeError" class="invite-error" :class="{ 'shake-animation': shakeInviteError }">
<text>邀请码无效</text>
</view>
<!-- 特殊邀请码13131313 -->
<view v-else-if="formData.invite_code_other === '13131313' && !inviterInfo" class="invite-tip">
请填写邀请人的邀请码若没有邀请人请填写13131313
</view>
<!-- 显示邀请人信息 -->
<view v-else-if="inviterInfo" class="inviter-info">
<text class="inviter-label">邀请人:</text>
<text class="inviter-name">{{ inviterInfo.name || inviterInfo.nick_name }}</text>
<text class="inviter-divider">/</text>
<text class="inviter-phone">{{ inviterInfo.account }}</text>
</view>
<!-- 其他情况(接口返回成功但没有认证铁军的邀请码) -->
<view v-else class="invite-error" :class="{ 'shake-animation': shakeInviteError }">
<text>邀请码无效</text>
</view>
</view>
</view>
<view class="popup" :class="{ show: showLocationPopupFlag }">
<view class="popup-mask" @click="hideLocationPopup"></view>
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">选择所在地</text>
<text class="popup-close" @click="hideLocationPopup">×</text>
</view>
<view class="region-body">
<picker-view @change="bindChangeLocation" class="picker-scroll" :indicator-style="indicatorStyle"
:value="locationValue">
<picker-view-column>
<view class="picker-item" v-for="(item, index) in ChinaCitys" :key="index">
{{ item.province }}
</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item, index) in locatinCitys" :key="index">
{{ item.city }}
</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item, index) in locationAreas" :key="index">
{{ item.area }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="popup-footer">
<view class="popup-btn confirm" @click="hideLocationPopup">
<text class="btn-text">取消</text>
</view>
<view class="popup-btn confirm" @click="confirmLocationSelect">
<text class="btn-text">确定</text>
</view>
</view>
</view>
</view>
<view class="tip-popup" :class="{ show: showTipPopupFlag }">
<view class="tip-popup-mask" @click="hideTipPopup"></view>
<view class="tip-popup-content">
<image class="tip-popup-bg"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ab410a5d-5819-47f2-a0fc-3fd6b90d6770"
mode="aspectFit"></image>
<view class="tip-popup-body">
<view class="tip-title">{{ tipTitle }}</view>
<view class="tip-image-container">
<image class="tip-image" :class="currentTipType" :src="tipImage" mode="widthFix"></image>
</view>
<view class="tip-buttons">
<view class="tip-btn cancel" @click="hideTipPopup">
<text class="btn-text">取消</text>
</view>
<view class="tip-btn confirm" @click="hideTipPopup">
<text class="btn-text">我已了解</text>
</view>
</view>
</view>
</view>
</view>
<uni-popup ref="existingInvitePopup" type="center" :mask-click="false">
<view class="invite-popup-content">
<view class="invite-popup-header">
<text class="invite-popup-title">请确认邀请信息</text>
</view>
<view class="invite-popup-body">
<view class="invite-item">
<text class="invite-label">邀请码</text>
<text class="invite-value">{{ existingInviterInfo && (existingInviterInfo.invite_code ||
existingInviterInfo.invite_code_other) }}</text>
</view>
<view class="invite-item">
<text class="invite-label">邀请人</text>
<text class="invite-value">{{ (existingInviterInfo && (existingInviterInfo.name ||
existingInviterInfo.nick_name)) || '' }}</text>
</view>
</view>
<view class="invite-popup-footer">
<view class="invite-btn cancel" @click="cancelInviteConfirm">关闭</view>
<view class="invite-btn confirm" @click="useExistingInviteCode">确认</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import request from '../../utils/request';
import {
debounce
} from '@/utils/debounce.js';
import ChinaCitys from '../../static/data/ChinaCitys.json';
export default {
data() {
const loadedData = this.loadFormDataFromLocal();
return {
userId: null,
userMobile: null, // 保存用户手机号用以查询邀请人
formData: loadedData || {
name: '',
contact_type: '1',
contact_name: '',
contact_phone: '',
backup_phone: '',
invite_code_other: '',
dependency: '',
address: '',
dependency_code: '',
dependency_province: '',
dependency_city: '',
longitude: '',
latitude: ''
},
showTipPopupFlag: false,
indicatorStyle: 'height: 68rpx;',
tipTitle: '',
tipImage: '',
currentTipType: '',
isSubmit: false,
identity: 2,
ChinaCitys: ChinaCitys,
locatinCitys: [],
locationAreas: [],
locationValue: [0, 0, 0],
showLocationPopupFlag: false,
// 抖动效果控制
shakeInviteError: false,
// 邀请码相关字段
inviteCodeValidating: false,
inviteCodeError: false,
inviterInfo: null,
currentValidatingCode: '',
inviteValidationTimer: null,
// 新增邀请码弹窗和替换逻辑需要的状态变量
existingInviterInfo: null,
hasExistingInviter: false,
hasAutoReplacedInvite: false,
confirmResolve: null // 存储 saveFormData 的 Promise resolve 方法
}
},
computed: {
},
watch: {
'formData.name'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.contact_name'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.contact_phone'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.backup_phone'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.invite_code_other'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.dependency'(newVal) {
this.saveFormDataToLocalDebounce();
},
'formData.address'(newVal) {
this.saveFormDataToLocalDebounce();
}
},
created() {
this.getUserInfo();
this.checkGlobalData();
this.setupAddressListener();
},
onShow() {
const localData = this.loadFormDataFromLocal();
if (localData) {
// 如果已经自动替换了邀请码,不要再覆盖
if (this.hasAutoReplacedInvite) {
const { invite_code_other, ...otherData } = localData;
Object.keys(otherData).forEach(key => {
if (this.formData[key] !== undefined && key !== 'invite_code_other') {
this.formData[key] = otherData[key];
}
});
} else {
this.formData = {
...this.formData,
...localData
};
}
}
this.checkGlobalData();
this.checkAddressData();
this.loadInviteStateFromLocal();
if (this.formData.invite_code_other) {
this.validateInviteCode(this.formData.invite_code_other);
}
},
onUnload() {
this.saveFormDataToLocal();
},
beforeDestroy() {
if (this.addressListener) {
uni.$off('address-selected', this.addressListener);
}
if (this.sjAddressListener) {
uni.$off('address-selected-for-sj', this.sjAddressListener);
}
},
async mounted() {
this.locatinCitys = this.ChinaCitys[0].citys;
this.locationAreas = this.locatinCitys[0].areas;
// 先检查绑定邀请人信息
await this.forceUseExistingInviter();
if (!this.hasAutoReplacedInvite && this.formData.invite_code_other) {
this.validateInviteCode(this.formData.invite_code_other);
}
},
onHide() {
this.saveFormDataToLocal();
},
methods: {
// 强制使用已绑定的邀请人
async forceUseExistingInviter() {
if (this.hasAutoReplacedInvite) return false;
// 确保我们有手机号,如果没有则再获取一次
if (!this.userMobile) {
await this.getUserInfo();
}
if (!this.userMobile) {
console.log('用户手机号未获取,跳过强制替换');
return false;
}
try {
// 1. 调用查询已绑定的邀请码
const res = await request.post('/sj/User/getBInviteCode', {
account: this.userMobile,
type: 2 // 商家端类型
});
if (res && (res.code === 200 || res.state === 1) && res.data) {
const oldInviteCode = res.data.invite_code || res.data.invite_code_other;
if (oldInviteCode) {
console.log('检测到已绑定邀请码:', oldInviteCode);
// 2. 用邀请码获取完整的邀请人信息
const inviteRes = await request.post('/sj/user/getInvite', {
invite_code: oldInviteCode
});
if (inviteRes && (inviteRes.code === 200 || inviteRes.state === 1) && inviteRes.data && inviteRes.data.account) {
const fullInviterInfo = inviteRes.data;
// 强制填充
this.formData.invite_code_other = oldInviteCode;
this.hasExistingInviter = true;
this.hasAutoReplacedInvite = true;
this.inviteCodeError = false;
this.inviterInfo = fullInviterInfo;
this.currentValidatingCode = oldInviteCode;
this.existingInviterInfo = fullInviterInfo;
// 保存状态
this.saveInviteStateToLocal();
this.saveFormDataToLocal();
return true;
}
}
}
} catch (error) {
console.error('强制替换邀请人失败:', error);
}
return false;
},
// 显示邀请码确认弹窗
showInviteConfirmPopup(inviterData) {
this.$nextTick(() => {
if (this.$refs.existingInvitePopup) {
this.existingInviterInfo = inviterData;
this.$refs.existingInvitePopup.open();
} else {
uni.showModal({
title: '请确认邀请信息',
content: `邀请码:${inviterData?.invite_code || inviterData?.invite_code_other}\n邀请人${inviterData?.name || inviterData?.nick_name}`,
confirmText: '确认',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
this.useExistingInviteCode();
} else {
this.cancelInviteConfirm();
}
}
});
}
});
},
// 隐藏邀请码确认弹窗
hideExistingInviteTipPopup() {
if (this.$refs.existingInvitePopup) {
this.$refs.existingInvitePopup.close();
}
},
// 用户点击确认按钮使用邀请码
useExistingInviteCode() {
if (this.existingInviterInfo) {
const inviteState = {
inviterInfo: this.existingInviterInfo,
inviteCodeError: false,
currentValidatingCode: this.existingInviterInfo.invite_code || this.existingInviterInfo.invite_code_other
};
uni.setStorageSync('store_invite_state', inviteState);
this.saveFormDataToLocal();
}
this.hideExistingInviteTipPopup();
// 触发 Promise 解决,以继续表单提交流程
if (this.confirmResolve) {
this.confirmResolve(true);
this.confirmResolve = null;
}
},
// 用户点击关闭/取消按钮
cancelInviteConfirm() {
this.hideExistingInviteTipPopup();
// 触发 Promise 拒绝拦截提交
if (this.confirmResolve) {
this.confirmResolve(false);
this.confirmResolve = null;
}
},
loadInviteStateFromLocal() {
try {
const inviteState = uni.getStorageSync('store_invite_state');
if (inviteState) {
console.log('加载邀请码验证状态:', inviteState);
// 恢复邀请码验证状态
this.inviterInfo = inviteState.inviterInfo || null;
this.inviteCodeError = inviteState.inviteCodeError || false;
this.currentValidatingCode = inviteState.currentValidatingCode || '';
// 特殊处理如果当前邀请码是13131313确保状态正确
if (this.formData.invite_code_other === '13131313') {
console.log('检测到特殊邀请码13131313重置验证状态');
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = '13131313';
}
// 如果正在验证的邀请码与当前表单中的一致,保持验证状态
if (this.currentValidatingCode === this.formData.invite_code_other) {
// 状态已恢复,无需额外操作
} else {
// 如果不一致,重新验证
if (this.formData.invite_code_other && this.formData.invite_code_other.trim() !== '') {
console.log('邀请码不一致,重新验证:', this.formData.invite_code_other);
this.handleInviteCodeInput({
detail: {
value: this.formData.invite_code_other
}
});
}
}
} else {
// 如果没有保存的状态,重置为初始状态
this.resetInviteCodeState();
}
} catch (e) {
console.log('加载邀请码验证状态失败:', e);
this.resetInviteCodeState();
}
},
// 新增方法:重置邀请码状态
resetInviteCodeState() {
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = '';
this.shakeInviteError = false;
},
// 新增方法:专门保存邀请码验证状态
saveInviteStateToLocal() {
try {
const inviteState = {
inviterInfo: this.inviterInfo,
inviteCodeError: this.inviteCodeError,
currentValidatingCode: this.currentValidatingCode || this.formData.invite_code_other || ''
};
uni.setStorageSync('store_invite_state', inviteState);
console.log('邀请码验证状态已保存:', {
hasInviterInfo: !!this.inviterInfo,
inviteCodeError: this.inviteCodeError,
currentValidatingCode: this.currentValidatingCode
});
} catch (e) {
console.log('保存邀请码验证状态失败:', e);
}
},
// 触发邀请码错误抖动效果
triggerInviteErrorShake() {
// 触发抖动效果
this.shakeInviteError = true;
// 滚动到邀请码容器位置
this.$nextTick(() => {
// 使用uni.createSelectorQuery获取邀请码容器的位置
const query = uni.createSelectorQuery().in(this);
query.select('.invite-code-container').boundingClientRect((rect) => {
if (rect) {
// 获取当前窗口高度
const windowHeight = uni.getSystemInfoSync().windowHeight;
// 判断邀请码容器是否已经在可视区域内
// 计算容器在屏幕中的位置比例0-1之间
const containerTopRatio = rect.top / windowHeight;
const containerBottomRatio = (rect.top + rect.height) / windowHeight;
// 如果容器已经在屏幕中上部(顶部在屏幕中间以上),就不需要滚动
// 或者容器整体都在屏幕内,也不需要滚动
if (containerTopRatio >= 0 && containerTopRatio < 0.7 &&
containerBottomRatio <= 1) {
console.log('邀请码容器已在可视区域内,不需要滚动');
return;
}
// 滚动到邀请码容器位置,减去一些偏移量让用户体验更好
uni.pageScrollTo({
scrollTop: rect.top - 50,
duration: 300
});
}
}).exec();
});
// 0.5秒后重置抖动状态
setTimeout(() => {
this.shakeInviteError = false;
}, 500);
},
// 处理邀请码输入
handleInviteCodeInput(e) {
// 【改动】如果已经被强制替换为已有邀请人,禁止任何手动修改
if (this.hasAutoReplacedInvite) {
console.log('已强制使用原邀请人,禁止修改邀请码');
this.formData.invite_code_other = this.inviterInfo ? (this.inviterInfo.invite_code || this.inviterInfo.invite_code_other) : '';
return;
}
const code = e.detail ? e.detail.value : this.formData.invite_code_other;
console.log('邀请码输入:', code);
// 立即重置状态
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
// 如果邀请码为空,不进行验证
if (!code || code.trim() === '') {
this.formData.invite_code_other = '';
this.saveFormDataToLocalDebounce();
// 保存空状态
this.saveInviteStateToLocal();
return;
}
this.formData.invite_code_other = code;
this.saveFormDataToLocalDebounce();
// 【关键修复】如果是13131313立即通过验证并取消任何正在进行的验证
if (code === '13131313') {
console.log('检测到特殊邀请码13131313立即通过');
// 清除任何可能的定时器
if (this.inviteValidationTimer) {
clearTimeout(this.inviteValidationTimer);
this.inviteValidationTimer = null;
}
// 立即更新状态
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = code;
// 特殊邀请码也需要保存状态
const inviteState = {
inviterInfo: null,
inviteCodeError: false,
currentValidatingCode: code
};
uni.setStorageSync('store_invite_state', inviteState);
// 强制更新视图
this.$forceUpdate();
return;
}
// 记录当前正在验证的邀请码
this.currentValidatingCode = code;
// 立即保存状态(验证中)
this.saveInviteStateToLocal();
// 清除之前的定时器
if (this.inviteValidationTimer) {
clearTimeout(this.inviteValidationTimer);
this.inviteValidationTimer = null;
}
// 设置新的定时器
this.inviteValidationTimer = setTimeout(() => {
// 检查邀请码是否变化
if (this.formData.invite_code_other !== this.currentValidatingCode) {
console.log('邀请码已变化,取消验证');
return;
}
// 再次检查是否是13131313双重检查
if (this.formData.invite_code_other === '13131313') {
console.log('双重检查检测到特殊邀请码13131313');
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = '13131313';
const inviteState = {
inviterInfo: null,
inviteCodeError: false,
currentValidatingCode: '13131313'
};
uni.setStorageSync('store_invite_state', inviteState);
return;
}
console.log('开始验证邀请码:', this.formData.invite_code_other);
this.validateInviteCode(this.formData.invite_code_other);
// 清理定时器
this.inviteValidationTimer = null;
}, 600); // 适当增加延迟时间
},
// 验证邀请码
async validateInviteCode(code) {
console.log('开始验证邀请码:', code);
// 特殊邀请码13131313直接通过
if (code === '13131313') {
console.log('特殊邀请码13131313直接通过');
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = code;
// 特殊邀请码也需要保存状态
const inviteState = {
inviterInfo: null,
inviteCodeError: false,
currentValidatingCode: code
};
uni.setStorageSync('store_invite_state', inviteState);
// 强制更新视图
this.$forceUpdate();
return;
}
// 如果邀请码为空
if (!code || code.trim() === '') {
this.inviteCodeValidating = false;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = '';
const inviteState = {
inviterInfo: null,
inviteCodeError: false,
currentValidatingCode: ''
};
uni.setStorageSync('store_invite_state', inviteState);
return;
}
// 设置验证中状态
this.inviteCodeValidating = true;
this.inviteCodeError = false;
this.inviterInfo = null;
this.currentValidatingCode = code;
try {
// 调用接口验证邀请码
const response = await request.post('/sj/user/getInvite', {
invite_code: code
});
console.log('邀请码验证响应:', response);
// 验证完成
this.inviteCodeValidating = false;
if (response && (response.state === 1 || response.code === 200) && response.data) {
const userData = response.data;
if (userData.account) {
// 邀请码有效,保存邀请人信息
this.inviterInfo = userData;
this.inviteCodeError = false;
console.log('邀请码验证通过,邀请人:', userData);
} else {
// 接口返回数据但没有account字段说明不是有效邀请人
console.log('接口返回数据无效没有account字段:', userData);
this.inviterInfo = null;
this.inviteCodeError = true;
}
} else {
// 接口返回错误或数据为空
console.log('接口返回错误:', response?.msg || '未知错误');
this.inviterInfo = null;
this.inviteCodeError = true;
}
} catch (error) {
console.error('验证邀请码失败:', error);
this.inviteCodeValidating = false;
this.inviteCodeError = true;
this.inviterInfo = null;
} finally {
// 无论成功失败都保存状态
const inviteState = {
inviterInfo: this.inviterInfo,
inviteCodeError: this.inviteCodeError,
currentValidatingCode: this.currentValidatingCode
};
uni.setStorageSync('store_invite_state', inviteState);
}
},
checkGlobalData() {
if (getApp().globalData.qualificationData) {
this.formData = {
...this.formData,
...getApp().globalData.qualificationData
};
this.saveFormDataToLocal();
getApp().globalData.qualificationData = null;
}
},
loadFormDataFromLocal() {
try {
const stored = uni.getStorageSync('qualification_form_data');
if (stored) {
console.log('从本地存储加载数据:', stored);
const inviteState = uni.getStorageSync('store_invite_state');
if (inviteState) {
this.inviterInfo = inviteState.inviterInfo;
this.inviteCodeError = inviteState.inviteCodeError || false;
this.currentValidatingCode = inviteState.currentValidatingCode || '';
console.log('加载邀请码验证状态:', inviteState);
}
return stored;
}
} catch (e) {
console.log('读取本地存储失败:', e);
}
return null;
},
saveFormDataToLocalDebounce: debounce(function () {
this.saveFormDataToLocal();
}, 500),
saveFormDataToLocal() {
try {
uni.setStorageSync('qualification_form_data', this.formData);
const inviteState = {
inviterInfo: this.inviterInfo,
inviteCodeError: this.inviteCodeError,
currentValidatingCode: this.currentValidatingCode
};
uni.setStorageSync('store_invite_state', inviteState);
console.log('数据已保存到本地存储');
} catch (e) {
console.log('保存数据失败:', e);
}
},
clearFormDataLocal() {
try {
uni.removeStorageSync('qualification_form_data');
console.log('已清空本地存储数据');
} catch (e) {
console.log('清空数据失败:', e);
}
},
getUserInfo() {
// 【改动】增加了对手机号的抓取并暴露至 data 内,以供给查询上级分销/邀请人使用
return new Promise((resolve, reject) => {
request.post('/sj/user/getuser').then(result => {
if (result.state === 1) {
this.userId = result.data.id;
this.userMobile = result.data.mobile || result.data.account; // 记录手机号
if (this.userMobile && getApp().globalData) {
getApp().globalData.userMobile = this.userMobile;
}
console.log('用户ID获取成功:', this.userId);
resolve(this.userId);
} else {
console.error('获取用户信息失败:', result.msg);
reject(result.msg);
}
}).catch(error => {
console.error('获取用户信息接口错误:', error);
reject(error);
});
});
},
getFormData() {
return {
...this.formData
};
},
// 这里改造为了 Promise以拦截并弹窗等待用户操作
saveFormData() {
return new Promise((resolve) => {
if (!this.formData.name) {
uni.showToast({
title: '请输入店铺名称',
icon: 'none'
});
return resolve(false);
}
if (!this.formData.dependency) {
uni.showToast({
title: '请选择门店所在地',
icon: 'none'
});
return resolve(false);
}
if (!this.formData.address) {
uni.showToast({
title: '请选择门店详细地址',
icon: 'none'
});
return resolve(false);
}
if (!this.formData.contact_name) {
uni.showToast({
title: '请输入联系人',
icon: 'none'
});
return resolve(false);
}
if (!this.formData.contact_phone) {
uni.showToast({
title: '请输入联系人电话',
icon: 'none'
});
return resolve(false);
}
if (!/^1[3-9]\d{9}$/.test(this.formData.contact_phone)) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
});
return resolve(false);
}
if (!this.formData.invite_code_other) {
uni.showToast({
title: '请输入邀请码',
icon: 'none'
});
return resolve(false);
}
// 验证邀请码的有效性状态
if (this.inviteCodeValidating) {
uni.showToast({ title: '邀请码验证中,请稍候', icon: 'none' });
return resolve(false);
}
if (this.formData.invite_code_other === '13131313') {
// 特殊跳过判断
} else if (this.inviteCodeError || !this.inviterInfo) {
this.triggerInviteErrorShake();
return resolve(false);
}
// 挂载 resolve在确认弹窗触发后再予以抛出
this.confirmResolve = resolve;
if (this.formData.invite_code_other === '13131313') {
this.showInviteConfirmPopup({ invite_code_other: '13131313', name: '暂无邀请人' });
} else if (this.inviterInfo && this.formData.invite_code_other) {
this.showInviteConfirmPopup(this.inviterInfo);
} else {
this.saveFormDataToLocal();
resolve(true);
}
});
},
setContactType(type) {
this.$set(this.formData, 'contact_type', type);
this.saveFormDataToLocal();
},
showTipPopup(field) {
const tipConfig = {
'name': {
title: '如何查看店铺名称',
image: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/4a2dc8c2-98d4-4465-ae31-b2ea2d13aa23'
}
};
if (tipConfig[field]) {
this.currentTipType = field;
this.tipTitle = tipConfig[field].title;
this.tipImage = tipConfig[field].image;
this.showTipPopupFlag = true;
}
},
hideTipPopup() {
this.showTipPopupFlag = false;
},
showLocationPopup() {
this.showLocationPopupFlag = true;
},
hideLocationPopup() {
this.showLocationPopupFlag = false;
},
bindChangeLocation(e) {
this.locationValue = e.detail.value;
let index1 = e.detail.value[0] || 0;
let index2 = e.detail.value[1] || 0;
this.locatinCitys = this.ChinaCitys[index1].citys;
this.locationAreas = this.locatinCitys[index2].areas;
},
confirmLocationSelect() {
let valueArr = this.locationValue;
let index1 = valueArr[0] || 0;
let index2 = valueArr[1] || 0;
let index3 = valueArr[2] || 0;
let province = this.ChinaCitys[index1].province;
let city = this.locatinCitys[index2].city;
let area = this.locationAreas[index3].area;
this.formData.dependency = province + '-' + city + '-' + area;
this.formData.address = '';
this.formData.longitude = '';
this.formData.latitude = '';
if (this.ChinaCitys[index1] && this.ChinaCitys[index1].code) {
let provinceCode = this.ChinaCitys[index1].code.toString();
this.formData.dependency_province = provinceCode.substring(0, 6);
}
if (this.locatinCitys[index2] && this.locatinCitys[index2].code) {
let cityCode = this.locatinCitys[index2].code.toString();
this.formData.dependency_city = cityCode.substring(0, 6);
}
if (this.locationAreas[index3] && this.locationAreas[index3].code) {
let areaCode = this.locationAreas[index3].code.toString();
this.formData.dependency_code = areaCode.substring(0, 6);
}
this.saveFormDataToLocal();
this.hideLocationPopup();
},
buildRegionTextForSearch() {
const dependency = String(this.formData.dependency || '').trim();
if (!dependency) return '';
const parts = dependency.split('-');
const province = parts[0] || '';
const city = parts[1] || '';
const district = parts[2] || '';
let regionText = '';
if (province) regionText += province;
if (city && city !== province) regionText += city;
if (district) regionText += district;
return regionText;
},
getAddressValueForSearch() {
const rawAddress = String(this.formData.address || '').trim();
if (!rawAddress) return '';
const dependencyText = String(this.formData.dependency || '').trim();
const regionText = this.buildRegionTextForSearch();
let detail = rawAddress;
if (regionText && detail.indexOf(regionText) === 0) {
detail = detail.slice(regionText.length).trim();
} else if (dependencyText && detail.indexOf(dependencyText) === 0) {
detail = detail.slice(dependencyText.length).trim();
}
detail = detail.replace(/^[\s,-]+/, '').trim();
return detail || rawAddress;
},
getAddressInfo() {
this.saveFormDataToLocal();
const dependency = String(this.formData.dependency || '').trim();
const dependencyCode = String(this.formData.dependency_code || '').trim();
const address = this.getAddressValueForSearch();
const longitude = String(this.formData.longitude || '').trim();
const latitude = String(this.formData.latitude || '').trim();
const hasDependency = !!dependency;
const hasAddress = !!address;
const hasLocation = !!(longitude && latitude);
let params = 'source=sj_info';
if (hasDependency) {
params += `&dependency=${encodeURIComponent(dependency)}`;
if (dependencyCode) {
params += `&dependency_code=${dependencyCode}`;
}
}
if (hasAddress) {
params += `&address=${encodeURIComponent(address)}`;
}
if (hasLocation) {
params += `&longitude=${longitude}&latitude=${latitude}`;
}
if (!hasDependency && !hasAddress && !hasLocation) {
params += '&init_current_location=1&silent_locate=1';
}
uni.navigateTo({
url: `/pages/address/search?${params}`
});
},
setupAddressListener() {
this.addressListener = (addressData) => {
this.handleAddressSelected(addressData);
};
this.sjAddressListener = (addressData) => {
this.handleAddressSelected(addressData);
};
uni.$on('address-selected', this.addressListener);
uni.$on('address-selected-for-sj', this.sjAddressListener);
},
checkAddressData() {
try {
const storedAddress = uni.getStorageSync('sj_selected_address');
if (storedAddress) {
this.handleAddressSelected(storedAddress);
uni.removeStorageSync('sj_selected_address');
return;
}
} catch (e) { }
if (getApp().globalData && getApp().globalData.selectedAddress) {
this.handleAddressSelected(getApp().globalData.selectedAddress);
delete getApp().globalData.selectedAddress;
}
try {
const selectedAddress = uni.getStorageSync('selectedAddress');
if (selectedAddress) {
this.handleAddressSelected(selectedAddress);
uni.removeStorageSync('selectedAddress');
}
} catch (e) { }
},
handleAddressSelected(addressData) {
if (!addressData) return;
let detailAddress = '';
if (addressData.address) {
detailAddress = String(addressData.address).trim();
} else if (addressData.name) {
detailAddress = String(addressData.name).trim();
const regionParts = [];
if (addressData.pname) regionParts.push(addressData.pname);
if (addressData.cityname && addressData.cityname !== addressData.pname) regionParts.push(addressData
.cityname);
if (addressData.adname) regionParts.push(addressData.adname);
const regionText = regionParts.join('');
if (regionText && detailAddress.indexOf(regionText) === 0) {
detailAddress = detailAddress.slice(regionText.length).trim();
}
detailAddress = detailAddress.replace(/^[\s,-]+/, '').trim();
}
this.formData.address = detailAddress;
if (addressData.location) {
const [longitude, latitude] = String(addressData.location).split(',');
this.formData.longitude = longitude || '';
this.formData.latitude = latitude || '';
}
if (addressData.pname || addressData.cityname || addressData.adname) {
const locationParts = [];
if (addressData.pname) locationParts.push(addressData.pname);
if (addressData.cityname) locationParts.push(addressData.cityname);
if (addressData.adname) locationParts.push(addressData.adname);
this.formData.dependency = locationParts.join('-');
}
this.formData.dependency_province = addressData.provinceCode || '';
this.formData.dependency_city = addressData.cityCode || '';
this.formData.dependency_code = addressData.districtCode || '';
this.saveFormDataToLocal();
this.$forceUpdate();
}
}
}
</script>
<style scoped>
/* 继承你以前的所有原有样式 */
.qualification-page {}
.section {
margin-bottom: 30rpx;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
.title-bar {
width: 6rpx;
height: 30rpx;
background-color: #FF4767;
margin-right: 7rpx;
border-radius: 5rpx;
}
.title-text {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #1D2129;
line-height: 48rpx;
text-align: left;
font-style: normal;
}
.section-title text {
font-size: 36rpx;
color: #1D2129;
font-weight: 500;
}
.box-cont {
background: #FFFFFF;
border-radius: 20rpx;
margin-bottom: 24rpx;
margin-left: 8rpx;
margin-right: 8rpx;
box-shadow: none;
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
}
.form-item-one {
display: flex;
align-items: center;
padding: 24rpx;
}
.form-item-two {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
}
.form-item-two>text.label {
flex-shrink: 0;
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
.invite-code-top {
display: flex;
align-items: center;
padding: 24rpx;
width: 100%;
box-sizing: border-box;
}
.label-wrapper {
display: inline-flex;
align-items: center;
}
.label {
font-size: 28rpx;
color: #333333;
font-weight: 500;
line-height: 1;
}
.label-icon {
width: 26rpx;
height: 26rpx;
margin-left: 8rpx;
align-items: center;
}
.required::before {
content: '*';
color: #FF0000;
margin-right: 4rpx;
}
.picker-content {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
}
.picker-content text {
margin-right: 19rpx;
}
.arrow-right {
width: 14rpx;
height: 26rpx;
}
.placeholder {
color: #999999;
font-size: 28rpx;
}
.picker-value {
font-size: 28rpx;
color: #333333;
}
.input {
flex: 1;
font-size: 28rpx;
color: #333333;
text-align: right;
margin-left: 20rpx;
}
.radio-group {
display: flex;
}
.radio-item {
display: flex;
align-items: center;
margin-right: 130rpx;
}
.radio {
width: 30rpx;
height: 30rpx;
border: 2rpx solid #DDDDDD;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
}
.radio.checked {
background-color: #FF4767;
border-color: #FF4767;
}
.radio-icon-image {
width: 32rpx;
height: 32rpx;
}
.radio-label {
font-size: 28rpx;
color: #333333;
}
.invite-tip {
padding: 24rpx;
}
.invite-tip-text {
font-size: 26rpx;
color: #999999;
line-height: 40rpx;
}
.popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
visibility: hidden;
opacity: 0;
transition: all 0.3s ease;
}
.popup.show {
visibility: visible;
opacity: 1;
}
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.popup-content {
position: relative;
background-color: #FFFFFF;
border-radius: 24rpx 24rpx 0 0;
padding: 32rpx;
transform: translateY(100%);
transition: transform 0.3s ease;
max-height: 70vh;
}
.popup.show .popup-content {
transform: translateY(0);
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32rpx;
}
.popup-title {
font-size: 32rpx;
color: #333333;
font-weight: 500;
}
.popup-close {
font-size: 40rpx;
color: #999999;
padding: 16rpx;
}
.popup-footer {
margin-top: 32rpx;
display: flex;
justify-content: space-between;
gap: 20rpx;
padding: 0 24rpx 24rpx;
}
.popup-btn {
flex: 1;
height: 88rpx;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, #f52540 0%, #FF4767 100%);
}
.popup-btn.cancel {
background-color: #F5F5F5;
}
.popup-btn.confirm {
background: linear-gradient(180deg, #f52540 0%, #FF4767 100%);
}
.popup-btn .btn-text {
font-size: 32rpx;
font-weight: 500;
color: #FFFFFF;
}
.popup-btn.cancel .btn-text {
color: #666666;
}
.popup-btn.confirm .btn-text {
color: #FFFFFF;
}
.region-body {
height: 400rpx;
}
.picker-scroll {
height: 400rpx;
}
.picker-item {
height: 68rpx;
line-height: 68rpx;
text-align: center;
font-size: 28rpx;
}
.tip-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
visibility: hidden;
opacity: 0;
transition: all 0.3s ease;
}
.tip-popup.show {
visibility: visible;
opacity: 1;
}
.tip-popup-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.tip-popup-content {
position: relative;
width: 620rpx;
height: 810rpx;
}
.tip-popup-bg {
width: 620rpx;
height: 810rpx;
position: absolute;
top: 0;
left: 0;
}
.tip-popup-body {
position: relative;
flex-direction: column;
padding: 80rpx 20rpx 40rpx 20rpx;
box-sizing: border-box;
}
.tip-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-top: 107rpx;
margin-bottom: 37rpx;
}
.tip-image-container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 50rpx;
}
.tip-image {
width: 90%;
max-height: 400rpx;
}
.tip-buttons {
display: flex;
justify-content: space-between;
padding: 0 28rpx;
}
.tip-btn {
width: 250rpx;
height: 80rpx;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
}
.tip-btn.cancel {
border: #FF4767 2rpx solid;
background-color: transparent;
color: #FF4767;
}
.tip-btn.confirm {
background: linear-gradient(180deg, #f52540 0%, #FF4767 100%);
color: #FFFFFF;
}
.tip-btn .btn-text {
color: inherit;
}
.invite-info-container {
padding: 20rpx 24rpx;
width: 100%;
box-sizing: border-box;
min-height: 60rpx;
}
.invite-tip {
font-size: 24rpx;
color: #666666;
}
.invite-validating {
font-size: 20rpx;
color: #999999;
}
.invite-error {
font-size: 24rpx;
color: #FF4767;
}
.inviter-info {
display: flex;
align-items: center;
font-size: 20rpx;
}
.inviter-label {
color: #666666;
}
.inviter-name {
color: #333333;
font-weight: 500;
}
.inviter-divider {
color: #666666;
margin: 0 5rpx;
}
.inviter-phone {
color: #666666;
}
/* 邀请码和禁用样式 */
/* 输入框禁用样式 */
.input:disabled {
color: #999999;
background-color: #F5F5F5;
}
/* 邀请码确认弹窗样式 */
.invite-popup-content {
width: 571rpx;
height: 535rpx;
background-image: url('https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/6f130301-f3df-467c-8a1c-dc49f85e5295.png');
background-size: cover;
background-position: center;
border-radius: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx;
box-sizing: border-box;
}
.invite-popup-header {
width: 100%;
text-align: center;
margin-bottom: 40rpx;
}
.invite-popup-title {
font-size: 36rpx;
font-weight: 500;
color: #333333;
}
.invite-popup-body {
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
gap: 24rpx;
margin-top: 20rpx;
}
.invite-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 16rpx;
}
.invite-label {
font-size: 28rpx;
color: #666666;
}
.invite-value {
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
.invite-popup-footer {
width: 100%;
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.invite-btn {
flex: 1;
height: 88rpx;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
margin: 0 5rpx;
}
.invite-btn.cancel {
background-color: #FFFFFF;
color: #FC437C;
border: 2rpx solid #FC437C;
}
.invite-btn.confirm {
background: linear-gradient(90deg, #FC437C 0%, #FF618F 100%);
color: #FFFFFF;
}
</style>