Files
ks-app-employment-service/pages/complete-info/complete-info.vue
2025-11-10 19:37:16 +08:00

1014 lines
35 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>
<AppLayout title="AI+就业服务程序">
<view class="tab-container">
<view class="uni-margin-wrap">
<swiper
class="swiper"
:current="tabCurrent"
:circular="false"
:indicator-dots="false"
:autoplay="false"
:duration="500"
>
<swiper-item @touchmove.stop="false">
<view class="login-content">
<image class="logo" src="@/static/logo.png"></image>
<view class="logo-title">就业</view>
</view>
<view class="btns">
<button class="wxlogin" @click="loginTest">内测登录</button>
<view class="wxaddress">{{ config.appInfo.areaName }}公共就业和人才服务中心</view>
</view>
</swiper-item>
<swiper-item @touchmove.stop="false">
<view class="content-one">
<!-- 固定标题 -->
<view class="content-title">
<view class="title-lf">
<view class="lf-h1">请您完善求职名片</view>
<view class="lf-text">个人信息仅用于推送优质内容</view>
</view>
<view class="title-ri">
<text style="color: #256bfa">1</text>
<text>/2</text>
</view>
</view>
<!-- 可滚动内容区域 -->
<scroll-view class="scroll-content" scroll-y>
<view class="scroll-inner">
<view class="content-input" :class="{ 'input-error': nameError }">
<view class="input-titile">姓名</view>
<input
class="input-con2"
v-model="fromValue.name"
maxlength="18"
placeholder="请输入姓名"
@input="validateName"
/>
<view v-if="nameError" class="error-message">{{ nameError }}</view>
</view>
<view class="content-input" :class="{ 'input-error': passwordError }">
<view class="input-titile">密码</view>
<input
class="input-con2"
v-model="fromValue.ytjPassword"
type="password"
placeholder="请输入密码"
maxlength="8"
@input="validatePassword"
/>
<view v-if="passwordError" class="error-message">{{ passwordError }}</view>
<view v-if="fromValue.ytjPassword && !passwordError" class="success-message"> 密码格式正确</view>
</view>
<view class="content-sex" :class="{ 'input-error': sexError }">
<view class="sex-titile">性别</view>
<view class="sext-ri">
<view
class="sext-box"
:class="{ 'sext-boxactive': fromValue.sex === 0 }"
@click="changeSex(0)"
>
</view>
<view
class="sext-box"
:class="{ 'sext-boxactive': fromValue.sex === 1 }"
@click="changeSex(1)"
>
</view>
</view>
</view>
<view v-if="sexError" class="error-message">{{ sexError }}</view>
<view class="content-input" :class="{ 'input-error': ageError }">
<view class="input-titile">年龄</view>
<input
class="input-con2"
v-model="fromValue.age"
maxlength="3"
placeholder="请输入年龄"
@input="validateAge"
/>
<view v-if="ageError" class="error-message">{{ ageError }}</view>
</view>
<view class="content-input" :class="{ 'input-error': experienceError }" @click="changeExperience">
<view class="input-titile">工作经验</view>
<input
class="input-con"
v-model="state.workExperience"
disabled
placeholder="请选择您的工作经验"
/>
<view v-if="experienceError" class="error-message">{{ experienceError }}</view>
</view>
<view class="content-input" @click="changeEducation">
<view class="input-titile">学历</view>
<input class="input-con" v-model="state.educationText" disabled placeholder="本科" />
</view>
<view class="content-input" :class="{ 'input-error': idCardError }">
<view class="input-titile">身份证</view>
<input
class="input-con2"
v-model="fromValue.idCard"
maxlength="18"
placeholder="请输入身份证号码"
@input="validateIdCard"
/>
<view v-if="idCardError" class="error-message">{{ idCardError }}</view>
<view v-if="fromValue.idCard && !idCardError" class="success-message"> 身份证格式正确</view>
</view>
</view>
</scroll-view>
<!-- 固定按钮 -->
<view class="next-btn" @tap="nextStep">下一步</view>
</view>
</swiper-item>
<swiper-item @touchmove.stop="false">
<view class="content-one">
<!-- 固定标题 -->
<view class="content-title">
<view class="title-lf">
<view class="lf-h1">请您完善求职名片</view>
<view class="lf-text">个人信息仅用于推送优质内容</view>
</view>
<view class="title-ri">
<text style="color: #256bfa">2</text>
<text>/2</text>
</view>
</view>
<!-- 可滚动内容区域 -->
<scroll-view class="scroll-content" scroll-y>
<view class="scroll-inner">
<view class="content-input" @click="changeArea">
<view class="input-titile">求职区域</view>
<input
class="input-con"
v-model="state.areaText"
disabled
placeholder="请选择您的求职区域"
/>
</view>
<view class="content-input" @click="changeJobs">
<view class="input-titile">求职岗位</view>
<input
class="input-con"
disabled
v-if="!state.jobsText.length"
placeholder="请选择您的求职岗位"
/>
<view class="input-nx" @click="changeJobs" v-else>
<view class="nx-item" v-for="(item, index) in state.jobsText" :key="index">{{ item }}</view>
</view>
</view>
<view class="content-input" @click="changeSkillLevel">
<view class="input-titile">技能等级</view>
<input
class="input-con"
v-model="state.skillLevelText"
disabled
placeholder="请选择您的技能等级"
/>
</view>
<view class="content-input" @click="changeSkills">
<view class="input-titile">技能名称</view>
<input
class="input-con"
disabled
v-if="!state.skillsText.length"
placeholder="请选择您的技能名称"
/>
<view class="input-nx" @click="changeSkills" v-else>
<view class="nx-item" v-for="(item, index) in state.skillsText" :key="index">{{ item }}</view>
</view>
</view>
<view class="content-input" @click="changeSalay">
<view class="input-titile">期望薪资</view>
<input
class="input-con"
v-model="state.salayText"
disabled
placeholder="请选择您的期望薪资"
/>
</view>
</view>
</scroll-view>
<!-- 固定按钮 -->
<view class="next-btn" @tap="complete">开启求职之旅</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<SelectJobs ref="selectJobsModel"></SelectJobs>
<SelectPopup ref="selectPopupRef"></SelectPopup>
</AppLayout>
</template>
<script setup>
import SelectJobs from '@/components/selectJobs/selectJobs.vue';
import SelectPopup from '@/components/selectPopup/selectPopup.vue';
import { reactive, inject, watch, ref, onMounted, onUnmounted } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import useUserStore from '@/stores/useUserStore';
import useDictStore from '@/stores/useDictStore';
const { $api, navTo, config, IdCardValidator } = inject('globalFunction');
const { loginSetToken, getUserResume } = useUserStore();
const dictStore = useDictStore();
const { getDictSelectOption, oneDictData, complete: dictComplete, getDictData } = dictStore;
// #ifdef H5
const injectedOpenSelectPopup = inject('openSelectPopup', null);
// #endif
// status
const selectJobsModel = ref();
const selectPopupRef = ref();
// 创建本地的 openSelectPopup 函数
const openSelectPopup = (config) => {
// #ifdef MP-WEIXIN
if (selectPopupRef.value) {
selectPopupRef.value.open(config);
}
// #endif
// #ifdef H5
if (injectedOpenSelectPopup) {
injectedOpenSelectPopup(config);
}
// #endif
};
const tabCurrent = ref(1);
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
const state = reactive({
station: [],
stationCateLog: 1,
lfsalay: [2, 5, 10, 15, 20, 25, 30, 50],
risalay: JSON.parse(JSON.stringify(salay)),
areaText: '',
educationText: '',
workExperience: '',
salayText: '',
jobsText: [],
skillLevelText: '',
skillsText: [],
});
const fromValue = reactive({
sex: null,
education: '4',
salaryMin: 2000,
salaryMax: 2000,
area: 0,
jobTitleId: '',
workExperience: '1',
idCard: '',
name: '',
age: '',
skillLevel: '',
skills: '',
ytjPassword: '',
});
// 输入校验相关
const idCardError = ref('');
const nameError = ref('');
const ageError = ref('');
const sexError = ref('');
const experienceError = ref('');
const passwordError = ref('');
onLoad((parmas) => {
getTreeselect();
// 初始化学历显示文本
initEducationText();
});
// 初始化学历显示文本
function initEducationText() {
// 等待字典数据加载完成
const checkDictData = () => {
if (complete.value && dictStore.state.education && dictStore.state.education.length > 0) {
// 字典数据已加载,设置学历显示文本
if (fromValue.education) {
const educationValue = Number(fromValue.education);
state.educationText = dictStore.dictLabel('education', educationValue);
}
} else {
// 如果字典数据未加载,等待一段时间后重试
setTimeout(() => {
if (complete.value && dictStore.state.education && dictStore.state.education.length > 0) {
if (fromValue.education) {
const educationValue = Number(fromValue.education);
state.educationText = dictStore.dictLabel('education', educationValue);
}
} else {
// 如果还是未加载,尝试加载字典数据
getDictSelectOption('education').then((data) => {
dictStore.state.education = data;
if (fromValue.education) {
const educationValue = Number(fromValue.education);
state.educationText = dictStore.dictLabel('education', educationValue);
}
}).catch((error) => {
console.error('加载学历字典数据失败:', error);
});
}
}, 500);
}
};
checkDictData();
}
// 技能选择回调函数
const handleSkillSelected = (skills) => {
if (Array.isArray(skills) && skills.length > 0) {
// 更新技能显示和值技能字段值传name
state.skillsText = skills;
fromValue.skills = skills.join(',');
} else {
// 如果返回空数组,清空选择
state.skillsText = [];
fromValue.skills = '';
}
};
// 监听页面显示,接收从技能查询页面返回的数据
onShow(() => {
// 通过事件总线接收技能选择结果
uni.$on('skillSelected', handleSkillSelected);
});
// 页面卸载时移除事件监听
onUnmounted(() => {
uni.$off('skillSelected', handleSkillSelected);
});
onMounted(() => {});
function changeSex(sex) {
fromValue.sex = sex;
// 选择后清除性别错误
sexError.value = '';
}
// 姓名实时校验中文2-18或英文2-30
function validateName() {
const name = (fromValue.name || '').trim();
if (!name) {
nameError.value = '请输入姓名';
return;
}
const cn = /^[\u4e00-\u9fa5·]{2,18}$/;
const en = /^[A-Za-z\s]{2,30}$/;
nameError.value = cn.test(name) || en.test(name) ? '' : '姓名格式不正确';
}
// 年龄实时校验16-65的整数
function validateAge() {
const ageStr = String(fromValue.age || '').trim();
if (!ageStr) {
ageError.value = '请输入年龄';
return;
}
const num = Number(ageStr);
if (!/^\d{1,3}$/.test(ageStr) || Number.isNaN(num)) {
ageError.value = '年龄必须为数字';
return;
}
ageError.value = num >= 16 && num <= 65 ? '' : '年龄需在16-65之间';
}
// 身份证实时校验
function validateIdCard() {
const idCard = (fromValue.idCard || '').trim();
// 如果为空,清除错误信息
if (!idCard) {
idCardError.value = '';
return;
}
// 检查IdCardValidator是否存在如果不存在提供简单的替代验证
if (IdCardValidator && typeof IdCardValidator.validate === 'function') {
const result = IdCardValidator.validate(idCard);
if (result.valid) {
idCardError.value = '';
} else {
idCardError.value = result.message;
}
} else {
// 简单的身份证验证规则18位最后一位可以是X
const idCardRegex = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
if (idCardRegex.test(idCard)) {
idCardError.value = '';
} else {
idCardError.value = '身份证号码格式不正确';
}
}
}
// 密码实时校验
function validatePassword() {
const password = (fromValue.ytjPassword || '').trim();
// 如果为空,清除错误信息
if (!password) {
passwordError.value = '';
return;
}
// 校验规则长度8位包含大小写字母和数字至少各有一个
if (password.length !== 8) {
passwordError.value = '密码长度必须为8位';
return;
}
// 检查是否包含大写字母
const hasUpperCase = /[A-Z]/.test(password);
// 检查是否包含小写字母
const hasLowerCase = /[a-z]/.test(password);
// 检查是否包含数字
const hasNumber = /[0-9]/.test(password);
if (!hasUpperCase) {
passwordError.value = '密码必须包含至少一个大写字母';
return;
}
if (!hasLowerCase) {
passwordError.value = '密码必须包含至少一个小写字母';
return;
}
if (!hasNumber) {
passwordError.value = '密码必须包含至少一个数字';
return;
}
// 检查是否只包含字母和数字
if (!/^[A-Za-z0-9]+$/.test(password)) {
passwordError.value = '密码只能包含大小写字母和数字';
return;
}
// 校验通过
passwordError.value = '';
}
function changeExperience() {
openSelectPopup({
title: '工作经验',
maskClick: true,
data: [oneDictData('experience')],
success: (_, [value]) => {
fromValue.workExperience = value.value;
state.workExperience = value.label;
// 选择后清除工作经验错误
experienceError.value = '';
},
change(_, [value]) {
// this.setColunm(1, [123, 123]);
console.log(this);
},
});
}
async function changeEducation() {
// 确保字典数据已加载
if (!complete.value || !dictStore.state.education || dictStore.state.education.length === 0) {
// 如果字典数据未加载,先加载数据
try {
await getDictSelectOption('education').then((data) => {
dictStore.state.education = data;
});
} catch (error) {
console.error('加载学历字典数据失败:', error);
}
}
// 等待数据加载完成后再获取数据
let educationData = oneDictData('education');
// 如果数据还是为空,等待一下再试
if (!educationData || educationData.length === 0) {
// 使用 nextTick 确保数据已渲染
await new Promise(resolve => setTimeout(resolve, 100));
educationData = oneDictData('education');
if (!educationData || educationData.length === 0) {
$api.msg('学历数据加载中,请稍后再试');
return;
}
}
// 将当前学历值转换为数字类型,用于查找默认索引
const currentEducation = fromValue.education ? Number(fromValue.education) : null;
// 查找当前学历在数据中的索引
let defaultIndex = [0];
if (currentEducation !== null && educationData && educationData.length > 0) {
const index = educationData.findIndex(item => Number(item.value) === currentEducation);
if (index >= 0) {
defaultIndex = [index];
}
}
openSelectPopup({
title: '学历',
maskClick: true,
data: [educationData],
defaultIndex: defaultIndex,
success: (_, [value]) => {
fromValue.education = String(value.value); // 确保存储为字符串
state.educationText = value.label;
},
});
}
function changeArea() {
openSelectPopup({
title: '区域',
maskClick: true,
data: [oneDictData('area')],
success: (_, [value]) => {
fromValue.area = value.value;
state.areaText = config.appInfo.areaName + '-' + value.label;
},
});
}
function changeSalay() {
let leftIndex = 0;
openSelectPopup({
title: '薪资',
maskClick: true,
data: [state.lfsalay, state.risalay],
unit: 'k',
success: (_, [min, max]) => {
fromValue.salaryMin = min.value * 1000;
fromValue.salaryMax = max.value * 1000;
state.salayText = `${fromValue.salaryMin}-${fromValue.salaryMax}`;
},
change(e) {
const salayData = e.detail.value;
if (leftIndex !== salayData[0]) {
const copyri = JSON.parse(JSON.stringify(salay));
const [lf, ri] = e.detail.value;
const risalay = copyri.slice(lf, copyri.length);
this.setColunm(1, risalay);
leftIndex = salayData[0];
}
},
});
}
function changeJobs() {
selectJobsModel.value?.open({
title: '添加岗位',
success: (ids, labels) => {
fromValue.jobTitleId = ids;
state.jobsText = labels.split(',');
},
});
}
// 技能等级选择
function changeSkillLevel() {
const skillLevels = [
{ label: '初级', value: '1' },
{ label: '中级', value: '2' },
{ label: '高级', value: '3' }
];
openSelectPopup({
title: '技能等级',
maskClick: true,
data: [skillLevels],
success: (_, [value]) => {
fromValue.skillLevel = value.value;
state.skillLevelText = value.label;
},
});
}
// 技能名称选择 - 跳转到模糊查询页面
function changeSkills() {
// 将当前已选中的技能名称传递给查询页面
const selectedSkills = state.skillsText || [];
uni.navigateTo({
url: `/pages/complete-info/skill-search?selected=${encodeURIComponent(JSON.stringify(selectedSkills))}`
});
}
function nextStep() {
// 统一必填与格式校验
validateName();
validateAge();
validateIdCard();
validatePassword();
if (fromValue.sex !== 0 && fromValue.sex !== 1) {
sexError.value = '请选择性别';
}
// 工作经验校验
if (!state.workExperience) {
experienceError.value = '请选择您的工作经验';
} else {
experienceError.value = '';
}
// 学历校验
if (!state.educationText) {
$api.msg('请选择您的学历');
return;
}
// 密码校验
if (!fromValue.ytjPassword) {
$api.msg('请输入密码');
return;
}
if (passwordError.value) {
$api.msg(passwordError.value);
return;
}
// 检查所有错误状态
if (nameError.value) return;
if (sexError.value) return;
if (ageError.value) return;
if (experienceError.value) return;
if (idCardError.value || !fromValue.idCard) {
if (!fromValue.idCard) $api.msg('请输入身份证号码');
return;
}
// 检查IdCardValidator是否存在如果不存在提供简单的替代验证
let isValid = false;
if (IdCardValidator && typeof IdCardValidator.validate === 'function') {
const result = IdCardValidator.validate(fromValue.idCard);
isValid = result.valid;
if (!isValid) {
$api.msg(result.message);
return;
}
} else {
// 简单的身份证验证规则18位最后一位可以是X
const idCardRegex = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
if (!idCardRegex.test(fromValue.idCard)) {
$api.msg('身份证号码格式不正确');
return;
}
isValid = true;
}
tabCurrent.value += 1;
}
// 获取职位
function getTreeselect() {
$api.createRequest('/app/common/jobTitle/treeselect', {}, 'GET').then((resData) => {
state.station = resData.data;
});
}
// 登录
function loginTest() {
// uni.share({
// provider: 'weixin',
// scene: 'WXSceneSession',
// type: 2,
// imageUrl: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni@2x.png',
// success: function (res) {
// console.log('success:' + JSON.stringify(res));
// },
// fail: function (err) {
// console.log('fail:' + JSON.stringify(err));
// },
// });
const params = {
username: 'test',
password: 'test',
};
$api.createRequest('/app/login', params, 'post').then((resData) => {
$api.msg('模拟帐号密码测试登录成功');
loginSetToken(resData.token).then((resume) => {
if (resume.data.jobTitleId) {
// 设置推荐列表,每次退出登录都需要更新
useUserStore().initSeesionId();
uni.reLaunch({
url: '/pages/index/index',
});
} else {
nextStep();
}
});
});
}
function complete() {
// 检查IdCardValidator是否存在如果不存在提供简单的替代验证
let isValid = false;
if (IdCardValidator && typeof IdCardValidator.validate === 'function') {
const result = IdCardValidator.validate(fromValue.idCard);
isValid = result.valid;
if (!isValid) {
$api.msg('身份证号码格式不正确');
return;
}
} else {
// 简单的身份证验证规则18位最后一位可以是X
const idCardRegex = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
if (!idCardRegex.test(fromValue.idCard)) {
$api.msg('身份证号码格式不正确');
return;
}
isValid = true;
}
if (isValid) {
// 构建 experiencesList 数组
const experiencesList = [];
if (fromValue.skills && fromValue.skillLevel) {
const skillsArray = fromValue.skills.split(',');
skillsArray.forEach(skill => {
if (skill.trim()) {
experiencesList.push({
name: skill.trim(),
levels: fromValue.skillLevel
});
}
});
}
// 构建符合要求的请求数据experiencesList 与 appUser 同级)
const requestData = {
appUser: {
name: fromValue.name,
isCompanyUser: 1,
age: fromValue.age,
sex: fromValue.sex,
workExperience: fromValue.workExperience,
education: fromValue.education,
idCard: fromValue.idCard,
area: fromValue.area,
jobTitleId: fromValue.jobTitleId,
salaryMin: fromValue.salaryMin,
salaryMax: fromValue.salaryMax,
ytjPassword: fromValue.ytjPassword
},
experiencesList: experiencesList
};
$api.createRequest('/registerUser', requestData, 'post').then(async (resData) => {
$api.msg('完成');
// 如果接口返回了token需要重新保存token
if (resData.token) {
try {
await loginSetToken(resData.token);
console.log('Token已更新:', resData.token);
} catch (error) {
console.error('更新Token失败:', error);
}
}
// 保存成功后,重新获取用户信息并更新缓存
try {
await getUserResume();
console.log('用户信息已更新到缓存');
} catch (error) {
console.error('获取用户信息失败:', error);
// 即使获取用户信息失败,也不影响页面跳转
}
// 跳转到首页
uni.reLaunch({
url: '/pages/index/index',
});
});
} else {
$api.msg('身份证校验失败');
console.log('验证失败:', result.message);
}
}
</script>
<style lang="stylus" scoped>
.tab-container
height: 100%
width: 100%
display: flex
align-items: center
justify-content: center
flex-direction: row
.uni-margin-wrap
width: 100%
height: 100%
.swiper
width: 100%
height: 100%
.swiper-item
display: block;
width: 100%
height: 100%
.input-nx
position: relative
border-bottom: 2rpx solid #EBEBEB
padding-bottom: 30rpx
display: flex
flex-wrap: wrap
.nx-item
padding: 16rpx 24rpx
width: fit-content
border-radius: 20rpx
border: 2rpx solid #E8EAEE
background-color: #f8f9fa
margin-right: 16rpx
margin-top: 16rpx
font-size: 28rpx
color: #333333
transition: all 0.2s ease
&:hover
background-color: #e9ecef
border-color: #256bfa
color: #256bfa
// 移除技能标签的箭头样式,因为技能标签不需要箭头指示
.container
// background: linear-gradient(#4778EC, #002979);
width: 100%;
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
position: fixed;
background: url('@/static/icon/background2.png') 0 0 no-repeat;
background-size: 100% 728rpx;
display: flex;
flex-direction: column
.container-hader
height: 88rpx;
text-align: center;
line-height: 88rpx;
color: #000000;
font-weight: bold
font-size: 32rpx
.login-content
position: absolute;
left: 50%;
top: 40%;
transform: translate(-50%, -50%);
display: flex;
align-items: flex-end;
flex-wrap: nowrap;
.logo
width: 266rpx;
height: 182rpx;
.logo-title
font-size: 88rpx;
color: #22c984;
width: 180rpx;
.btns
position: absolute;
top: 70%;
left: 50%;
transform: translate(-50%, 0)
.wxlogin
width: 562rpx;
height: 140rpx;
border-radius: 70rpx;
background-color: #13C57C;
color: #FFFFFF;
text-align: center;
line-height: 140rpx;
font-size: 70rpx;
.wxaddress
color: #BBBBBB;
margin-top: 70rpx;
text-align: center;
.content-one
padding: 0;
display: flex;
flex-direction: column;
height: 100%
.content-title
flex-shrink: 0
padding: 60rpx 28rpx 0
display: flex
justify-content: space-between;
align-items: center
margin-bottom: 40rpx
.title-lf
font-size: 44rpx;
color: #000000;
font-weight: 600;
.lf-text
font-weight: 400;
font-size: 28rpx;
color: #6C7282;
.title-ri
font-size: 36rpx;
color: #000000;
font-weight: 600;
.content-input
margin-bottom: 52rpx
.input-titile
font-weight: 400;
font-size: 28rpx;
color: #6A6A6A;
.input-con2
font-weight: 400;
font-size: 32rpx;
color: #333333;
line-height: 80rpx;
height: 80rpx;
border-bottom: 2rpx solid #EBEBEB
.input-con
font-weight: 400;
font-size: 32rpx;
color: #333333;
line-height: 80rpx;
height: 80rpx;
border-bottom: 2rpx solid #EBEBEB
position: relative;
.input-con::before
position: absolute;
right: 20rpx;
top: calc(50% - 2rpx);
content: '';
width: 4rpx;
height: 18rpx;
border-radius: 2rpx
background: #697279;
transform: translate(0, -50%) rotate(-45deg) ;
.input-con::after
position: absolute;
right: 20rpx;
top: 50%;
content: '';
width: 4rpx;
height: 18rpx;
border-radius: 2rpx
background: #697279;
transform: rotate(45deg)
.error-message
color: #ff4757;
font-size: 24rpx;
margin-top: 10rpx;
line-height: 1.4;
.success-message
color: #2ed573;
font-size: 24rpx;
margin-top: 10rpx;
line-height: 1.4;
.input-error
.input-con2
border-bottom-color: #ff4757;
.content-sex
height: 110rpx;
display: flex
justify-content: space-between;
align-items: flex-start;
border-bottom: 2rpx solid #EBEBEB
margin-bottom: 52rpx
.sex-titile
line-height: 80rpx;
.sext-ri
display: flex
align-items: center;
.sext-box
height: 76rpx;
width: 152rpx;
text-align: center;
line-height: 80rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx
border: 2rpx solid #E8EAEE;
margin-left: 28rpx
font-weight: 400;
font-size: 28rpx;
.sext-boxactive
color: #256BFA
background: rgba(37,107,250,0.1);
border: 2rpx solid #256BFA;
.scroll-content
flex: 1
overflow: hidden
height: 0 // 关键让flex布局正确计算高度
.scroll-inner
padding: 0 28rpx
padding-bottom: 40rpx
.next-btn
flex-shrink: 0
width: calc(100% - 56rpx);
height: 90rpx;
margin: 0 28rpx 40rpx;
background: #256BFA;
border-radius: 12rpx 12rpx 12rpx 12rpx;
font-weight: 500;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
line-height: 90rpx
position: relative
z-index: 100
</style>