610 lines
14 KiB
Vue
610 lines
14 KiB
Vue
<template>
|
||
<div class="partner-request-container" @touchstart="handleTouchStart">
|
||
<div class="request-card">
|
||
<form @submit.prevent="submitRequest" class="request-form">
|
||
<div class="form-group">
|
||
<label for="name">您的姓名</label>
|
||
<input
|
||
type="text"
|
||
id="name"
|
||
v-model="formData.name"
|
||
placeholder="请输入您的姓名"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="phone">您的电话</label>
|
||
<div class="phone-input-group">
|
||
<input
|
||
type="tel"
|
||
id="phone"
|
||
v-model="formData.phone"
|
||
placeholder="请输入您的联系电话"
|
||
required
|
||
pattern="[0-9]{11}"
|
||
/>
|
||
<button
|
||
type="button"
|
||
class="btn-send-code"
|
||
@click="sendVerificationCode"
|
||
:disabled="cooldown > 0"
|
||
>
|
||
{{ cooldown > 0 ? `${cooldown}秒后重发` : '发送验证码' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="phoneCode">验证码</label>
|
||
<input
|
||
type="text"
|
||
id="phoneCode"
|
||
v-model="formData.phone_code"
|
||
placeholder="请输入短信验证码"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>合伙类型</label>
|
||
<div class="partner-type-selector">
|
||
<div
|
||
class="partner-type-option"
|
||
:class="{ 'active': formData.partnerType === 'community' }"
|
||
@click="selectPartnerType('community')"
|
||
>
|
||
<div class="option-radio">
|
||
<div class="radio-inner" v-if="formData.partnerType === 'community'"></div>
|
||
</div>
|
||
<div class="option-label">小区合伙人</div>
|
||
</div>
|
||
|
||
<div
|
||
class="partner-type-option"
|
||
:class="{ 'active': formData.partnerType === 'city' }"
|
||
@click="selectPartnerType('city')"
|
||
>
|
||
<div class="option-radio">
|
||
<div class="radio-inner" v-if="formData.partnerType === 'city'"></div>
|
||
</div>
|
||
<div class="option-label">城市合伙人</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="serviceArea">
|
||
{{ formData.partnerType === 'community' ? '服务小区' : '服务城市' }}
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="serviceArea"
|
||
v-model="formData.serviceArea"
|
||
:placeholder="formData.partnerType === 'community' ? '请输入小区名称' : '请输入城市名称'"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div class="form-actions">
|
||
<button type="button" class="btn-cancel" @click="goBack">取消</button>
|
||
<button type="submit" class="btn-submit" :disabled="isSubmitting">
|
||
{{ isSubmitting ? '提交中...' : '提交申请' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 成功弹窗 -->
|
||
<div class="modal" v-if="showModal">
|
||
<div class="modal-content">
|
||
<div class="modal-icon" :class="{ 'success-icon': isSuccess, 'error-icon': !isSuccess }">
|
||
<span v-if="isSuccess">✓</span>
|
||
<span v-else>!</span>
|
||
</div>
|
||
<h3>{{ modalTitle }}</h3>
|
||
<p>{{ modalMessage }}</p>
|
||
<button @click="closeModal" class="btn-confirm">确定</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
||
import { useRouter, useRoute } from 'vue-router'
|
||
import apiClient from '../services/api'
|
||
|
||
export default {
|
||
name: 'PartnerRequest',
|
||
setup() {
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
const isSubmitting = ref(false)
|
||
const showModal = ref(false)
|
||
const isSuccess = ref(true)
|
||
const modalTitle = ref('')
|
||
const modalMessage = ref('')
|
||
const userId = ref('')
|
||
const lastTouchEnd = ref(0)
|
||
const cooldown = ref(0)
|
||
|
||
const formData = reactive({
|
||
name: '',
|
||
phone: '',
|
||
phone_code: '',
|
||
partnerType: 'community',
|
||
serviceArea: ''
|
||
})
|
||
|
||
onMounted(() => {
|
||
// 从URL获取userId
|
||
userId.value = route.query.userid || ''
|
||
|
||
if (!userId.value) {
|
||
console.warn('未找到用户ID,可能影响提交功能')
|
||
}
|
||
|
||
// 检测是否在小程序环境中
|
||
checkMiniProgramEnvironment()
|
||
|
||
// 设置页面标题
|
||
document.title = '合伙人申请'
|
||
// 添加额外的触摸事件处理
|
||
const handleTouchEnd = (event) => {
|
||
const now = Date.now()
|
||
if (now - lastTouchEnd.value <= 300) {
|
||
event.preventDefault()
|
||
}
|
||
lastTouchEnd.value = now
|
||
}
|
||
|
||
document.addEventListener('touchend', handleTouchEnd)
|
||
|
||
onBeforeUnmount(() => {
|
||
document.removeEventListener('touchend', handleTouchEnd)
|
||
document.title = '蜂快到家'
|
||
})
|
||
})
|
||
|
||
const checkMiniProgramEnvironment = () => {
|
||
// 检查是否在微信小程序环境中
|
||
const userAgent = navigator.userAgent.toLowerCase()
|
||
const isWechatMiniProgram = /miniprogram/.test(userAgent) || window.__wxjs_environment === 'miniprogram'
|
||
|
||
console.log('是否在小程序环境中:', isWechatMiniProgram)
|
||
}
|
||
|
||
const selectPartnerType = (type) => {
|
||
formData.partnerType = type
|
||
}
|
||
|
||
const sendVerificationCode = async () => {
|
||
// 验证手机号格式
|
||
if (!/^1[3-9]\d{9}$/.test(formData.phone)) {
|
||
alert('请输入正确的手机号码')
|
||
return
|
||
}
|
||
|
||
try {
|
||
// 发送验证码请求
|
||
await apiClient.post('/api/user/send-code', {
|
||
phone: formData.phone
|
||
})
|
||
|
||
// 设置倒计时
|
||
cooldown.value = 60
|
||
const timer = setInterval(() => {
|
||
cooldown.value--
|
||
if (cooldown.value <= 0) {
|
||
clearInterval(timer)
|
||
}
|
||
}, 1000)
|
||
|
||
alert('验证码已发送,请注意查收')
|
||
} catch (error) {
|
||
console.error('发送验证码失败:', error)
|
||
alert('发送验证码失败,请稍后重试')
|
||
}
|
||
}
|
||
|
||
const submitRequest = async () => {
|
||
if (isSubmitting.value) return
|
||
|
||
isSubmitting.value = true
|
||
|
||
try {
|
||
// 构建请求数据
|
||
const requestData = {
|
||
user_id: userId.value || 0,
|
||
name: formData.name,
|
||
phone: formData.phone,
|
||
phone_code: formData.phone_code,
|
||
type: formData.partnerType,
|
||
service_target: formData.serviceArea
|
||
}
|
||
|
||
// 发送请求
|
||
const response = await apiClient.post('/api/feedback/partner-apply', requestData)
|
||
|
||
// 检查返回的状态码
|
||
if (response.data && response.data.code === 200) {
|
||
console.log('申请提交成功:', response.data)
|
||
|
||
// 显示成功弹窗
|
||
isSuccess.value = true
|
||
modalTitle.value = '申请提交成功'
|
||
modalMessage.value = '我们将尽快处理您的合伙人申请'
|
||
showModal.value = true
|
||
|
||
// 重置表单
|
||
formData.name = ''
|
||
formData.phone = ''
|
||
formData.phone_code = ''
|
||
formData.serviceArea = ''
|
||
} else {
|
||
// 显示错误弹窗
|
||
const errorMessage = response.data?.message || '提交失败,请稍后重试'
|
||
console.error('提交申请失败:', errorMessage)
|
||
|
||
isSuccess.value = false
|
||
modalTitle.value = '提交失败'
|
||
modalMessage.value = errorMessage
|
||
showModal.value = true
|
||
}
|
||
} catch (error) {
|
||
console.error('提交申请失败:', error)
|
||
|
||
// 尝试从错误响应中获取详细信息
|
||
const errorMessage = error.response?.data?.message || '提交失败,请稍后重试'
|
||
|
||
isSuccess.value = false
|
||
modalTitle.value = '提交失败'
|
||
modalMessage.value = errorMessage
|
||
showModal.value = true
|
||
} finally {
|
||
isSubmitting.value = false
|
||
}
|
||
}
|
||
|
||
const closeModal = () => {
|
||
showModal.value = false
|
||
|
||
// 如果是成功状态,关闭弹窗后返回上一页
|
||
if (isSuccess.value) {
|
||
goBack()
|
||
}
|
||
}
|
||
|
||
const goBack = () => {
|
||
// 如果在小程序环境中,调用小程序的返回方法
|
||
if (window.wx && window.wx.miniProgram) {
|
||
window.wx.miniProgram.navigateBack({ delta: 1 })
|
||
} else {
|
||
// 否则使用路由返回
|
||
router.back()
|
||
}
|
||
}
|
||
|
||
const handleTouchStart = (event) => {
|
||
// 防止iOS双击缩放
|
||
if (event.touches.length > 1) {
|
||
event.preventDefault()
|
||
}
|
||
}
|
||
|
||
return {
|
||
formData,
|
||
isSubmitting,
|
||
showModal,
|
||
isSuccess,
|
||
modalTitle,
|
||
modalMessage,
|
||
selectPartnerType,
|
||
submitRequest,
|
||
closeModal,
|
||
goBack,
|
||
handleTouchStart,
|
||
sendVerificationCode,
|
||
cooldown
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.partner-request-container {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
padding: 20px 15px 30px;
|
||
background: linear-gradient(to bottom, #FFCC00, #FFFFFF);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.request-card {
|
||
width: 100%;
|
||
max-width: 98%;
|
||
background-color: #FFFFFF;
|
||
border-radius: 20px;
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||
padding: 25px 20px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #333333;
|
||
margin-bottom: 25px;
|
||
text-align: center;
|
||
}
|
||
|
||
.request-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.form-group label {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #333333;
|
||
}
|
||
|
||
.form-group input {
|
||
padding: 12px 15px;
|
||
border: 1px solid #DDDDDD;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
color: #333333;
|
||
background-color: #F9F9F9;
|
||
transition: border-color 0.3s, box-shadow 0.3s;
|
||
}
|
||
|
||
.form-group input:focus {
|
||
border-color: #FFCC00;
|
||
box-shadow: 0 0 0 2px rgba(255, 204, 0, 0.2);
|
||
outline: none;
|
||
}
|
||
|
||
/* 手机号输入组样式 */
|
||
.phone-input-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.phone-input-group input {
|
||
flex: 1;
|
||
}
|
||
|
||
.btn-send-code {
|
||
padding: 0 15px;
|
||
background-color: #FFCC00;
|
||
color: #333333;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.btn-send-code:hover {
|
||
background-color: #FFD633;
|
||
}
|
||
|
||
.btn-send-code:disabled {
|
||
background-color: #DDDDDD;
|
||
color: #999999;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* 合伙类型选择器样式 */
|
||
.partner-type-selector {
|
||
display: flex;
|
||
gap: 15px;
|
||
}
|
||
|
||
.partner-type-option {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 12px 15px;
|
||
border: 1px solid #DDDDDD;
|
||
border-radius: 8px;
|
||
background-color: #F9F9F9;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.partner-type-option.active {
|
||
border-color: #FFCC00;
|
||
background-color: rgba(255, 204, 0, 0.1);
|
||
}
|
||
|
||
.option-radio {
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
border: 2px solid #DDDDDD;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 10px;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.partner-type-option.active .option-radio {
|
||
border-color: #FFCC00;
|
||
}
|
||
|
||
.radio-inner {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background-color: #FFCC00;
|
||
}
|
||
|
||
.option-label {
|
||
font-size: 16px;
|
||
color: #333333;
|
||
}
|
||
|
||
.form-actions {
|
||
display: flex;
|
||
gap: 15px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.btn-cancel, .btn-submit {
|
||
flex: 1;
|
||
padding: 12px 15px;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
text-align: center;
|
||
}
|
||
|
||
.btn-cancel {
|
||
background-color: #F2F2F2;
|
||
color: #666666;
|
||
border: none;
|
||
}
|
||
|
||
.btn-submit {
|
||
background-color: #FFCC00;
|
||
color: #333333;
|
||
border: none;
|
||
}
|
||
|
||
.btn-cancel:hover {
|
||
background-color: #E6E6E6;
|
||
}
|
||
|
||
.btn-submit:hover {
|
||
background-color: #FFD633;
|
||
}
|
||
|
||
.btn-submit:disabled {
|
||
background-color: #DDDDDD;
|
||
color: #999999;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* 成功弹窗样式 */
|
||
.modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-content {
|
||
background-color: #FFFFFF;
|
||
border-radius: 15px;
|
||
padding: 30px;
|
||
width: 80%;
|
||
max-width: 350px;
|
||
text-align: center;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal-icon {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 30px;
|
||
color: white;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.success-icon {
|
||
background-color: #FFCC00;
|
||
}
|
||
|
||
.error-icon {
|
||
background-color: #FF6B6B;
|
||
}
|
||
|
||
.modal-content h3 {
|
||
font-size: 20px;
|
||
margin-bottom: 10px;
|
||
color: #333333;
|
||
}
|
||
|
||
.modal-content p {
|
||
color: #666666;
|
||
margin-bottom: 25px;
|
||
}
|
||
|
||
.btn-confirm {
|
||
background-color: #FFCC00;
|
||
color: #333333;
|
||
border: none;
|
||
border-radius: 8px;
|
||
padding: 12px 15px;
|
||
width: 100%;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.btn-confirm:hover {
|
||
background-color: #FFD633;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 480px) {
|
||
.request-card {
|
||
padding: 20px 15px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group label {
|
||
font-size: 15px;
|
||
}
|
||
|
||
.form-group input,
|
||
.btn-cancel,
|
||
.btn-submit {
|
||
padding: 10px 12px;
|
||
font-size: 15px;
|
||
}
|
||
|
||
.partner-type-option {
|
||
padding: 10px 12px;
|
||
}
|
||
|
||
.option-label {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
</style> |