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:
DevOps
2026-01-05 15:12:04 +08:00
co-authored by factory-droid[bot]
parent 4eddc5a194
commit 13eb311575
8 changed files with 720 additions and 489 deletions
+96 -63
View File
@@ -59,8 +59,31 @@
<text class="empty-text">暂无集体信息</text>
</view>
<!-- 联系人Tab内容 (Tab 2) -->
<view class="empty-state" v-if="currentTab === 2">
<!-- 联系人列表 (Tab 2) -->
<view class="player-list" v-if="currentTab === 2 && contactList.length > 0">
<view class="player-item" v-for="(item, index) in contactList" :key="index">
<view class="player-info">
<view class="player-name">
{{ item.name }}
<text class="default-tag" v-if="item.isDefault">默认</text>
</view>
<view class="player-id">手机{{ item.phone }}</view>
</view>
<view class="player-actions">
<view class="action-btn edit-btn" @click.stop="handleEditContact(item)">
<image class="action-icon" src="/static/images/编辑@3x.png" mode="aspectFit"></image>
<text>编辑</text>
</view>
<view class="action-btn delete-btn" @click.stop="handleDelete(item, 'contact')">
<image class="action-icon" src="/static/images/删除@3x.png" mode="aspectFit"></image>
<text>删除</text>
</view>
</view>
</view>
</view>
<!-- 联系人空状态 -->
<view class="empty-state" v-if="currentTab === 2 && contactList.length === 0">
<text class="empty-text">暂无联系人信息</text>
</view>
@@ -98,6 +121,7 @@ export default {
currentTab: 0,
playerList: [],
teamList: [],
contactList: [],
showDeleteModal: false,
showSuccessToast: false,
currentItem: null,
@@ -111,31 +135,31 @@ export default {
return '新增联系人'
},
deleteModalTitle() {
return this.deleteType === 'team' ? '删除集体' : '删除选手'
if (this.deleteType === 'team') return '删除集体'
if (this.deleteType === 'contact') return '删除联系人'
return '删除选手'
},
deleteModalContent() {
return this.deleteType === 'team' ? '确定要删除该集体吗?' : '确定要删除该选手吗?'
if (this.deleteType === 'team') return '确定要删除该集体吗?'
if (this.deleteType === 'contact') return '确定要删除该联系人吗?'
return '确定要删除该选手吗?'
}
},
onLoad() {
this.loadPlayerList()
this.loadTeamList()
this.loadContactList()
},
onShow() {
this.loadPlayerList()
this.loadTeamList()
this.loadContactList()
},
methods: {
/**
* Load player list
*/
async loadPlayerList() {
try {
const userInfo = getUserInfo()
if (!userInfo || !userInfo.userId) {
console.error('未获取到用户信息')
return
}
if (!userInfo || !userInfo.userId) return
const res = await athleteAPI.getAthleteList({
current: 1,
@@ -143,13 +167,7 @@ export default {
createUser: userInfo.userId
})
let list = []
if (res.records) {
list = res.records
} else if (Array.isArray(res)) {
list = res
}
let list = res.records || (Array.isArray(res) ? res : [])
this.playerList = list.map(item => ({
id: item.id,
name: item.name || item.playerName,
@@ -163,17 +181,11 @@ export default {
}
},
/**
* Load team list
*/
async loadTeamList() {
try {
const userInfo = getUserInfo()
if (!userInfo || !userInfo.userId) {
return
}
if (!userInfo || !userInfo.userId) return
// Try to load team list from API
if (athleteAPI.getTeamList) {
const res = await athleteAPI.getTeamList({
current: 1,
@@ -181,13 +193,7 @@ export default {
createUser: userInfo.userId
})
let list = []
if (res.records) {
list = res.records
} else if (Array.isArray(res)) {
list = res
}
let list = res.records || (Array.isArray(res) ? res : [])
this.teamList = list.map(item => ({
id: item.id,
name: item.name || item.teamName,
@@ -200,33 +206,55 @@ export default {
}
},
async loadContactList() {
try {
const userInfo = getUserInfo()
if (!userInfo || !userInfo.userId) return
if (athleteAPI.getContactList) {
const res = await athleteAPI.getContactList({
current: 1,
size: 100,
createUser: userInfo.userId
})
let list = res.records || (Array.isArray(res) ? res : [])
this.contactList = list.map(item => ({
id: item.id,
name: item.name,
phone: item.phone,
idCard: item.idCard,
email: item.email,
address: item.address,
isDefault: item.isDefault
}))
}
} catch (err) {
console.error('加载联系人列表失败:', err)
this.contactList = []
}
},
handleTabChange(index) {
this.currentTab = index;
},
handleAdd() {
if (this.currentTab === 0) {
uni.navigateTo({
url: '/pages/add-player/add-player'
});
uni.navigateTo({ url: '/pages/add-player/add-player' });
} else if (this.currentTab === 1) {
uni.navigateTo({
url: '/pages/add-team/add-team'
});
uni.navigateTo({ url: '/pages/add-team/add-team' });
} else if (this.currentTab === 2) {
uni.navigateTo({
url: '/pages/add-contact/add-contact'
});
uni.navigateTo({ url: '/pages/add-contact/add-contact' });
}
},
handleEdit(item) {
uni.navigateTo({
url: '/pages/edit-player/edit-player?id=' + item.id
});
uni.navigateTo({ url: '/pages/edit-player/edit-player?id=' + item.id });
},
handleEditTeam(item) {
uni.navigateTo({
url: '/pages/edit-team/edit-team?id=' + item.id
});
uni.navigateTo({ url: '/pages/edit-team/edit-team?id=' + item.id });
},
handleEditContact(item) {
uni.navigateTo({ url: '/pages/edit-contact/edit-contact?id=' + item.id });
},
handleDelete(item, type) {
this.currentItem = item;
@@ -242,27 +270,24 @@ export default {
await athleteAPI.removeTeam(this.currentItem.id)
}
const index = this.teamList.findIndex(item => item.id === this.currentItem.id);
if (index > -1) {
this.teamList.splice(index, 1);
if (index > -1) this.teamList.splice(index, 1);
} else if (this.deleteType === 'contact') {
if (athleteAPI.removeContact) {
await athleteAPI.removeContact(this.currentItem.id)
}
const index = this.contactList.findIndex(item => item.id === this.currentItem.id);
if (index > -1) this.contactList.splice(index, 1);
} else {
await athleteAPI.removeAthlete(this.currentItem.id)
const index = this.playerList.findIndex(item => item.id === this.currentItem.id);
if (index > -1) {
this.playerList.splice(index, 1);
}
if (index > -1) this.playerList.splice(index, 1);
}
this.showSuccessToast = true;
setTimeout(() => {
this.showSuccessToast = false;
}, 2000);
setTimeout(() => { this.showSuccessToast = false; }, 2000);
} catch (err) {
console.error('删除失败:', err)
uni.showToast({
title: '删除失败',
icon: 'none'
})
uni.showToast({ title: '删除失败', icon: 'none' })
}
}
}
@@ -315,6 +340,18 @@ export default {
font-weight: bold;
color: #333333;
margin-bottom: 10rpx;
display: flex;
align-items: center;
gap: 10rpx;
}
.default-tag {
font-size: 22rpx;
color: #fff;
background-color: #C93639;
padding: 4rpx 12rpx;
border-radius: 6rpx;
font-weight: normal;
}
.player-id {
@@ -348,10 +385,6 @@ export default {
border-color: #C93639;
}
.icon {
font-size: 28rpx;
}
.action-icon {
width: 28rpx;
height: 28rpx;