fix(add-player): 修复新增选手页面问题

- 移除一直显示的悬浮提示弹窗 (Issue #8)
- 添加登录状态检查
- 优化表单验证逻辑
- 改进错误提示显示方式
This commit is contained in:
DevOps
2025-12-30 17:26:46 +08:00
parent c6c9f9a5d1
commit b5a8c811aa

View File

@@ -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 {