2025-08-07 17:53:23 +08:00

954 lines
24 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>
<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"
:placeholderStyle="placeholderStyle" maxlength="11" @blur="validatePhone" />
</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() {
// 这里可以跳转到用户服务协议页面
uni.showToast({
title: '打开用户服务协议',
icon: 'none'
})
},
// 打开隐私政策
openPrivacyPolicy() {
// 这里可以跳转到隐私政策页面
uni.showToast({
title: '打开隐私政策',
icon: 'none'
})
},
// 切换科目选择
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
uni.showToast({
title: '表单已重置',
icon: 'success',
duration: 1500
})
}
}
}
</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>