Files
martial-mini/pages/edit-player/edit-player.vue
2025-12-12 01:44:41 +08:00

434 lines
9.6 KiB
Vue
Raw Permalink 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="edit-player-page">
<!-- 表单 -->
<view class="form-container">
<view class="form-item" @click="showIdTypePicker = true">
<view class="form-label">证件类型</view>
<view class="form-value">
<text>{{ formData.idType }}</text>
<text class="arrow"></text>
</view>
</view>
<view class="form-item">
<view class="form-label">姓名</view>
<view class="form-value">
<input
class="form-input"
v-model="formData.name"
placeholder="请输入姓名"
/>
</view>
</view>
<view class="form-item">
<view class="form-label">证件号码</view>
<view class="form-value">
<input
class="form-input"
v-model="formData.idCard"
placeholder="请输入身份证号码"
/>
</view>
</view>
<view class="form-item">
<view class="form-label">队伍</view>
<view class="form-value">
<input
class="form-input"
v-model="formData.team"
placeholder="请输入队伍名称"
/>
</view>
</view>
<view class="form-item">
<view class="form-label">所属单位</view>
<view class="form-value">
<input
class="form-input"
v-model="formData.organization"
placeholder="请输入所属单位"
/>
</view>
</view>
<view class="form-item">
<view class="form-label">联系电话</view>
<view class="form-value">
<input
class="form-input"
v-model="formData.phone"
type="number"
placeholder="请输入联系电话"
/>
</view>
</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>
</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>
</view>
</template>
<script>
import athleteAPI from '@/api/athlete.js'
export default {
data() {
return {
playerId: '',
formData: {
idType: '身份证',
name: '',
idCard: '',
team: '',
organization: '',
phone: ''
},
errors: [],
showHint: false,
showToast: false,
toastMessage: '',
showIdTypePicker: false
};
},
computed: {
isFormValid() {
return (
this.formData.name &&
this.formData.idCard &&
this.formData.team &&
this.formData.organization &&
this.formData.phone &&
this.validateIdCard(this.formData.idCard) &&
this.validatePhone(this.formData.phone)
);
}
},
watch: {
'formData.name'(val) {
this.validateForm();
},
'formData.idCard'(val) {
this.validateForm();
},
'formData.team'(val) {
this.validateForm();
},
'formData.organization'(val) {
this.validateForm();
},
'formData.phone'(val) {
this.validateForm();
}
},
onLoad(options) {
if (options.id) {
this.playerId = options.id
this.loadPlayerData(options.id);
}
},
methods: {
/**
* 加载选手数据
*/
async loadPlayerData(id) {
try {
const res = await athleteAPI.getAthleteDetail(id)
// 回显数据(使用后端实体类的字段名)
this.formData = {
idType: res.idCardType === 1 ? '身份证' : '其他',
name: res.playerName || '',
idCard: res.idCard || '',
team: res.teamName || '',
organization: res.organization || '',
phone: res.contactPhone || ''
}
} catch (err) {
console.error('加载选手数据失败:', err)
uni.showToast({
title: '加载失败',
icon: 'none'
})
}
},
validateIdCard(idCard) {
// 身份证号验证18位最后一位可以是数字或字母X
return /^\d{17}[\dXx]$/.test(idCard);
},
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;
this.errors.push({
label: '有空文本时弹出:',
message: '按钮置灰'
});
}
if (this.formData.idCard && !this.validateIdCard(this.formData.idCard)) {
this.errors.push({
label: '身份证不足18位',
message: '按钮置灰'
});
}
if (this.formData.phone && !this.validatePhone(this.formData.phone)) {
this.errors.push({
label: '手机号格式不正确:',
message: '按钮置灰'
});
}
},
/**
* 从身份证号中提取信息
*/
extractInfoFromIdCard(idCard) {
if (!idCard || idCard.length !== 18) {
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
}
},
async handleSave() {
if (!this.isFormValid) {
return;
}
try {
// 从身份证号中提取信息
const info = this.extractInfoFromIdCard(this.formData.idCard)
// 调用API更新选手信息使用后端实体类的字段名
await athleteAPI.submitAthlete({
id: this.playerId,
playerName: this.formData.name,
idCard: this.formData.idCard,
teamName: this.formData.team,
organization: this.formData.organization,
contactPhone: this.formData.phone,
idCardType: 1, // 身份证类型固定为1
gender: info.gender,
age: info.age,
birthDate: info.birthDate
})
// 保存成功
uni.showToast({
title: '保存成功',
icon: 'success'
})
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (err) {
console.error('保存选手失败:', err)
// 显示错误提示
this.toastMessage = '保存失败,请重试'
this.showToast = true
setTimeout(() => {
this.showToast = false
}, 2000)
}
}
}
};
</script>
<style lang="scss" scoped>
.edit-player-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 200rpx;
}
.form-container {
background-color: #fff;
margin: 30rpx;
border-radius: 16rpx;
overflow: hidden;
}
.form-item {
display: flex;
align-items: center;
padding: 35rpx 30rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.form-item:last-child {
border-bottom: none;
}
.form-label {
width: 180rpx;
font-size: 30rpx;
color: #333333;
}
.form-value {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
}
.form-input {
flex: 1;
font-size: 30rpx;
color: #333333;
}
.arrow {
font-size: 40rpx;
color: #cccccc;
margin-left: 10rpx;
}
.error-hints {
margin: 30rpx;
padding: 30rpx;
background-color: #fff;
border-radius: 16rpx;
}
.error-item {
margin-bottom: 15rpx;
}
.error-label {
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 {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 30rpx;
background-color: #f5f5f5;
}
.btn {
width: 100%;
text-align: center;
padding: 30rpx;
border-radius: 12rpx;
font-size: 32rpx;
font-weight: bold;
}
.save-btn {
background-color: #C93639;
color: #fff;
}
.save-btn.disabled {
background-color: rgba(201, 54, 57, 0.5);
}
</style>