fix(add-player): 修复新增选手页面问题
- 移除一直显示的悬浮提示弹窗 (Issue #8) - 添加登录状态检查 - 优化表单验证逻辑 - 改进错误提示显示方式
This commit is contained in:
@@ -72,29 +72,16 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view class="error-hints" v-if="errors.length > 0">
|
||||
<view class="error-item" v-for="(error, index) in errors" :key="index">
|
||||
<text class="error-label">{{ error.label }}</text>
|
||||
<text class="error-msg">{{ error.message }}</text>
|
||||
<!-- 错误提示 - 只在有具体错误时显示 -->
|
||||
<view class="error-hints" v-if="validationErrors.length > 0">
|
||||
<view class="error-item" v-for="(error, index) in validationErrors" :key="index">
|
||||
<text class="error-text">{{ error }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<view class="hint-message" v-if="showHint">
|
||||
<text class="hint-icon">ℹ</text>
|
||||
<text class="hint-text">请完善信息</text>
|
||||
</view>
|
||||
|
||||
<!-- Toast提示 -->
|
||||
<view class="toast-message" v-if="showToast">
|
||||
<text class="toast-text">{{ toastMessage }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn save-btn disabled" v-if="!isFormValid">保存</view>
|
||||
<view class="btn save-btn" v-else @click="handleSave">保存</view>
|
||||
<view class="btn save-btn" :class="{ disabled: !isFormValid }" @click="handleSave">保存</view>
|
||||
</view>
|
||||
|
||||
<!-- 证件类型选择器 -->
|
||||
@@ -114,6 +101,7 @@
|
||||
|
||||
<script>
|
||||
import athleteAPI from '@/api/athlete.js'
|
||||
import { getUserInfo, getToken } from '@/utils/auth.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -128,25 +116,17 @@ export default {
|
||||
},
|
||||
competitionId: '',
|
||||
projectIds: [],
|
||||
errors: [],
|
||||
showHint: false,
|
||||
showToast: false,
|
||||
toastMessage: '',
|
||||
validationErrors: [],
|
||||
showIdTypePicker: false
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
// 接收赛事ID和项目ID
|
||||
if (options.competitionId) {
|
||||
this.competitionId = options.competitionId
|
||||
}
|
||||
if (options.projectIds) {
|
||||
this.projectIds = options.projectIds.split(',')
|
||||
}
|
||||
console.log('新增选手页面接收参数:', {
|
||||
competitionId: this.competitionId,
|
||||
projectIds: this.projectIds
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
isFormValid() {
|
||||
@@ -162,51 +142,28 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'formData.name'(val) {
|
||||
this.validateForm();
|
||||
},
|
||||
'formData.idCard'(val) {
|
||||
this.validateForm();
|
||||
},
|
||||
'formData.team'(val) {
|
||||
this.validateForm();
|
||||
},
|
||||
'formData.organization'(val) {
|
||||
this.validateForm();
|
||||
this.updateValidationErrors();
|
||||
},
|
||||
'formData.phone'(val) {
|
||||
this.validateForm();
|
||||
this.updateValidationErrors();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateIdCard(idCard) {
|
||||
// 身份证号验证:18位,最后一位可以是数字或字母X
|
||||
if (!/^\d{17}[\dXx]$/.test(idCard)) {
|
||||
return false;
|
||||
}
|
||||
if (!idCard) return false;
|
||||
if (!/^\d{17}[\dXx]$/.test(idCard)) return false;
|
||||
|
||||
// 验证日期部分是否有效
|
||||
const year = parseInt(idCard.substring(6, 10))
|
||||
const month = parseInt(idCard.substring(10, 12))
|
||||
const day = parseInt(idCard.substring(12, 14))
|
||||
|
||||
// 检查月份是否有效 (1-12)
|
||||
if (month < 1 || month > 12) {
|
||||
return false;
|
||||
}
|
||||
if (month < 1 || month > 12) return false;
|
||||
if (day < 1 || day > 31) return false;
|
||||
|
||||
// 检查日期是否有效 (1-31)
|
||||
if (day < 1 || day > 31) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查年份是否合理 (1900-当前年份)
|
||||
const currentYear = new Date().getFullYear()
|
||||
if (year < 1900 || year > currentYear) {
|
||||
return false;
|
||||
}
|
||||
if (year < 1900 || year > currentYear) return false;
|
||||
|
||||
// 进一步验证日期是否真实存在
|
||||
const date = new Date(year, month - 1, day)
|
||||
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
||||
return false;
|
||||
@@ -215,131 +172,106 @@ export default {
|
||||
return true;
|
||||
},
|
||||
validatePhone(phone) {
|
||||
// 手机号验证:11位数字
|
||||
return /^1[3-9]\d{9}$/.test(phone);
|
||||
},
|
||||
validateForm() {
|
||||
this.errors = [];
|
||||
this.showHint = false;
|
||||
|
||||
if (!this.formData.name || !this.formData.idCard || !this.formData.team || !this.formData.organization || !this.formData.phone) {
|
||||
this.showHint = true;
|
||||
if (!this.formData.name || !this.formData.idCard || !this.formData.team || !this.formData.organization || !this.formData.phone) {
|
||||
this.errors.push({
|
||||
label: '有空文本时弹出:',
|
||||
message: '按钮置灰'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateValidationErrors() {
|
||||
this.validationErrors = [];
|
||||
|
||||
if (this.formData.idCard && !this.validateIdCard(this.formData.idCard)) {
|
||||
this.errors.push({
|
||||
label: '身份证不足18位:',
|
||||
message: '按钮置灰'
|
||||
});
|
||||
this.errors.push({
|
||||
label: '输入不合法:',
|
||||
message: '按钮置灰'
|
||||
});
|
||||
this.validationErrors.push('身份证号码格式不正确');
|
||||
}
|
||||
|
||||
|
||||
if (this.formData.phone && !this.validatePhone(this.formData.phone)) {
|
||||
this.errors.push({
|
||||
label: '手机号格式不正确:',
|
||||
message: '按钮置灰'
|
||||
});
|
||||
this.validationErrors.push('手机号格式不正确');
|
||||
}
|
||||
},
|
||||
handleIdTypeChange(e) {
|
||||
this.formData.idType = '身份证';
|
||||
this.showIdTypePicker = false;
|
||||
},
|
||||
/**
|
||||
* 从身份证号中提取信息
|
||||
*/
|
||||
extractInfoFromIdCard(idCard) {
|
||||
if (!idCard || idCard.length !== 18) {
|
||||
return {
|
||||
gender: null,
|
||||
age: null,
|
||||
birthDate: null
|
||||
}
|
||||
return { gender: null, age: null, birthDate: null }
|
||||
}
|
||||
|
||||
// 提取出生日期
|
||||
const year = idCard.substring(6, 10)
|
||||
const month = idCard.substring(10, 12)
|
||||
const day = idCard.substring(12, 14)
|
||||
const birthDate = `${year}-${month}-${day}`
|
||||
|
||||
// 计算年龄
|
||||
const birthYear = parseInt(year)
|
||||
const currentYear = new Date().getFullYear()
|
||||
const age = currentYear - birthYear
|
||||
|
||||
// 提取性别(倒数第二位,奇数为男,偶数为女)
|
||||
const genderCode = parseInt(idCard.substring(16, 17))
|
||||
const gender = genderCode % 2 === 1 ? 1 : 2
|
||||
|
||||
return {
|
||||
gender,
|
||||
age,
|
||||
birthDate
|
||||
}
|
||||
return { gender, age, birthDate }
|
||||
},
|
||||
|
||||
async handleSave() {
|
||||
if (!this.isFormValid) {
|
||||
uni.showToast({
|
||||
title: '请完善信息',
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
// Check login status
|
||||
const token = getToken()
|
||||
if (!token) {
|
||||
uni.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
}, 1500)
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 从身份证号中提取信息
|
||||
const info = this.extractInfoFromIdCard(this.formData.idCard)
|
||||
|
||||
// 调用API保存选手信息(使用后端实体类的字段名)
|
||||
const submitData = {
|
||||
playerName: this.formData.name,
|
||||
idCard: this.formData.idCard,
|
||||
teamName: this.formData.team,
|
||||
organization: this.formData.organization,
|
||||
contactPhone: this.formData.phone,
|
||||
idCardType: 1, // 身份证类型固定为1
|
||||
idCardType: 1,
|
||||
gender: info.gender,
|
||||
age: info.age,
|
||||
birthDate: info.birthDate
|
||||
}
|
||||
|
||||
// 如果有赛事ID和项目ID,一起提交
|
||||
if (this.competitionId) {
|
||||
submitData.competitionId = this.competitionId
|
||||
}
|
||||
if (this.projectIds && this.projectIds.length > 0) {
|
||||
// 如果有多个项目,取第一个项目ID
|
||||
submitData.projectId = this.projectIds[0]
|
||||
}
|
||||
|
||||
console.log('提交选手数据:', submitData)
|
||||
await athleteAPI.submitAthlete(submitData)
|
||||
|
||||
// 保存成功
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 延迟返回上一页
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} catch (err) {
|
||||
console.error('保存选手失败:', err)
|
||||
// 显示错误提示
|
||||
this.toastMessage = '保存失败,请重试'
|
||||
this.showToast = true
|
||||
setTimeout(() => {
|
||||
this.showToast = false
|
||||
}, 2000)
|
||||
uni.showToast({
|
||||
title: err.message || '保存失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,64 +333,23 @@ export default {
|
||||
}
|
||||
|
||||
.error-hints {
|
||||
margin: 30rpx;
|
||||
padding: 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin: 0 30rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #fff3f3;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.error-item {
|
||||
margin-bottom: 15rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.error-label {
|
||||
.error-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 26rpx;
|
||||
color: #C93639;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
font-size: 26rpx;
|
||||
color: #C93639;
|
||||
}
|
||||
|
||||
.hint-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 30rpx 50rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15rpx;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.hint-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 30rpx 50rpx;
|
||||
border-radius: 16rpx;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toast-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.btn-wrapper {
|
||||
|
||||
Reference in New Issue
Block a user