Compare commits

...

2 Commits

Author SHA1 Message Date
DevOps
412069524e fix: 新增联系人后刷新列表
- 问题2: 在onShow生命周期中自动刷新联系人列表

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-08 16:08:39 +08:00
DevOps
53cc4600a8 重构项4: 小程序出场顺序页面改用真实数据
- 修改api/schedule.js添加getScheduleStatus和getLineup方法
- 重写event-lineup.vue,从硬编码mock数据改为调用后端API
- 添加编排未完成状态的友好提示

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-08 15:42:55 +08:00
3 changed files with 187 additions and 120 deletions

View File

@@ -91,6 +91,27 @@ export function saveDispatch(data) {
return request.post('/martial/schedule/save-dispatch', data) return request.post('/martial/schedule/save-dispatch', data)
} }
/**
* 获取编排状态(小程序用)
* @param {Number} competitionId - 赛事ID
*/
export function getScheduleStatus(competitionId) {
return request.get('/mini/schedule/status', {
params: { competitionId }
})
}
/**
* 获取出场顺序(小程序用)
* @param {Number} competitionId - 赛事ID
* @param {Number} projectId - 项目ID (可选)
*/
export function getLineup(competitionId, projectId) {
return request.get('/mini/schedule/lineup', {
params: { competitionId, projectId }
})
}
export default { export default {
getScheduleResult, getScheduleResult,
triggerAutoArrange, triggerAutoArrange,
@@ -99,5 +120,7 @@ export default {
moveScheduleGroup, moveScheduleGroup,
getDispatchData, getDispatchData,
adjustOrder, adjustOrder,
saveDispatch saveDispatch,
getScheduleStatus,
getLineup
} }

View File

@@ -1,135 +1,127 @@
<template> <template>
<view class="event-lineup-page"> <view class="event-lineup-page">
<!-- 组别选择 --> <view v-if="loading" class="loading-container">
<view class="group-tabs"> <text>加载中...</text>
<view
class="group-tab"
v-for="(group, index) in groups"
:key="index"
:class="{ active: currentGroup === index }"
@click="currentGroup = index"
>
{{ group }}
</view>
</view> </view>
<!-- 出场顺序列表 --> <view v-else-if="!isScheduleCompleted" class="not-ready">
<view class="lineup-list"> <view class="not-ready-icon">📋</view>
<view class="lineup-item" v-for="(item, index) in currentLineup" :key="index"> <text class="not-ready-text">赛程编排尚未完成</text>
<view class="lineup-order"> <text class="not-ready-hint">请等待赛事组织方完成编排后查看</text>
<view class="order-number">{{ item.order }}</view> </view>
<text class="order-text"></text>
</view> <template v-else>
<view class="lineup-info"> <!-- 组别选择 -->
<view class="lineup-name">{{ item.name }}</view> <view class="group-tabs">
<view class="lineup-detail"> <view
<text class="detail-item">{{ item.team }}</text> class="group-tab"
<text class="divider">|</text> v-for="(group, index) in groups"
<text class="detail-item">{{ item.time }}</text> :key="index"
</view> :class="{ active: currentGroupIndex === index }"
</view> @click="currentGroupIndex = index"
<view class="lineup-status" :class="item.status"> >
{{ item.statusText }} {{ group.groupName }}
</view> </view>
</view> </view>
</view>
<!-- 出场顺序列表 -->
<view class="lineup-list" v-if="currentGroup">
<view class="group-header">
<text class="group-venue">{{ currentGroup.venueName }}</text>
<text class="group-time">{{ currentGroup.timeSlot }}</text>
<text class="group-table">表号: {{ currentGroup.tableNo }}</text>
</view>
<view class="lineup-item" v-for="(item, index) in currentGroup.participants" :key="index">
<view class="lineup-order">
<view class="order-number">{{ item.order }}</view>
<text class="order-text"></text>
</view>
<view class="lineup-info">
<view class="lineup-name">{{ item.playerName }}</view>
<view class="lineup-detail">
<text class="detail-item">{{ item.organization }}</text>
</view>
</view>
<view class="lineup-status" :class="item.status">
{{ getStatusText(item.status) }}
</view>
</view>
<view v-if="!currentGroup.participants || currentGroup.participants.length === 0" class="empty-list">
<text>暂无参赛者信息</text>
</view>
</view>
</template>
</view> </view>
</template> </template>
<script> <script>
import { getScheduleStatus, getLineup } from '@/api/schedule.js'
export default { export default {
data() { data() {
return { return {
currentGroup: 0, eventId: '',
groups: ['男子A组', '男子B组', '女子A组'], loading: true,
lineups: { isScheduleCompleted: false,
0: [ currentGroupIndex: 0,
{ groups: []
order: 1, }
name: '张三',
team: '北京队',
time: '09:00',
status: 'finished',
statusText: '已完成'
},
{
order: 2,
name: '李四',
team: '上海队',
time: '09:15',
status: 'finished',
statusText: '已完成'
},
{
order: 3,
name: '王五',
team: '广东队',
time: '09:30',
status: 'ongoing',
statusText: '进行中'
},
{
order: 4,
name: '赵六',
team: '天津队',
time: '09:45',
status: 'waiting',
statusText: '待出场'
},
{
order: 5,
name: '刘七',
team: '江苏队',
time: '10:00',
status: 'waiting',
statusText: '待出场'
}
],
1: [
{
order: 1,
name: '孙八',
team: '浙江队',
time: '10:30',
status: 'waiting',
statusText: '待出场'
},
{
order: 2,
name: '周九',
team: '湖北队',
time: '10:45',
status: 'waiting',
statusText: '待出场'
}
],
2: [
{
order: 1,
name: '小红',
team: '四川队',
time: '14:00',
status: 'waiting',
statusText: '待出场'
},
{
order: 2,
name: '小芳',
team: '河南队',
time: '14:15',
status: 'waiting',
statusText: '待出场'
}
]
}
};
}, },
computed: { computed: {
currentLineup() { currentGroup() {
return this.lineups[this.currentGroup] || []; return this.groups[this.currentGroupIndex] || null
}
},
onLoad(options) {
if (options.eventId) {
this.eventId = options.eventId
this.checkScheduleStatus()
}
},
methods: {
async checkScheduleStatus() {
try {
const res = await getScheduleStatus(this.eventId)
if (res.data) {
this.isScheduleCompleted = res.data.isCompleted
if (this.isScheduleCompleted) {
await this.loadLineup()
}
}
} catch (error) {
console.error('检查编排状态失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
this.loading = false
}
},
async loadLineup() {
try {
const res = await getLineup(this.eventId)
if (res.data && res.data.groups) {
this.groups = res.data.groups
}
} catch (error) {
console.error('加载出场顺序失败:', error)
}
},
getStatusText(status) {
const map = {
'waiting': '待出场',
'ongoing': '进行中',
'finished': '已完成'
}
return map[status] || '待出场'
} }
} }
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -138,6 +130,38 @@ export default {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
.loading-container {
display: flex;
justify-content: center;
align-items: center;
height: 300rpx;
color: #666;
}
.not-ready {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 40rpx;
}
.not-ready-icon {
font-size: 80rpx;
margin-bottom: 30rpx;
}
.not-ready-text {
font-size: 32rpx;
color: #333;
margin-bottom: 15rpx;
}
.not-ready-hint {
font-size: 26rpx;
color: #999;
}
.group-tabs { .group-tabs {
background-color: #fff; background-color: #fff;
display: flex; display: flex;
@@ -166,6 +190,21 @@ export default {
padding: 0 30rpx 20rpx; padding: 0 30rpx 20rpx;
} }
.group-header {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx 30rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.group-venue, .group-time, .group-table {
font-size: 26rpx;
color: #666;
}
.lineup-item { .lineup-item {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
@@ -216,10 +255,6 @@ export default {
color: #666666; color: #666666;
} }
.divider {
margin: 0 10rpx;
}
.lineup-status { .lineup-status {
padding: 8rpx 20rpx; padding: 8rpx 20rpx;
border-radius: 8rpx; border-radius: 8rpx;
@@ -241,4 +276,11 @@ export default {
background-color: #F5F5F5; background-color: #F5F5F5;
color: #999999; color: #999999;
} }
.empty-list {
text-align: center;
padding: 60rpx;
color: #999;
font-size: 28rpx;
}
</style> </style>

View File

@@ -310,6 +310,8 @@ export default {
} }
}, },
onShow() { onShow() {
// Refresh contact list when returning from add-contact page
this.loadContactList()
if (this.currentStep === 1) { if (this.currentStep === 1) {
if (this.isTeamProject) { if (this.isTeamProject) {
this.loadTeamList() this.loadTeamList()