feat: add contact management and various bug fixes
- Add contact API methods in athlete.js - Add contact list display in common-info.vue - Update add-contact.vue for contact creation - Create edit-contact page for contact editing - Fix event-register.vue with contact picker modal - Fix home.vue registration status display - Fix my-registration.vue cert modal display Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot]
parent
4eddc5a194
commit
13eb311575
@@ -98,22 +98,22 @@
|
||||
<view class="event-info-card">
|
||||
<view class="event-title">{{ eventInfo.title }}</view>
|
||||
<view class="divider"></view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">地点:</text>
|
||||
<text class="value">{{ eventInfo.location }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">比赛时间:</text>
|
||||
<text class="value">{{ eventInfo.matchTime }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">报名项目:</text>
|
||||
<text class="value">{{ eventInfo.projects }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">联系人:</text>
|
||||
<text class="value">{{ eventInfo.contact }}</text>
|
||||
<text class="edit-icon">📋</text>
|
||||
<text class="value" :class="{ placeholder: !selectedContact }">{{ selectedContact ? selectedContact.name + " " + selectedContact.phone : "请选择联系人" }}</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
<view class="info-hint">(注意是否用此号码接收信息)</view>
|
||||
<view class="info-item participants-item">
|
||||
@@ -151,21 +151,21 @@
|
||||
<view class="event-info-card">
|
||||
<view class="event-title">{{ eventInfo.title }}</view>
|
||||
<view class="divider"></view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">地点:</text>
|
||||
<text class="value">{{ eventInfo.location }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">比赛时间:</text>
|
||||
<text class="value">{{ eventInfo.matchTime }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">报名项目:</text>
|
||||
<text class="value">{{ eventInfo.projects }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">联系人:</text>
|
||||
<text class="value">{{ eventInfo.contact }}</text>
|
||||
<text class="value" :class="{ placeholder: !selectedContact }">{{ selectedContact ? selectedContact.name + " " + selectedContact.phone : "请选择联系人" }}</text>
|
||||
</view>
|
||||
|
||||
<template v-if="!isTeamProject">
|
||||
@@ -211,6 +211,32 @@
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人选择弹窗 -->
|
||||
<view class="contact-modal" v-if="showContactPicker" @click="showContactPicker = false">
|
||||
<view class="modal-content" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">选择联系人</text>
|
||||
<text class="close-icon" @click="showContactPicker = false">✕</text>
|
||||
</view>
|
||||
<view class="add-contact-btn" @click="goToAddContact">
|
||||
<text class="add-icon">⊕</text>
|
||||
<text>新增联系人</text>
|
||||
</view>
|
||||
<scroll-view class="modal-body contact-list" scroll-y>
|
||||
<view class="contact-item" v-for="(item, index) in contactList" :key="index" @click="selectContact(item)">
|
||||
<view class="contact-info">
|
||||
<view class="contact-name">{{ item.name }}</view>
|
||||
<view class="contact-phone">{{ item.phone }}</view>
|
||||
</view>
|
||||
<view class="contact-check" v-if="selectedContact && selectedContact.id === item.id">✓</view>
|
||||
</view>
|
||||
<view class="empty-state" v-if="contactList.length === 0">
|
||||
<text class="empty-text">暂无联系人,请先新增</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -240,6 +266,9 @@ export default {
|
||||
selectedPlayers: [],
|
||||
selectedTeams: [],
|
||||
showPlayerModal: false,
|
||||
showContactPicker: false,
|
||||
contactList: [],
|
||||
selectedContact: null,
|
||||
totalPrice: 0,
|
||||
registrationId: ''
|
||||
};
|
||||
@@ -290,6 +319,38 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Contact methods
|
||||
async loadContactList() {
|
||||
try {
|
||||
const res = await athleteAPI.getContactList({ current: 1, size: 100 })
|
||||
this.contactList = (res.records || []).map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
phone: item.phone,
|
||||
idCard: item.idCard
|
||||
}))
|
||||
// Auto select default contact if exists
|
||||
if (!this.selectedContact && this.contactList.length > 0) {
|
||||
const defaultContact = this.contactList.find(c => c.isDefault) || this.contactList[0]
|
||||
this.selectedContact = defaultContact
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载联系人列表失败:', err)
|
||||
}
|
||||
},
|
||||
|
||||
selectContact(contact) {
|
||||
this.selectedContact = contact
|
||||
this.showContactPicker = false
|
||||
},
|
||||
|
||||
goToAddContact() {
|
||||
this.showContactPicker = false
|
||||
uni.navigateTo({
|
||||
url: '/pages/add-contact/add-contact'
|
||||
})
|
||||
},
|
||||
|
||||
async loadEventDetail(id) {
|
||||
try {
|
||||
const res = await competitionAPI.getCompetitionDetail(id)
|
||||
@@ -487,6 +548,7 @@ export default {
|
||||
}
|
||||
|
||||
this.totalPrice = this.calculateTotalPrice()
|
||||
this.loadContactList()
|
||||
this.$nextTick(() => { this.currentStep = 2 })
|
||||
},
|
||||
|
||||
@@ -518,7 +580,7 @@ export default {
|
||||
projectIds: this.selectedProjects.map(p => String(p.id)),
|
||||
teamIds: selected.map(t => String(t.id)),
|
||||
athleteIds: [],
|
||||
contactPhone: this.eventInfo.contact || '',
|
||||
contactPhone: this.selectedContact ? this.selectedContact.phone : '',
|
||||
totalAmount: parseFloat(this.totalPrice) || 0
|
||||
}
|
||||
} else {
|
||||
@@ -532,7 +594,7 @@ export default {
|
||||
competitionId: String(this.eventId),
|
||||
projectIds: this.selectedProjects.map(p => String(p.id)),
|
||||
athleteIds: selected.map(p => String(p.id)),
|
||||
contactPhone: this.eventInfo.contact || '',
|
||||
contactPhone: this.selectedContact ? this.selectedContact.phone : '',
|
||||
totalAmount: parseFloat(this.totalPrice) || 0
|
||||
}
|
||||
}
|
||||
@@ -1014,6 +1076,84 @@ export default {
|
||||
color: #C93639;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* Contact Modal Styles */
|
||||
.contact-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.contact-modal .modal-content {
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.contact-modal .add-contact-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
color: #C93639;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.contact-modal .add-contact-btn .add-icon {
|
||||
margin-right: 10rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.contact-modal .contact-list {
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.contact-modal .contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.contact-modal .contact-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.contact-modal .contact-name {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.contact-modal .contact-phone {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.contact-modal .contact-check {
|
||||
color: #C93639;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.contact-item.clickable,
|
||||
.info-item.contact-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-item .placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
.empty-state {
|
||||
|
||||
Reference in New Issue
Block a user