|
|
|
@ -110,10 +110,16 @@ |
|
|
|
<view class="section waiting-info" v-if="waitingStudents && waitingStudents.length > 0"> |
|
|
|
<view class="section-header"> |
|
|
|
<view class="section-title">等待位 ({{ waitingStudents.length }}人)</view> |
|
|
|
<view class="waiting-tip"> |
|
|
|
<text class="tip-text">点击卡片转为正式课学员</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="cards-grid"> |
|
|
|
<view class="student-card filled waiting-filled" v-for="(student, index) in waitingStudents" :key="index" |
|
|
|
@click="handleStudentClick(student, index)"> |
|
|
|
<!-- 转换提示图标 --> |
|
|
|
<view class="convert-icon">⚡</view> |
|
|
|
|
|
|
|
<!-- 续费提醒徽章 --> |
|
|
|
<view v-if="student.needsRenewal && !student.isTrialStudent" class="renewal-badge">待续费</view> |
|
|
|
|
|
|
|
@ -200,6 +206,30 @@ |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</fui-modal> |
|
|
|
|
|
|
|
<!-- 升级确认弹窗 --> |
|
|
|
<fui-modal :show="showUpgradeConfirm" title="升级确认" @cancel="cancelUpgrade" :buttons="[]" :zIndex="10000"> |
|
|
|
<view class="upgrade-confirm-modal" v-if="upgradeStudent"> |
|
|
|
<view class="confirm-content"> |
|
|
|
<view class="upgrade-icon">⚡</view> |
|
|
|
<view class="confirm-text"> |
|
|
|
是否将等待位学员 <text class="student-name-highlight">{{ upgradeStudent.name }}</text> 升级为正式学员? |
|
|
|
</view> |
|
|
|
<view class="confirm-tip"> |
|
|
|
升级后将占用一个正式位 |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="confirm-buttons"> |
|
|
|
<view class="confirm-btn cancel-btn" @click="cancelUpgrade"> |
|
|
|
<text>取消</text> |
|
|
|
</view> |
|
|
|
<view class="confirm-btn upgrade-btn" @click="confirmUpgrade"> |
|
|
|
<text>确定升级</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</fui-modal> |
|
|
|
</fui-modal> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -222,11 +252,11 @@ |
|
|
|
// 分离正式学员和等待位学员 |
|
|
|
formalStudents() { |
|
|
|
if (!this.scheduleInfo || !this.scheduleInfo.students) return []; |
|
|
|
return this.scheduleInfo.students.filter(student => student.course_type !== 3); |
|
|
|
return this.scheduleInfo.students.filter(student => student.schedule_type === 1 || student.schedule_type === null); |
|
|
|
}, |
|
|
|
waitingStudents() { |
|
|
|
if (!this.scheduleInfo || !this.scheduleInfo.students) return []; |
|
|
|
return this.scheduleInfo.students.filter(student => student.course_type === 3); |
|
|
|
return this.scheduleInfo.students.filter(student => student.schedule_type === 2); |
|
|
|
}, |
|
|
|
statusClass() { |
|
|
|
const statusMap = { |
|
|
|
@ -271,7 +301,10 @@ |
|
|
|
scheduleInfo: null, |
|
|
|
showAttendanceModal: false, |
|
|
|
selectedStudent: null, |
|
|
|
selectedStudentIndex: -1 |
|
|
|
selectedStudentIndex: -1, |
|
|
|
showUpgradeConfirm: false, |
|
|
|
upgradeStudent: null, |
|
|
|
upgradeStudentIndex: -1 |
|
|
|
} |
|
|
|
}, |
|
|
|
watch: { |
|
|
|
@ -400,9 +433,90 @@ |
|
|
|
|
|
|
|
// 学员点击处理 |
|
|
|
handleStudentClick(student, index) { |
|
|
|
this.selectedStudent = student; |
|
|
|
this.selectedStudentIndex = index; |
|
|
|
this.showAttendanceModal = true; |
|
|
|
console.log('点击了学员:', student) |
|
|
|
// 检查是否是等待位学员 |
|
|
|
if (student.schedule_type === 2) { |
|
|
|
// 等待位学员 - 询问是否转为正式课 |
|
|
|
this.handleWaitingStudentClick(student, index); |
|
|
|
} else { |
|
|
|
// 正式学员 - 进行签到/请假操作 |
|
|
|
this.selectedStudent = student; |
|
|
|
this.selectedStudentIndex = index; |
|
|
|
this.showAttendanceModal = true; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理等待位学员点击 |
|
|
|
handleWaitingStudentClick(student, index) { |
|
|
|
this.upgradeStudent = student; |
|
|
|
this.upgradeStudentIndex = index; |
|
|
|
this.showUpgradeConfirm = true; |
|
|
|
}, |
|
|
|
|
|
|
|
// 确认升级等待位学员 |
|
|
|
confirmUpgrade() { |
|
|
|
this.showUpgradeConfirm = false; |
|
|
|
if (this.upgradeStudent && this.upgradeStudentIndex >= 0) { |
|
|
|
this.convertWaitingToFormal(this.upgradeStudent, this.upgradeStudentIndex); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 取消升级等待位学员 |
|
|
|
cancelUpgrade() { |
|
|
|
this.showUpgradeConfirm = false; |
|
|
|
this.upgradeStudent = null; |
|
|
|
this.upgradeStudentIndex = -1; |
|
|
|
}, |
|
|
|
|
|
|
|
// 将等待位学员转为正式课学员 |
|
|
|
async convertWaitingToFormal(student, index) { |
|
|
|
try { |
|
|
|
uni.showLoading({ |
|
|
|
title: '升级中...' |
|
|
|
}); |
|
|
|
|
|
|
|
// 构建升级参数,参考class_arrangement_detail页面的逻辑 |
|
|
|
const upgradeData = { |
|
|
|
resources_id: student.resources_id || student.resource_id, |
|
|
|
schedule_id: this.scheduleId, |
|
|
|
student_id: student.student_id || student.id, |
|
|
|
from_schedule_type: 2, // 从等待位 |
|
|
|
to_schedule_type: 1, // 升级到正式位 |
|
|
|
position: this.formalStudents.length + 1, // 新的正式位位置 |
|
|
|
course_type: student.course_type === 3 ? 1 : student.course_type // 等待位课程类型改为正式课 |
|
|
|
}; |
|
|
|
|
|
|
|
// 调用升级接口 |
|
|
|
const response = await api.upgradeStudentSchedule(upgradeData); |
|
|
|
|
|
|
|
if (response.code === 1) { |
|
|
|
// 转换成功,更新学员类型 |
|
|
|
student.course_type = 1; // 改为正式学员 |
|
|
|
student.courseStatus = '正式课'; |
|
|
|
student.courseType = 'temporary'; // 临时课 |
|
|
|
|
|
|
|
// 重新获取课程详情以更新学员列表 |
|
|
|
await this.fetchScheduleDetail(); |
|
|
|
|
|
|
|
uni.showToast({ |
|
|
|
title: '升级成功', |
|
|
|
icon: 'success' |
|
|
|
}); |
|
|
|
} else { |
|
|
|
uni.showToast({ |
|
|
|
title: response.msg || '升级失败', |
|
|
|
icon: 'none' |
|
|
|
}); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('升级等待位学员失败:', error); |
|
|
|
uni.showToast({ |
|
|
|
title: '升级失败,请重试', |
|
|
|
icon: 'none' |
|
|
|
}); |
|
|
|
} finally { |
|
|
|
uni.hideLoading(); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 关闭点名弹窗 |
|
|
|
@ -648,6 +762,21 @@ |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.waiting-tip { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
padding: 8rpx 16rpx; |
|
|
|
background: rgba(139, 92, 246, 0.2); |
|
|
|
border-radius: 6rpx; |
|
|
|
border: 1px solid rgba(139, 92, 246, 0.3); |
|
|
|
} |
|
|
|
|
|
|
|
.tip-text { |
|
|
|
font-size: 22rpx; |
|
|
|
color: #8b5cf6; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.info-item { |
|
|
|
display: flex; |
|
|
|
margin-bottom: 16rpx; |
|
|
|
@ -889,6 +1018,39 @@ |
|
|
|
.student-card.waiting-filled { |
|
|
|
border-color: #8b5cf6; |
|
|
|
background: #2a2a3a; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
/* 转换提示图标 */ |
|
|
|
.convert-icon { |
|
|
|
position: absolute; |
|
|
|
top: 8rpx; |
|
|
|
left: 8rpx; |
|
|
|
width: 32rpx; |
|
|
|
height: 32rpx; |
|
|
|
background: linear-gradient(45deg, #8b5cf6, #a855f7); |
|
|
|
border-radius: 50%; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
font-size: 16rpx; |
|
|
|
z-index: 5; |
|
|
|
animation: pulse 2s infinite; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes pulse { |
|
|
|
0% { |
|
|
|
transform: scale(1); |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
50% { |
|
|
|
transform: scale(1.1); |
|
|
|
opacity: 0.8; |
|
|
|
} |
|
|
|
100% { |
|
|
|
transform: scale(1); |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.student-card:active { |
|
|
|
@ -1023,4 +1185,100 @@ |
|
|
|
border-radius: 4rpx; |
|
|
|
transition: width 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
/* 升级确认弹窗样式 */ |
|
|
|
.upgrade-confirm-modal { |
|
|
|
padding: 40rpx 30rpx; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-content { |
|
|
|
margin-bottom: 40rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.upgrade-icon { |
|
|
|
font-size: 60rpx; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
background: linear-gradient(45deg, #8b5cf6, #a855f7); |
|
|
|
background-clip: text; |
|
|
|
-webkit-background-clip: text; |
|
|
|
color: transparent; |
|
|
|
animation: glow 2s ease-in-out infinite alternate; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes glow { |
|
|
|
from { |
|
|
|
filter: drop-shadow(0 0 5rpx #8b5cf6); |
|
|
|
} |
|
|
|
to { |
|
|
|
filter: drop-shadow(0 0 15rpx #a855f7); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-text { |
|
|
|
font-size: 32rpx; |
|
|
|
color: #fff; |
|
|
|
line-height: 1.5; |
|
|
|
margin-bottom: 16rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.student-name-highlight { |
|
|
|
color: #8b5cf6; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-tip { |
|
|
|
font-size: 26rpx; |
|
|
|
color: #999; |
|
|
|
line-height: 1.4; |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-buttons { |
|
|
|
display: flex; |
|
|
|
gap: 20rpx; |
|
|
|
justify-content: center; |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-btn { |
|
|
|
flex: 1; |
|
|
|
padding: 24rpx 32rpx; |
|
|
|
border-radius: 12rpx; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
text-align: center; |
|
|
|
max-width: 200rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-btn text { |
|
|
|
font-size: 28rpx; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.cancel-btn { |
|
|
|
background: #4a4a4a; |
|
|
|
border: 1px solid #666; |
|
|
|
} |
|
|
|
|
|
|
|
.cancel-btn text { |
|
|
|
color: #ccc; |
|
|
|
} |
|
|
|
|
|
|
|
.cancel-btn:active { |
|
|
|
background: #5a5a5a; |
|
|
|
transform: scale(0.98); |
|
|
|
} |
|
|
|
|
|
|
|
.upgrade-btn { |
|
|
|
background: linear-gradient(45deg, #8b5cf6, #a855f7); |
|
|
|
border: 1px solid #8b5cf6; |
|
|
|
} |
|
|
|
|
|
|
|
.upgrade-btn text { |
|
|
|
color: #fff; |
|
|
|
} |
|
|
|
|
|
|
|
.upgrade-btn:active { |
|
|
|
background: linear-gradient(45deg, #7c3aed, #9333ea); |
|
|
|
transform: scale(0.98); |
|
|
|
} |
|
|
|
</style> |