This commit is contained in:
2025-12-12 17:29:38 +08:00
parent 7d9ac4c8ca
commit 7807f4b3e4
14 changed files with 2476 additions and 51 deletions
+448
View File
@@ -0,0 +1,448 @@
<template>
<view class="schedule-page">
<view class="header">
<text class="title">赛程编排管理</text>
</view>
<!-- 状态显示 -->
<view class="status-card">
<view class="status-item">
<text class="label">编排状态</text>
<text :class="['status-text', getStatusClass()]">{{ getStatusText() }}</text>
</view>
<view class="status-item">
<text class="label">分组数</text>
<text class="value">{{ scheduleData.totalGroups || 0 }}</text>
</view>
<view class="status-item">
<text class="label">参赛人数</text>
<text class="value">{{ scheduleData.totalParticipants || 0 }}</text>
</view>
<view class="status-item" v-if="scheduleData.lastAutoScheduleTime">
<text class="label">最后编排时间</text>
<text class="value">{{ scheduleData.lastAutoScheduleTime }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<!-- 触发自动编排 -->
<button
class="btn btn-primary"
@click="handleAutoArrange"
:disabled="loading || scheduleData.scheduleStatus === 2"
>
{{ loading ? '编排中...' : '自动编排' }}
</button>
<!-- 刷新编排结果 -->
<button
class="btn btn-default"
@click="loadScheduleResult"
:disabled="loading"
>
刷新结果
</button>
<!-- 保存并锁定 -->
<button
class="btn btn-success"
@click="handleSaveAndLock"
:disabled="loading || scheduleData.scheduleStatus === 2 || scheduleData.scheduleStatus === 0"
>
{{ scheduleData.scheduleStatus === 2 ? '已锁定' : '保存并锁定' }}
</button>
</view>
<!-- 编排结果列表 -->
<view class="schedule-list" v-if="scheduleData.scheduleGroups && scheduleData.scheduleGroups.length > 0">
<view class="list-title">编排结果</view>
<view
class="schedule-item"
v-for="group in scheduleData.scheduleGroups"
:key="group.groupId"
>
<view class="group-header">
<text class="group-name">{{ group.groupName }}</text>
<text class="participant-count">{{ group.participants.length }}</text>
</view>
<view class="group-info">
<text class="info-text">场地{{ group.venueName }}</text>
<text class="info-text">时间{{ group.scheduleDate }} {{ group.scheduleTime }}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else>
<text class="empty-text">暂无编排数据</text>
<text class="empty-hint">点击"自动编排"开始编排</text>
</view>
</view>
</template>
<script>
import scheduleAPI from '@/api/schedule.js'
export default {
data() {
return {
competitionId: null, // 赛事ID,从页面参数获取
loading: false,
scheduleData: {
scheduleStatus: 0, // 0-未编排, 1-已编排, 2-已锁定
totalGroups: 0,
totalParticipants: 0,
lastAutoScheduleTime: null,
scheduleGroups: []
}
}
},
onLoad(options) {
// 从页面参数获取赛事ID
if (options.competitionId) {
this.competitionId = parseInt(options.competitionId)
this.loadScheduleResult()
} else {
uni.showToast({
title: '缺少赛事ID',
icon: 'none'
})
}
},
methods: {
/**
* 加载赛程编排结果
*/
async loadScheduleResult() {
if (!this.competitionId) return
this.loading = true
try {
const result = await scheduleAPI.getScheduleResult(this.competitionId)
this.scheduleData = result
console.log('编排结果:', result)
} catch (error) {
console.error('加载编排结果失败:', error)
uni.showToast({
title: error.message || '加载失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
/**
* 触发自动编排
*/
async handleAutoArrange() {
if (!this.competitionId) return
// 确认提示
const [err, res] = await uni.showModal({
title: '确认编排',
content: '确定要执行自动编排吗?',
confirmText: '确定',
cancelText: '取消'
})
if (err || !res.confirm) return
this.loading = true
uni.showLoading({
title: '编排中...',
mask: true
})
try {
await scheduleAPI.triggerAutoArrange(this.competitionId)
uni.showToast({
title: '编排成功',
icon: 'success'
})
// 延迟1秒后刷新结果
setTimeout(() => {
this.loadScheduleResult()
}, 1000)
} catch (error) {
console.error('自动编排失败:', error)
uni.showToast({
title: error.message || '编排失败',
icon: 'none'
})
} finally {
this.loading = false
uni.hideLoading()
}
},
/**
* 保存并锁定编排
*/
async handleSaveAndLock() {
if (!this.competitionId) return
// 确认提示
const [err, res] = await uni.showModal({
title: '确认锁定',
content: '锁定后将无法再修改编排,确定要锁定吗?',
confirmText: '确定锁定',
cancelText: '取消'
})
if (err || !res.confirm) return
this.loading = true
uni.showLoading({
title: '保存中...',
mask: true
})
try {
await scheduleAPI.saveAndLockSchedule(this.competitionId)
uni.showToast({
title: '锁定成功',
icon: 'success'
})
// 刷新结果
setTimeout(() => {
this.loadScheduleResult()
}, 1000)
} catch (error) {
console.error('保存锁定失败:', error)
uni.showToast({
title: error.message || '锁定失败',
icon: 'none'
})
} finally {
this.loading = false
uni.hideLoading()
}
},
/**
* 获取状态文本
*/
getStatusText() {
const statusMap = {
0: '未编排',
1: '已编排',
2: '已锁定'
}
return statusMap[this.scheduleData.scheduleStatus] || '未知'
},
/**
* 获取状态样式类
*/
getStatusClass() {
const classMap = {
0: 'status-pending',
1: 'status-draft',
2: 'status-locked'
}
return classMap[this.scheduleData.scheduleStatus] || ''
}
}
}
</script>
<style lang="scss" scoped>
.schedule-page {
min-height: 100vh;
background: #f5f5f5;
padding: 20rpx;
}
.header {
background: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 16rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.status-card {
background: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 16rpx;
}
.status-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
}
.label {
font-size: 28rpx;
color: #666;
min-width: 180rpx;
}
.value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.status-text {
font-size: 28rpx;
font-weight: bold;
padding: 8rpx 20rpx;
border-radius: 8rpx;
&.status-pending {
color: #999;
background: #f0f0f0;
}
&.status-draft {
color: #1890ff;
background: #e6f7ff;
}
&.status-locked {
color: #52c41a;
background: #f6ffed;
}
}
.action-buttons {
display: flex;
gap: 20rpx;
margin-bottom: 20rpx;
}
.btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 12rpx;
font-size: 28rpx;
border: none;
&.btn-primary {
background: #1890ff;
color: #fff;
&:disabled {
background: #d9d9d9;
color: #999;
}
}
&.btn-default {
background: #fff;
color: #333;
border: 2rpx solid #d9d9d9;
&:disabled {
background: #f5f5f5;
color: #999;
}
}
&.btn-success {
background: #52c41a;
color: #fff;
&:disabled {
background: #d9d9d9;
color: #999;
}
}
}
.schedule-list {
background: #fff;
padding: 30rpx;
border-radius: 16rpx;
}
.list-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.schedule-item {
padding: 24rpx;
background: #f9f9f9;
border-radius: 12rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.group-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
}
.group-name {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.participant-count {
font-size: 24rpx;
color: #1890ff;
background: #e6f7ff;
padding: 4rpx 12rpx;
border-radius: 6rpx;
}
.group-info {
display: flex;
gap: 30rpx;
}
.info-text {
font-size: 26rpx;
color: #666;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
background: #fff;
border-radius: 16rpx;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-bottom: 16rpx;
}
.empty-hint {
font-size: 26rpx;
color: #ccc;
}
</style>