948 lines
24 KiB
Vue
Raw Normal View History

2025-08-07 17:53:23 +08:00
<template>
<view class="container">
<view class="form-container">
<tn-form ref="form" :model="form" :errorType="errorType" :labelPosition="labelPosition"
:labelWidth="labelWidth" :labelAlign="labelAlign" :borderBottom="false">
<!-- 姓名 -->
<tn-form-item label="姓名" prop="name" class="form-item-vertical" required>
<tn-input v-model="form.name" type="text" placeholder="请输入姓名" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 性别 -->
<tn-form-item label="性别" prop="sex" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.sex" direction="row">
<tn-radio name="男" style="margin-right: 40rpx;"></tn-radio>
<tn-radio name="女"></tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 身份证号 -->
<tn-form-item label="身份证号" prop="code" class="form-item-vertical" required>
<tn-input v-model="form.code" type="text" placeholder="请输入身份证号" :border="false"
:placeholderStyle="placeholderStyle" maxlength="18" />
</tn-form-item>
<!-- 出生日期 -->
<tn-form-item label="出生日期" prop="userymd" class="form-item-vertical" required @click="showDatePicker">
<view class="date-picker-wrapper" @click="showDatePicker">
<tn-input @click="showDatePicker" v-model="form.userymd" type="text" placeholder="请选择出生日期"
:border="false" :placeholderStyle="placeholderStyle" :disabled="true" />
<view class="picker-icon">
<text class="tn-icon-calendar"></text>
</view>
</view>
</tn-form-item>
<!-- 联系电话 -->
<tn-form-item label="手机号码" prop="phone" class="form-item-vertical" required>
<tn-input v-model="form.phone" type="number" placeholder="请输入手机号码" :border="false"
2025-08-08 18:28:22 +08:00
:placeholderStyle="placeholderStyle" maxlength="11"/>
2025-08-07 17:53:23 +08:00
</tn-form-item>
<!-- 上传蓝底电子版照片 -->
<tn-form-item label="蓝底电子版照片" prop="oneimage" class="form-item-vertical" required>
<view class="upload-new-wrapper">
<view class="upload-status">
<view class="upload-status-text">
<text v-if="form.imageFile">文件选择成功</text>
<text v-if="form.imageFile" class="preview-link" @click="previewImage">点击预览</text>
<text v-if="!form.imageFile">请选择图片文件</text>
</view>
<text style="color: #E5E5E5;">|</text>
<view class="upload-btn" @click="chooseImage">
<text class="upload-btn-text">{{ form.imageFile ? '重新选择' : '选择文件' }}</text>
</view>
</view>
</view>
</tn-form-item>
<!-- 报考科目 -->
<tn-form-item label="报考科目" prop="kemu" class="form-item-vertical" required>
<view class="subject-tags">
<view v-for="subject in subjectOptions" :key="subject.value" class="subject-tag"
:class="{ 'subject-tag--selected': form.kemu.includes(subject.value) }"
@click="toggleSubject(subject.value)">
<text>{{ subject.label }}</text>
<view v-if="form.kemu.includes(subject.value)" class="subject-tag__check">
<text class="tn-icon-success"></text>
</view>
</view>
</view>
</tn-form-item>
<!-- 报考级别 -->
<tn-form-item label="报考级别" prop="jibie" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.jibie" direction="row">
<tn-radio v-for="level in levelOptions" :key="level.value" :name="level.value"
style="margin-right: 40rpx;">
{{ level.label }}
</tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 报考类型 -->
<tn-form-item label="报考类型" prop="type" class="form-item-vertical" required>
<view class="exam-type-tags">
<view v-for="type in examTypeOptions" :key="type.value" class="exam-type-tag"
:class="{ 'exam-type-tag--selected': form.type.includes(type.value) }"
@click="toggleExamType(type.value)">
<text>{{ type.label }}</text>
<view v-if="form.type.includes(type.value)" class="exam-type-tag__check">
<text class="tn-icon-success"></text>
</view>
</view>
</view>
</tn-form-item>
<!-- 毕业学校 -->
<tn-form-item label="毕业学校" prop="by_school" class="form-item-vertical" required>
<tn-input v-model="form.by_school" type="text" placeholder="请输入毕业学校" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 毕业专业 -->
<tn-form-item label="毕业专业" prop="by_zy" class="form-item-vertical" required>
<tn-input v-model="form.by_zy" type="text" placeholder="请输入毕业专业" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 最高学历 -->
<tn-form-item label="最高学历" prop="zgxl" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.zgxl" direction="row">
<tn-radio v-for="edu in educationOptions" :key="edu.value" :name="edu.value">{{ edu.label
}}</tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 工作单位 -->
<tn-form-item label="工作单位" prop="danwei" class="form-item-vertical" required>
<tn-input v-model="form.danwei" type="text" placeholder="请输入工作单位" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 累计从事本职业时间 -->
<tn-form-item label="累计从事本职业时间" prop="leijishijian" class="form-item-vertical" required>
<tn-input v-model="form.leijishijian" type="text" placeholder="请输入累计从事本职业时间" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 培训基地 -->
<tn-form-item label="培训基地" prop="pxjd" class="form-item-vertical" required>
<tn-input v-model="form.pxjd" type="text" placeholder="请输入培训基地" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
</tn-form>
<!-- 提交按钮 -->
<view class="submit-section">
<tn-button fontColor="#ffffff" type="primary" width="100%" height="88rpx" @click="submitForm"
:loading="submitting" backgroundColor="#1A73E8">
马上提交
</tn-button>
</view>
<!-- 用户协议同意 -->
<view class="agreement-section">
<view>
<tn-checkbox-group activeColor="#1A73E8" :size="43" v-model="agreementChecked">
<tn-checkbox name="agree" class="agreement-checkbox"></tn-checkbox>
</tn-checkbox-group>
</view>
<view class="agreement-content">
<text class="agreement-text">我已阅读并同意</text>
<text class="agreement-link" @click="openUserAgreement">用户服务协议</text>
<text class="agreement-text"></text>
<text class="agreement-link" @click="openPrivacyPolicy">隐私政策</text>
</view>
</view>
</view>
<!-- 日期选择器 -->
<tn-picker v-model="datePickerShow" mode="time" :params="dateParams" @confirm="onDateConfirm"
@cancel="datePickerShow = false"></tn-picker>
<login ref="login" v-on:succ="ajax()"></login>
</view>
</template>
<script>
export default {
data() {
return {
TimeShow: false,
// 表单数据
form: {
name: '', // 姓名
sex: '', // 性别
code: '', // 身份证号
userymd: '', // 出生日期
phone: '', // 联系电话
oneimage: '', // 电子照片URL用于显示
imageFile: null, // 电子照片文件(用于提交)
kemu: [], // 报考科目
jibie: '', // 报考级别
type: [], // 报考类型
by_school: '', // 毕业学校
by_zy: '', // 毕业专业
zgxl: '', // 最高学历
danwei: '', // 工作单位
leijishijian: '', // 累计从事本职业时间
pxjd: '' // 培训基地
},
// 表单配置
errorType: ['toast'],
labelPosition: 'top',
labelWidth: 120,
labelAlign: 'left',
placeholderStyle: 'color: #999; font-size: 28rpx;',
// 日期选择器
datePickerShow: false,
dateParams: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
// 提交状态
submitting: false,
// 用户协议同意状态
agreementChecked: [],
// 选项数据
subjectOptions: [
{ label: '游泳救生员', value: '游泳救生员' },
{ label: '游泳社会体育指导员', value: '游泳社会体育指导员' },
{ label: '健身教练', value: '健身教练' },
{ label: '水质管理员', value: '水质管理员' },
{ label: '潜水', value: '潜水' },
{ label: '滑雪', value: '滑雪' },
{ label: '少儿体适能', value: '少儿体适能' }
],
levelOptions: [
{ label: '初级(五级)', value: '初级(五级)' },
{ label: '中级(四级)', value: '中级(四级)' },
{ label: '高级(三级)', value: '高级(三级)' }
],
examTypeOptions: [
{ label: '正常', value: '正常' },
{ label: '补考理论', value: '补考理论' },
{ label: '补考实操', value: '补考实操' },
{ label: '补考双项', value: '补考双项' }
],
educationOptions: [
{ label: '博士', value: '博士' },
{ label: '硕士', value: '硕士' },
{ label: '大学', value: '大学' },
{ label: '大专', value: '大专' },
{ label: '高中、高职、中专', value: '高中、高职、中专' },
{ label: '初中', value: '初中' },
{ label: '小学', value: '小学' }
]
}
},
onLoad(){
//console.log(this.utils.apiUrlReturn());
},
methods: {
// 显示日期选择器
showDatePicker() {
this.datePickerShow = true
},
// 日期选择确认
onDateConfirm(e) {
this.form.userymd = e.year + '/' + e.month + '/' + e.day;
this.datePickerShow = false
},
// 选择图片
chooseImage() {
console.log(123);
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0]
// 保存文件路径用于后续提交
this.form.imageFile = tempFilePath
// 设置显示用的URL
this.form.oneimage = tempFilePath
uni.showToast({
title: '图片选择成功',
icon: 'success'
})
},
fail: (res) => {
console.log(res);
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
// 预览图片
previewImage() {
if (this.form.oneimage) {
uni.previewImage({
urls: [this.form.oneimage],
current: this.form.oneimage
})
}
},
// 提交表单
submitForm() {
// 检查是否同意用户协议
if (!this.agreementChecked.includes('agree')) {
uni.showToast({
title: '请先同意用户服务协议和隐私政策',
icon: 'none'
})
return
}
// 验证表单字段
if (!this.validateForm()) {
return
}
this.submitting = true
// 准备提交数据
const formData = {
name: this.form.name,
sex: this.form.sex,
code: this.form.code,
userymd: this.form.userymd,
phone: this.form.phone,
kemu: this.form.kemu.join(','), // 数组转字符串
jibie: this.form.jibie,
type: this.form.type.join(','), // 数组转字符串
by_school: this.form.by_school,
by_zy: this.form.by_zy,
zgxl: this.form.zgxl,
danwei: this.form.danwei,
leijishijian: this.form.leijishijian,
pxjd: this.form.pxjd
}
// 使用uni.uploadFile提交表单和文件
uni.uploadFile({
url: this.utils.apiUrlReturn() + '/addons/exam/gzinfo/add', // 替换为您的提交接口
filePath: this.form.imageFile,
name: 'oneimage', // 文件字段名
formData: formData, // 其他表单数据
header: {
'token': uni.getStorageSync('token')
},
success: (res) => {
this.submitting = false;
console.log(res);
const data = JSON.parse(res.data)
if(data.code===401){
uni.showToast({
title: '请登录后提交!',
icon: 'none'
})
this.$refs.login.modal = true;
return;
}
if (res.statusCode === 200 && data.code === 1) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
// 提交成功后清空表单
this.resetForm()
} else {
uni.showToast({
title: data.message || '提交失败',
icon: 'none'
})
}
},
fail: (error) => {
this.submitting = false
uni.showToast({
title: '提交失败',
icon: 'none'
})
console.error('提交错误:', error)
}
})
},
//判断表单字段
validateForm() {
// 判断姓名
if (!this.form.name || this.form.name.trim() === '') {
uni.showToast({
title: '请输入姓名',
icon: 'none'
})
return false
}
// 判断性别
if (!this.form.sex || this.form.sex === '') {
uni.showToast({
title: '请选择性别',
icon: 'none'
})
return false
}
// 判断身份证号
if (!this.form.code || this.form.code.trim() === '') {
uni.showToast({
title: '请输入身份证号',
icon: 'none'
})
return false
}
// 验证身份证号格式
const idCardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
if (!idCardReg.test(this.form.code)) {
uni.showToast({
title: '身份证号格式不正确',
icon: 'none'
})
return false
}
// 判断出生日期
if (!this.form.userymd || this.form.userymd === '') {
uni.showToast({
title: '请选择出生日期',
icon: 'none'
})
return false
}
// 判断联系电话
if (!this.form.phone || this.form.phone.trim() === '') {
uni.showToast({
title: '请输入联系电话',
icon: 'none'
})
return false
}
// 验证手机号格式
const phone = this.form.phone.trim()
// 检查是否为11位数字
if (!/^\d{11}$/.test(phone)) {
uni.showToast({
title: '手机号必须为11位数字',
icon: 'none'
})
return false
}
// 检查是否以1开头
if (!phone.startsWith('1')) {
uni.showToast({
title: '手机号必须以1开头',
icon: 'none'
})
return false
}
// 检查第二位数字是否为3-9
const secondDigit = phone.charAt(1)
if (!/[3-9]/.test(secondDigit)) {
uni.showToast({
title: '手机号第二位必须为3-9',
icon: 'none'
})
return false
}
// 详细的运营商号段验证
const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (!phoneReg.test(phone)) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
})
return false
}
// 判断电子照片
if (!this.form.imageFile) {
uni.showToast({
title: '请选择蓝底电子版照片',
icon: 'none'
})
return false
}
// 判断报考科目
if (!this.form.kemu || this.form.kemu.length === 0) {
uni.showToast({
title: '请选择报考科目',
icon: 'none'
})
return false
}
// 判断报考级别
if (!this.form.jibie || this.form.jibie === '') {
uni.showToast({
title: '请选择报考级别',
icon: 'none'
})
return false
}
// 判断报考类型
if (!this.form.type || this.form.type.length === 0) {
uni.showToast({
title: '请选择报考类型',
icon: 'none'
})
return false
}
// 判断毕业学校
if (!this.form.by_school || this.form.by_school.trim() === '') {
uni.showToast({
title: '请输入毕业学校',
icon: 'none'
})
return false
}
// 判断毕业专业
if (!this.form.by_zy || this.form.by_zy.trim() === '') {
uni.showToast({
title: '请输入毕业专业',
icon: 'none'
})
return false
}
// 判断最高学历
if (!this.form.zgxl || this.form.zgxl === '') {
uni.showToast({
title: '请选择最高学历',
icon: 'none'
})
return false
}
// 判断工作单位
if (!this.form.danwei || this.form.danwei.trim() === '') {
uni.showToast({
title: '请输入工作单位',
icon: 'none'
})
return false
}
// 判断累计从事本职业时间
if (!this.form.leijishijian || this.form.leijishijian.trim() === '') {
uni.showToast({
title: '请输入累计从事本职业时间',
icon: 'none'
})
return false
}
// 判断培训基地
if (!this.form.pxjd || this.form.pxjd.trim() === '') {
uni.showToast({
title: '请输入培训基地',
icon: 'none'
})
return false
}
// 所有验证通过
return true
},
// 打开用户服务协议
openUserAgreement() {
// 这里可以跳转到用户服务协议页面
2025-08-09 18:33:13 +08:00
// uni.showToast({
// title: '打开用户服务协议',
// icon: 'none'
// })
uni.navigateTo({
url:"/pages/index/news-detail?id=3"
2025-08-07 17:53:23 +08:00
})
},
// 打开隐私政策
openPrivacyPolicy() {
// 这里可以跳转到隐私政策页面
2025-08-09 18:33:13 +08:00
uni.navigateTo({
url:"/pages/index/news-detail?id=4"
2025-08-07 17:53:23 +08:00
})
},
// 切换科目选择
toggleSubject(value) {
const index = this.form.kemu.indexOf(value)
if (index > -1) {
// 如果已选中,则取消选择
this.form.kemu.splice(index, 1)
} else {
// 如果未选中,则添加选择
this.form.kemu.push(value)
}
},
// 切换报考类型选择
toggleExamType(value) {
const index = this.form.type.indexOf(value)
if (index > -1) {
// 如果已选中,则取消选择
this.form.type.splice(index, 1)
} else {
// 如果未选中,则添加选择
this.form.type.push(value)
}
},
// 实时验证手机号
validatePhone() {
const phone = this.form.phone.trim()
// 如果为空,不显示错误(在提交时再验证)
if (!phone) {
return
}
// 长度检查
if (phone.length !== 11) {
uni.showToast({
title: '手机号必须为11位',
icon: 'none',
duration: 1500
})
return
}
// 格式检查
const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (!phoneReg.test(phone)) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none',
duration: 1500
})
}
},
// 重置表单
resetForm() {
// 清空表单数据
this.form = {
name: '', // 姓名
sex: '', // 性别
code: '', // 身份证号
userymd: '', // 出生日期
phone: '', // 联系电话
oneimage: '', // 电子照片URL用于显示
imageFile: null, // 电子照片文件(用于提交)
kemu: [], // 报考科目
jibie: '', // 报考级别
type: [], // 报考类型
by_school: '', // 毕业学校
by_zy: '', // 毕业专业
zgxl: '', // 最高学历
danwei: '', // 工作单位
leijishijian: '', // 累计从事本职业时间
pxjd: '' // 培训基地
}
// 清空用户协议选择
this.agreementChecked = []
// 清空日期选择器状态
this.datePickerShow = false
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
background-color: #f8f8f8;
padding: 20rpx;
}
.form-container {
background-color: #ffffff;
border-radius: 20rpx;
padding: 0rpx 40rpx;
padding-bottom: 50rpx;
}
// 垂直布局的表单项
.form-item-vertical {
/deep/ .tn-form-item__body {
flex-direction: column;
align-items: flex-start;
}
/deep/ .tn-form-item__label {
margin-bottom: 20rpx;
font-weight: bold;
color: #333;
position: relative;
}
// 将必填*号放在文字左侧
/deep/ .tn-form-item--left__content--required {
position: absolute;
left: -20rpx;
top: 50%;
transform: translateY(-50%);
color: #ff0000 !important;
order: -1;
}
/deep/ .tn-form-item--left__content {
position: relative;
}
/deep/ .tn-form-item__content {
width: 100%;
}
// 去掉下划线
/deep/ .tn-form-item {
border-bottom: none !important;
}
/deep/ .tn-form-item::after {
display: none !important;
}
// 确保所有输入框宽度为100%
/deep/ .tn-input {
width: 640rpx;
background-color: #F7F7F7 !important;
border: none !important;
padding: 20rpx;
height: 100rpx;
}
/deep/ .tn-input__input {
width: 100%;
background-color: #F7F7F7 !important;
border: none !important;
padding: 20rpx;
height: 100rpx;
}
/deep/ .tn-input__wrap {
background-color: #F7F7F7 !important;
border: none !important;
}
}
// 日期选择器样式
.date-picker-wrapper {
position: relative;
width: 640rpx;
/deep/ .tn-input {
width: 640rpx;
background-color: #F7F7F7 !important;
border: none !important;
}
/deep/ .tn-input__input {
width: 100%;
background-color: #F7F7F7 !important;
border: none !important;
}
/deep/ .tn-input__wrap {
background-color: #F7F7F7 !important;
border: none !important;
}
.picker-icon {
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
color: #999;
font-size: 32rpx;
}
}
// 新的图片上传样式
.upload-new-wrapper {
width: 640rpx;
.upload-status {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 10rpx 20rpx 30rpx;
background-color: #F7F7F7;
border-radius: 0rpx;
height: 100rpx;
box-sizing: border-box;
.upload-status-text {
color: #666;
font-size: 28rpx;
flex: 1;
display: flex;
align-items: center;
.preview-link {
color: #1A73E8;
text-decoration: underline;
cursor: pointer;
}
}
.upload-btn {
padding: 8rpx 20rpx;
.upload-btn-text {
color: #333;
font-size: 24rpx;
}
}
}
.preview-section {
margin-top: 20rpx;
.preview-thumb {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
border: 1rpx solid #eee;
}
}
}
// 科目标签样式
.subject-tags {
display: flex;
flex-direction: column;
gap: 20rpx;
.subject-tag {
position: relative;
width: 640rpx;
padding: 10rpx 40rpx;
border-radius: 0rpx;
background-color: #f8f8f8;
color: #666;
font-size: 28rpx;
transition: all 0.3s ease;
text-align: left;
display: flex;
align-items: center;
justify-content: space-between;
&--selected {
border-color: #1A73E8;
background-color: #e8f0fe;
color: #1A73E8;
}
&__check {
width: 40rpx;
height: 40rpx;
background-color: #1A73E8;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24rpx;
flex-shrink: 0;
}
}
}
// 报考类型标签样式(与科目标签样式一致)
.exam-type-tags {
display: flex;
flex-direction: column;
gap: 20rpx;
.exam-type-tag {
position: relative;
width: 640rpx;
padding: 10rpx 40rpx;
background-color: #f8f8f8;
color: #666;
font-size: 28rpx;
transition: all 0.3s ease;
text-align: left;
display: flex;
align-items: center;
justify-content: space-between;
&--selected {
background-color: #e8f0fe;
color: #1A73E8;
}
&__check {
width: 40rpx;
height: 40rpx;
background-color: #1A73E8;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24rpx;
flex-shrink: 0;
}
}
}
// 用户协议区域
.agreement-section {
margin-top: 30rpx;
display: flex;
align-items: center;
}
.agreement-text {
color: #666;
font-size: 26rpx;
}
.agreement-link {
color: #1A73E8;
font-size: 26rpx;
}
// 提交按钮区域
.submit-section {
margin-top: 30rpx;
padding: 0 20rpx;
}
</style>