- 移除 localStorage 表单缓存(STORAGE_KEY、saveFormToStorage、restoreFormFromStorage、clearFormStorage、watch、onUnload) - 恢复 getPendingRecord API 调用和弹窗逻辑 - 恢复继续测评模式(表单自动填充、禁用编辑、按钮文案切换) - 恢复进行中测评弹窗(重新开始/继续测评)
953 lines
23 KiB
Vue
953 lines
23 KiB
Vue
<script setup>
|
||
/**
|
||
* 测评信息填写页面
|
||
*
|
||
* 功能:
|
||
* - 顶部 banner 插画区域
|
||
* - 表单填写:姓名、手机号、性别、年龄、学业阶段、省市区
|
||
* - 支付测评和邀请码免费测评两个入口
|
||
* - 邀请码验证弹窗
|
||
* - 进行中测评记录恢复(断点续答)
|
||
*/
|
||
|
||
import { ref, computed } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { useUserStore } from '@/store/user.js'
|
||
import { useAuth } from '@/composables/useAuth.js'
|
||
import { usePayment } from '@/composables/usePayment.js'
|
||
import { getIntro, verifyInviteCode, getPendingRecord } from '@/api/assessment.js'
|
||
import { createOrder } from '@/api/order.js'
|
||
import { isPhone } from '@/utils/validate.js'
|
||
import Navbar from '@/components/Navbar/index.vue'
|
||
|
||
const userStore = useUserStore()
|
||
const { checkLogin } = useAuth()
|
||
const { processPayment } = usePayment()
|
||
|
||
// 页面参数
|
||
const typeId = ref(0)
|
||
const typeName = ref('')
|
||
|
||
// 测评介绍数据
|
||
const introData = ref({
|
||
title: '',
|
||
description: '',
|
||
imageUrl: '',
|
||
price: 0
|
||
})
|
||
|
||
// 表单数据
|
||
const formData = ref({
|
||
name: '',
|
||
phone: '',
|
||
gender: '',
|
||
age: '',
|
||
educationStage: '',
|
||
province: '',
|
||
city: '',
|
||
district: ''
|
||
})
|
||
|
||
// 选择器数据
|
||
const genderOptions = ['男', '女']
|
||
const ageOptions = Array.from({ length: 41 }, (_, i) => `${i + 10}岁`)
|
||
const educationOptions = ['小学及以下', '初中', '高中', '大专', '本科', '研究生及以上']
|
||
|
||
/**
|
||
* 学业阶段文本转数值
|
||
*/
|
||
function getEducationStageValue(label) {
|
||
const map = {
|
||
'小学及以下': 1, '初中': 2, '高中': 3,
|
||
'大专': 4, '本科': 4, '研究生及以上': 4
|
||
}
|
||
return map[label] || 1
|
||
}
|
||
|
||
// 选择器索引
|
||
const genderIndex = ref(-1)
|
||
const ageIndex = ref(-1)
|
||
const educationIndex = ref(-1)
|
||
|
||
// 省市区数据
|
||
const regionValue = ref([])
|
||
|
||
// 邀请码弹窗
|
||
const showInvitePopup = ref(false)
|
||
const inviteCode = ref('')
|
||
const inviteLoading = ref(false)
|
||
|
||
// 页面加载状态
|
||
const pageLoading = ref(true)
|
||
|
||
// 进行中测评记录
|
||
const pendingRecord = ref(null)
|
||
const showPendingPopup = ref(false)
|
||
|
||
/**
|
||
* 是否为继续测评模式
|
||
*/
|
||
const isContinueMode = computed(() => !!pendingRecord.value)
|
||
|
||
/**
|
||
* 性别数值转文本
|
||
*/
|
||
function getGenderLabel(val) {
|
||
return val === 1 ? '男' : val === 2 ? '女' : ''
|
||
}
|
||
|
||
/**
|
||
* 学业阶段数值转文本
|
||
*/
|
||
function getEducationStageLabel(val) {
|
||
const map = { 1: '小学及以下', 2: '初中', 3: '高中', 4: '大专' }
|
||
return map[val] || ''
|
||
}
|
||
|
||
/**
|
||
* 检查是否有进行中的测评记录
|
||
*/
|
||
async function checkPendingRecord() {
|
||
try {
|
||
const res = await getPendingRecord(typeId.value)
|
||
if (res && res.code === 0 && res.data) {
|
||
pendingRecord.value = res.data
|
||
showPendingPopup.value = true
|
||
}
|
||
} catch (e) {
|
||
console.error('检查进行中测评失败:', e)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 继续进行中的测评
|
||
*/
|
||
function handleContinuePending() {
|
||
if (!pendingRecord.value) return
|
||
const r = pendingRecord.value
|
||
|
||
// 填充表单
|
||
formData.value.name = r.name || ''
|
||
formData.value.phone = r.phone || ''
|
||
formData.value.gender = getGenderLabel(r.gender)
|
||
formData.value.age = r.age ? `${r.age}岁` : ''
|
||
formData.value.educationStage = getEducationStageLabel(r.educationStage)
|
||
formData.value.province = r.province || ''
|
||
formData.value.city = r.city || ''
|
||
formData.value.district = r.district || ''
|
||
|
||
// 同步选择器索引
|
||
genderIndex.value = r.gender === 1 ? 0 : r.gender === 2 ? 1 : -1
|
||
ageIndex.value = r.age ? r.age - 10 : -1
|
||
educationIndex.value = educationOptions.indexOf(getEducationStageLabel(r.educationStage))
|
||
regionValue.value = [r.province || '', r.city || '', r.district || '']
|
||
|
||
showPendingPopup.value = false
|
||
}
|
||
|
||
/**
|
||
* 放弃进行中的测评,重新开始
|
||
*/
|
||
function handleDismissPending() {
|
||
pendingRecord.value = null
|
||
showPendingPopup.value = false
|
||
}
|
||
|
||
/**
|
||
* 表单是否填写完整
|
||
*/
|
||
const isFormComplete = computed(() => {
|
||
return (
|
||
formData.value.name.trim() !== '' &&
|
||
formData.value.phone.trim() !== '' &&
|
||
formData.value.gender !== '' &&
|
||
formData.value.age !== '' &&
|
||
formData.value.educationStage !== '' &&
|
||
formData.value.province !== '' &&
|
||
formData.value.city !== '' &&
|
||
formData.value.district !== ''
|
||
)
|
||
})
|
||
|
||
/**
|
||
* 底部按钮文案
|
||
*/
|
||
const payBtnText = computed(() => {
|
||
if (isContinueMode.value) return '继续测评'
|
||
return `支付¥${introData.value.price || 20}元开始测评`
|
||
})
|
||
|
||
/**
|
||
* 加载测评介绍
|
||
*/
|
||
async function loadIntro() {
|
||
pageLoading.value = true
|
||
try {
|
||
const res = await getIntro(typeId.value)
|
||
if (res && res.code === 0 && res.data) {
|
||
introData.value = {
|
||
title: res.data.title || typeName.value || '多元智能测评',
|
||
description: res.data.description || '',
|
||
imageUrl: res.data.imageUrl || '',
|
||
price: res.data.price || 0
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载测评介绍失败:', error)
|
||
} finally {
|
||
pageLoading.value = false
|
||
}
|
||
}
|
||
|
||
/** 性别选择 */
|
||
function onGenderChange(e) {
|
||
genderIndex.value = e.detail.value
|
||
formData.value.gender = genderOptions[e.detail.value]
|
||
}
|
||
|
||
/** 年龄选择 */
|
||
function onAgeChange(e) {
|
||
ageIndex.value = e.detail.value
|
||
formData.value.age = ageOptions[e.detail.value]
|
||
}
|
||
|
||
/** 学业阶段选择 */
|
||
function onEducationChange(e) {
|
||
educationIndex.value = e.detail.value
|
||
formData.value.educationStage = educationOptions[e.detail.value]
|
||
}
|
||
|
||
/** 省市区选择 */
|
||
function onRegionChange(e) {
|
||
const value = e.detail.value
|
||
regionValue.value = value
|
||
formData.value.province = value[0] || ''
|
||
formData.value.city = value[1] || ''
|
||
formData.value.district = value[2] || ''
|
||
}
|
||
|
||
/** 验证表单 */
|
||
function validateForm() {
|
||
if (!formData.value.name.trim()) {
|
||
uni.showToast({ title: '请输入姓名', icon: 'none' })
|
||
return false
|
||
}
|
||
if (!isPhone(formData.value.phone)) {
|
||
uni.showToast({ title: '手机号格式有误', icon: 'none' })
|
||
return false
|
||
}
|
||
if (!formData.value.gender) {
|
||
uni.showToast({ title: '请选择性别', icon: 'none' })
|
||
return false
|
||
}
|
||
if (!formData.value.age) {
|
||
uni.showToast({ title: '请选择年龄', icon: 'none' })
|
||
return false
|
||
}
|
||
if (!formData.value.educationStage) {
|
||
uni.showToast({ title: '请选择学业阶段', icon: 'none' })
|
||
return false
|
||
}
|
||
if (!formData.value.district) {
|
||
uni.showToast({ title: '请选择所在城市', icon: 'none' })
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
/**
|
||
* 构建测评信息对象
|
||
*/
|
||
function buildAssessmentInfo() {
|
||
return {
|
||
name: formData.value.name,
|
||
phone: formData.value.phone,
|
||
gender: formData.value.gender === '男' ? 1 : 2,
|
||
age: parseInt(formData.value.age) || 0,
|
||
educationStage: getEducationStageValue(formData.value.educationStage),
|
||
province: formData.value.province,
|
||
city: formData.value.city,
|
||
district: formData.value.district
|
||
}
|
||
}
|
||
|
||
/** 支付测评 */
|
||
async function handlePayAssessment() {
|
||
if (!checkLogin()) return
|
||
|
||
// 继续测评模式:直接跳转到答题页
|
||
if (isContinueMode.value && pendingRecord.value) {
|
||
uni.redirectTo({
|
||
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${pendingRecord.value.recordId}`
|
||
})
|
||
return
|
||
}
|
||
|
||
if (!validateForm()) return
|
||
|
||
try {
|
||
uni.showLoading({ title: '创建订单中...' })
|
||
const result = await processPayment({
|
||
orderType: 1,
|
||
productId: typeId.value,
|
||
assessmentInfo: buildAssessmentInfo()
|
||
})
|
||
uni.hideLoading()
|
||
|
||
if (result.success) {
|
||
// 从 createOrder 返回中获取 assessmentRecordId
|
||
const recordId = result.assessmentRecordId || ''
|
||
uni.redirectTo({
|
||
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${recordId}`
|
||
})
|
||
} else if (result.error) {
|
||
uni.showToast({ title: result.error, icon: 'none' })
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('支付失败:', error)
|
||
uni.showToast({ title: '支付失败,请重试', icon: 'none' })
|
||
}
|
||
}
|
||
|
||
/** 打开邀请码弹窗 */
|
||
function openInvitePopup() {
|
||
if (!checkLogin()) return
|
||
if (!validateForm()) return
|
||
inviteCode.value = ''
|
||
showInvitePopup.value = true
|
||
}
|
||
|
||
/** 关闭邀请码弹窗 */
|
||
function closeInvitePopup() {
|
||
showInvitePopup.value = false
|
||
inviteCode.value = ''
|
||
}
|
||
|
||
/** 邀请码输入处理 */
|
||
function onInviteCodeInput(e) {
|
||
inviteCode.value = e.detail.value.toUpperCase()
|
||
}
|
||
|
||
/** 提交邀请码 */
|
||
async function submitInviteCode() {
|
||
if (!inviteCode.value.trim()) {
|
||
uni.showToast({ title: '请输入邀请码', icon: 'none' })
|
||
return
|
||
}
|
||
|
||
inviteLoading.value = true
|
||
try {
|
||
// 1. 验证邀请码
|
||
const res = await verifyInviteCode(inviteCode.value.trim())
|
||
if (!res || res.code !== 0 || !res.data || !res.data.isValid) {
|
||
uni.showToast({
|
||
title: res?.data?.errorMessage || res?.message || '邀请码有误,请重新输入',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 2. 邀请码有效,创建免费订单(带 inviteCodeId)
|
||
const inviteCodeId = res.data.inviteCodeId
|
||
uni.showLoading({ title: '创建订单中...' })
|
||
|
||
const orderRes = await createOrder({
|
||
orderType: 1,
|
||
productId: typeId.value,
|
||
assessmentInfo: buildAssessmentInfo(),
|
||
inviteCodeId: inviteCodeId
|
||
})
|
||
uni.hideLoading()
|
||
|
||
if (orderRes && orderRes.code === 0 && orderRes.data) {
|
||
closeInvitePopup()
|
||
const recordId = orderRes.data.assessmentRecordId || ''
|
||
uni.redirectTo({
|
||
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${recordId}`
|
||
})
|
||
} else {
|
||
uni.showToast({ title: orderRes?.message || '创建订单失败', icon: 'none' })
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('邀请码提交失败:', error)
|
||
uni.showToast({ title: '提交失败,请重试', icon: 'none' })
|
||
} finally {
|
||
inviteLoading.value = false
|
||
}
|
||
}
|
||
|
||
/** 页面加载 */
|
||
onLoad((options) => {
|
||
typeId.value = Number(options.typeId) || 1
|
||
typeName.value = decodeURIComponent(options.typeName || '')
|
||
userStore.restoreFromStorage()
|
||
|
||
// 如果已登录且手机号为空,预填手机号
|
||
if (userStore.isLoggedIn && userStore.phone && !formData.value.phone) {
|
||
formData.value.phone = userStore.phone
|
||
}
|
||
|
||
loadIntro()
|
||
|
||
// 检查是否有进行中的测评记录
|
||
if (userStore.isLoggedIn) {
|
||
checkPendingRecord()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<view class="assessment-info-page">
|
||
<!-- 导航栏 -->
|
||
<Navbar title="多元智能测评" :showBack="true" />
|
||
|
||
<!-- 蓝色 banner 区域 -->
|
||
<view class="banner-section">
|
||
<image
|
||
v-if="introData.imageUrl"
|
||
:src="introData.imageUrl"
|
||
mode="widthFix"
|
||
class="banner-image"
|
||
/>
|
||
<view v-else class="banner-placeholder">
|
||
<image src="/static/logo.png" mode="aspectFit" class="banner-logo" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 表单卡片 -->
|
||
<view class="form-card">
|
||
<view class="form-tip">
|
||
{{ isContinueMode ? '您有一份进行中的测评,信息已自动填充' : '正式测评前,请先填写您的基本信息' }}
|
||
</view>
|
||
|
||
<!-- 姓名 -->
|
||
<view class="form-item">
|
||
<view class="form-label"><text class="required">*</text>姓名</view>
|
||
<view class="form-input-box">
|
||
<input
|
||
type="text"
|
||
placeholder="请输入"
|
||
placeholder-class="input-placeholder"
|
||
v-model="formData.name"
|
||
maxlength="20"
|
||
:disabled="isContinueMode"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 手机号 -->
|
||
<view class="form-item">
|
||
<view class="form-label"><text class="required">*</text>手机号</view>
|
||
<view class="form-input-box">
|
||
<input
|
||
type="number"
|
||
placeholder="请输入"
|
||
placeholder-class="input-placeholder"
|
||
v-model="formData.phone"
|
||
maxlength="11"
|
||
:disabled="isContinueMode"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 性别 -->
|
||
<view class="form-item">
|
||
<view class="form-label"><text class="required">*</text>性别</view>
|
||
<picker mode="selector" :range="genderOptions" @change="onGenderChange" :disabled="isContinueMode">
|
||
<view class="form-select-box">
|
||
<text :class="formData.gender ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.gender || '请选择' }}
|
||
</text>
|
||
<view class="arrow-down"></view>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
|
||
<!-- 年龄 -->
|
||
<view class="form-item">
|
||
<view class="form-label"><text class="required">*</text>年龄</view>
|
||
<picker mode="selector" :range="ageOptions" @change="onAgeChange" :disabled="isContinueMode">
|
||
<view class="form-select-box">
|
||
<text :class="formData.age ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.age || '请选择' }}
|
||
</text>
|
||
<view class="arrow-down"></view>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
|
||
<!-- 学业阶段 -->
|
||
<view class="form-item">
|
||
<view class="form-label"><text class="required">*</text>学业阶段</view>
|
||
<picker mode="selector" :range="educationOptions" @change="onEducationChange" :disabled="isContinueMode">
|
||
<view class="form-select-box">
|
||
<text :class="formData.educationStage ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.educationStage || '请选择' }}
|
||
</text>
|
||
<view class="arrow-down"></view>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
|
||
<!-- 所在城市 -->
|
||
<view class="form-item form-item-last">
|
||
<view class="form-label"><text class="required">*</text>所在城市</view>
|
||
<picker mode="region" @change="onRegionChange" :disabled="isContinueMode">
|
||
<view class="form-region-row">
|
||
<view class="region-box">
|
||
<text :class="formData.province ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.province || '省' }}
|
||
</text>
|
||
<view class="arrow-down-sm"></view>
|
||
</view>
|
||
<view class="region-box">
|
||
<text :class="formData.city ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.city || '市' }}
|
||
</text>
|
||
<view class="arrow-down-sm"></view>
|
||
</view>
|
||
<view class="region-box">
|
||
<text :class="formData.district ? 'select-value' : 'select-placeholder'">
|
||
{{ formData.district || '区/县' }}
|
||
</text>
|
||
<view class="arrow-down-sm"></view>
|
||
</view>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部按钮 -->
|
||
<view class="btn-group">
|
||
<view v-if="!isContinueMode" class="btn-invite" @click="openInvitePopup">
|
||
<text>邀请码免费测评</text>
|
||
</view>
|
||
<view class="btn-pay" :class="{ 'btn-full': isContinueMode }" @click="handlePayAssessment">
|
||
<text>{{ payBtnText }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 邀请码弹窗 -->
|
||
<view v-if="showInvitePopup" class="popup-mask" @click="closeInvitePopup">
|
||
<view class="popup-container" @click.stop>
|
||
<view class="popup-header">
|
||
<text class="popup-title">填写测评邀请码</text>
|
||
<view class="popup-close" @click="closeInvitePopup">
|
||
<text>×</text>
|
||
</view>
|
||
</view>
|
||
<view class="popup-body">
|
||
<input
|
||
class="invite-input"
|
||
type="text"
|
||
placeholder="请输入5位邀请码"
|
||
:value="inviteCode"
|
||
@input="onInviteCodeInput"
|
||
maxlength="5"
|
||
/>
|
||
</view>
|
||
<view class="popup-footer">
|
||
<view class="popup-btn" :class="{ 'btn-loading': inviteLoading }" @click="submitInviteCode">
|
||
<text>{{ inviteLoading ? '验证中...' : '提交' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 进行中测评弹窗 -->
|
||
<view v-if="showPendingPopup" class="popup-mask" @click="handleDismissPending">
|
||
<view class="popup-container pending-popup" @click.stop>
|
||
<view class="popup-header">
|
||
<text class="popup-title">发现进行中的测评</text>
|
||
</view>
|
||
<view class="popup-body">
|
||
<view class="pending-msg">
|
||
您有一份未完成的测评记录,是否继续?
|
||
</view>
|
||
<view class="pending-info">
|
||
<text>姓名:{{ pendingRecord?.name }}</text>
|
||
<text>手机号:{{ pendingRecord?.phone }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="pending-footer">
|
||
<view class="popup-btn-outline" @click="handleDismissPending">
|
||
<text>重新开始</text>
|
||
</view>
|
||
<view class="popup-btn" @click="handleContinuePending">
|
||
<text>继续测评</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/styles/variables.scss';
|
||
|
||
.assessment-info-page {
|
||
min-height: 100vh;
|
||
background-color: rgba(255, 234, 231, 1);
|
||
padding-bottom: calc(#{$spacing-xl} + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
// ========== Banner 区域 ==========
|
||
.banner-section {
|
||
width: 100%;
|
||
height: 400rpx;
|
||
background: linear-gradient(180deg, #4A90E2 0%, #6BB5FF 100%);
|
||
overflow: hidden;
|
||
|
||
.banner-image {
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.banner-placeholder {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.banner-logo {
|
||
width: 400rpx;
|
||
height: 280rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 表单卡片 ==========
|
||
.form-card {
|
||
background-color: $bg-white;
|
||
border-radius: $border-radius-xl;
|
||
margin: $spacing-lg $spacing-lg 0;
|
||
padding: $spacing-xl $spacing-lg $spacing-lg;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.form-tip {
|
||
text-align: center;
|
||
font-size: $font-size-md;
|
||
color: $text-secondary;
|
||
margin-bottom: $spacing-xl;
|
||
}
|
||
|
||
// ========== 表单项 ==========
|
||
.form-item {
|
||
margin-bottom: $spacing-lg;
|
||
}
|
||
|
||
.form-item-last {
|
||
margin-bottom: 0;
|
||
padding-bottom: $spacing-lg;
|
||
}
|
||
|
||
.form-label {
|
||
font-size: $font-size-lg;
|
||
color: $text-color;
|
||
font-weight: $font-weight-bold;
|
||
margin-bottom: $spacing-sm;
|
||
|
||
.required {
|
||
color: $error-color;
|
||
margin-right: 4rpx;
|
||
}
|
||
}
|
||
|
||
// 文本输入框 - 灰色背景圆角
|
||
.form-input-box {
|
||
background-color: $bg-gray;
|
||
border-radius: $border-radius-md;
|
||
padding: 0 $spacing-lg;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
input {
|
||
width: 100%;
|
||
height: 100%;
|
||
font-size: $font-size-md;
|
||
color: $text-color;
|
||
}
|
||
}
|
||
|
||
.input-placeholder {
|
||
color: $text-placeholder;
|
||
font-size: $font-size-md;
|
||
}
|
||
|
||
// 下拉选择框 - 灰色背景圆角 + 下拉箭头
|
||
.form-select-box {
|
||
background-color: $bg-gray;
|
||
border-radius: $border-radius-md;
|
||
padding: 0 $spacing-lg;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.select-value {
|
||
font-size: $font-size-md;
|
||
color: $text-color;
|
||
}
|
||
|
||
.select-placeholder {
|
||
font-size: $font-size-md;
|
||
color: $text-placeholder;
|
||
}
|
||
}
|
||
|
||
// CSS 下拉箭头
|
||
.arrow-down {
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-right: 3rpx solid $text-placeholder;
|
||
border-bottom: 3rpx solid $text-placeholder;
|
||
transform: rotate(45deg);
|
||
flex-shrink: 0;
|
||
margin-left: $spacing-sm;
|
||
}
|
||
|
||
.arrow-down-sm {
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
border-right: 3rpx solid $text-placeholder;
|
||
border-bottom: 3rpx solid $text-placeholder;
|
||
transform: rotate(45deg);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
// 省市区三列选择
|
||
.form-region-row {
|
||
display: flex;
|
||
gap: $spacing-md;
|
||
}
|
||
|
||
.region-box {
|
||
flex: 1;
|
||
background-color: $bg-gray;
|
||
border-radius: $border-radius-md;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: $spacing-xs;
|
||
|
||
.select-value {
|
||
font-size: $font-size-md;
|
||
color: $text-color;
|
||
}
|
||
|
||
.select-placeholder {
|
||
font-size: $font-size-md;
|
||
color: $text-placeholder;
|
||
}
|
||
}
|
||
|
||
// ========== 底部按钮 ==========
|
||
.btn-group {
|
||
display: flex;
|
||
gap: $spacing-md;
|
||
padding: $spacing-xl $spacing-lg 0;
|
||
}
|
||
|
||
.btn-invite {
|
||
flex: 0.8;
|
||
height: 88rpx;
|
||
background-color: $bg-white;
|
||
border: 2rpx solid #FF6B60;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
text {
|
||
font-size: $font-size-md;
|
||
font-weight: $font-weight-medium;
|
||
color: #FF6B60;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
|
||
.btn-pay {
|
||
flex: 1;
|
||
height: 88rpx;
|
||
background-color: #FF6B60;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
text {
|
||
font-size: $font-size-md;
|
||
font-weight: $font-weight-medium;
|
||
color: $text-white;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
&.btn-full {
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
// ========== 弹窗通用 ==========
|
||
.popup-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: $bg-mask;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.popup-container {
|
||
width: 600rpx;
|
||
background-color: $bg-white;
|
||
border-radius: $border-radius-xl;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.popup-header {
|
||
position: relative;
|
||
padding: $spacing-lg;
|
||
text-align: center;
|
||
border-bottom: 1rpx solid $border-light;
|
||
|
||
.popup-title {
|
||
font-size: $font-size-lg;
|
||
font-weight: $font-weight-medium;
|
||
color: $text-color;
|
||
}
|
||
|
||
.popup-close {
|
||
position: absolute;
|
||
top: $spacing-md;
|
||
right: $spacing-md;
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
text {
|
||
font-size: 48rpx;
|
||
color: $text-placeholder;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.popup-body {
|
||
padding: $spacing-xl $spacing-lg;
|
||
}
|
||
|
||
.popup-footer {
|
||
padding: 0 $spacing-lg $spacing-xl;
|
||
}
|
||
|
||
.popup-btn {
|
||
height: 88rpx;
|
||
background-color: #FF6B60;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
text {
|
||
font-size: $font-size-lg;
|
||
font-weight: $font-weight-medium;
|
||
color: $text-white;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
&.btn-loading {
|
||
opacity: 0.7;
|
||
pointer-events: none;
|
||
}
|
||
}
|
||
|
||
.popup-btn-outline {
|
||
height: 88rpx;
|
||
background-color: $bg-white;
|
||
border: 2rpx solid $border-color;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
text {
|
||
font-size: $font-size-lg;
|
||
font-weight: $font-weight-medium;
|
||
color: $text-secondary;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
|
||
// ========== 进行中测评弹窗 ==========
|
||
.pending-popup {
|
||
.pending-msg {
|
||
font-size: $font-size-md;
|
||
color: $text-color;
|
||
text-align: center;
|
||
margin-bottom: $spacing-lg;
|
||
}
|
||
|
||
.pending-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: $spacing-sm;
|
||
background-color: $bg-gray;
|
||
border-radius: $border-radius-md;
|
||
padding: $spacing-lg;
|
||
|
||
text {
|
||
font-size: $font-size-sm;
|
||
color: $text-secondary;
|
||
}
|
||
}
|
||
}
|
||
|
||
.pending-footer {
|
||
display: flex;
|
||
gap: $spacing-md;
|
||
padding: 0 $spacing-lg $spacing-xl;
|
||
|
||
.popup-btn-outline,
|
||
.popup-btn {
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
// ========== 邀请码输入 ==========
|
||
.invite-input {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background-color: $bg-gray;
|
||
border-radius: $border-radius-md;
|
||
padding: 0 $spacing-lg;
|
||
font-size: $font-size-lg;
|
||
color: $text-color;
|
||
text-align: center;
|
||
letter-spacing: 8rpx;
|
||
}
|
||
</style>
|