Files
ks-app-employment-service/pages/complete-info/complete-info.vue
2025-11-13 11:49:08 +08:00

1147 lines
41 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="changeSalay">
<view class="input-titile">期望薪资</view>
<input
class="input-con"
v-model="state.salayText"
disabled
placeholder="请选择您的期望薪资"
/>
</view>
<view class="content-skills">
<view class="skills-header">
<view class="input-titile">技能信息</view>
<view
class="add-skill-btn"
@click="addSkill"
:class="{ 'disabled': state.skills.length >= 3 }"
>
+ 添加技能
</view>
</view>
<view class="skills-list">
<view class="skill-item" v-for="(skill, index) in state.skills" :key="index">
<view class="skill-header">
<view class="skill-number">技能 {{ index + 1 }}</view>
<view class="skill-actions" v-if="state.skills.length > 1">
<view class="action-btn delete-btn" @click="removeSkill(index)">删除</view>
</view>
</view>
<view class="skill-fields">
<view class="skill-field" @click="changeSkillName(index)">
<view class="field-label">技能名称</view>
<input
class="field-input triangle"
disabled
:value="skill.name"
placeholder="请选择技能名称"
/>
</view>
<view class="skill-field" @click="changeSkillLevel(index)">
<view class="field-label">技能等级</view>
<input
class="field-input triangle"
disabled
:value="getSkillLevelText(skill.level)"
placeholder="请选择技能等级"
/>
</view>
</view>
</view>
<view class="empty-skills" v-if="state.skills.length === 0">
<text class="empty-text">暂无技能信息点击上方按钮添加</text>
</view>
</view>
</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: [],
skills: [], // 新的技能数据结构
currentEditingSkillIndex: -1 // 当前正在编辑的技能索引
});
const fromValue = reactive({
sex: null,
education: '4',
salaryMin: 2000,
salaryMax: 2000,
area: 0,
jobTitleId: '',
workExperience: '1',
idCard: '',
name: '',
age: '',
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 addSkill = () => {
if (state.skills.length >= 3) {
$api.msg('最多只能添加3个技能');
return;
}
state.skills.push({ name: '', level: '' });
};
const removeSkill = (index) => {
state.skills.splice(index, 1);
};
const changeSkillName = (index) => {
state.currentEditingSkillIndex = index;
// 跳转到技能查询页面
uni.navigateTo({
url: `/pages/complete-info/skill-search?selected=${encodeURIComponent(JSON.stringify([]))}`
});
};
const changeSkillLevel = (index) => {
state.currentEditingSkillIndex = index;
const skillLevels = [
{ label: '初级', value: '1' },
{ label: '中级', value: '2' },
{ label: '高级', value: '3' }
];
openSelectPopup({
title: '技能等级',
maskClick: true,
data: [skillLevels],
success: (_, [value]) => {
if (state.currentEditingSkillIndex >= 0) {
state.skills[state.currentEditingSkillIndex].level = value.value;
state.currentEditingSkillIndex = -1;
}
},
});
};
const getSkillLevelText = (level) => {
const levelMap = {
'1': '初级',
'2': '中级',
'3': '高级'
};
return levelMap[level] || '';
};
// 技能选择回调函数
const handleSkillSelected = (skillName) => {
if (state.currentEditingSkillIndex >= 0 && skillName) {
state.skills[state.currentEditingSkillIndex].name = skillName;
state.currentEditingSkillIndex = -1;
}
};
// 监听页面显示,接收从技能查询页面返回的数据
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 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 = [];
state.skills.forEach(skill => {
if (skill.name && skill.level) {
experiencesList.push({
name: skill.name,
levels: skill.level
});
}
});
// 构建符合要求的请求数据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
/* 技能列表样式 */
.content-skills
margin-bottom: 52rpx
.skills-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 32rpx
.input-titile
font-weight: 400
font-size: 28rpx
color: #6A6A6A
.add-skill-btn
padding: 16rpx 24rpx
background: #256BFA
color: #FFFFFF
border-radius: 8rpx
font-size: 24rpx
font-weight: 500
&.disabled
background: #CCCCCC
color: #999999
.skills-list
.skill-item
background: #F8F9FA
border-radius: 12rpx
padding: 24rpx
margin-bottom: 24rpx
.skill-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 20rpx
.skill-number
font-size: 28rpx
font-weight: 500
color: #333333
.skill-actions
.action-btn
padding: 8rpx 16rpx
border-radius: 6rpx
font-size: 24rpx
&.delete-btn
background: #FF4757
color: #FFFFFF
.skill-fields
.skill-field
margin-bottom: 20rpx
&:last-child
margin-bottom: 0
.field-label
font-size: 24rpx
color: #6A6A6A
margin-bottom: 8rpx
.field-input
width: 100%
height: 72rpx
background: #FFFFFF
border: 2rpx solid #E8EAEE
border-radius: 8rpx
padding: 0 20rpx
font-size: 28rpx
color: #333333
position: relative
&.triangle::before
position: absolute
right: 20rpx
top: calc(50% - 2rpx)
content: ''
width: 4rpx
height: 14rpx
border-radius: 2rpx
background: #697279
transform: translate(0, -50%) rotate(-45deg)
&.triangle::after
position: absolute
right: 20rpx
top: 50%
content: ''
width: 4rpx
height: 14rpx
border-radius: 2rpx
background: #697279
transform: rotate(45deg)
.empty-skills
text-align: center
padding: 60rpx 0
.empty-text
font-size: 28rpx
color: #999999
</style>