智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

461 lines
12 KiB

<template>
<view class="container safe-area">
<view class="search-bar" @click="showSearch = true">
<uni-icons type="search" size="22" color="#00d18c" />
<text class="search-placeholder">搜索学员...</text>
</view>
<view class="content">
<view v-if="studentList.length === 0" class="empty-box">
<image src="/static/icon-img/empty.png" mode="aspectFit" class="empty-img"></image>
<text class="empty-text">暂无学员数据</text>
</view>
<view v-else class="student-list">
<view v-for="(item, index) in studentList" :key="index" class="student-item" @click="goToDetail(item)">
<view class="student-card">
<view class="student-avatar">
<image :src="item.avatar || '/static/icon-img/avatar.png'" mode="aspectFill" class="avatar-img"></image>
</view>
<view class="student-info">
<view class="student-name">{{item.name}}</view>
<view class="info-row">
<text class="info-label">所属校区:</text>
<text class="info-value">{{item.campus}}</text>
</view>
<view class="info-row">
<text class="info-label">剩余课程:</text>
<text class="info-value">{{ getRemainingCourses(item) }}节</text>
</view>
<view class="info-row">
<text class="info-label">到期时间:</text>
<text class="info-value">{{item.end_date}}</text>
</view>
</view>
<view class="arrow-right">
<uni-icons type="right" size="16" color="#CCCCCC"></uni-icons>
</view>
</view>
</view>
</view>
</view>
<fui-drawer :show="showSearch" position="top" @close="closeSearch" :maskClick="true" background="#23232a">
<view class="fui-page__bd">
<view class="fui-section__title">学员搜索</view>
<view class="search-close-icon" @click="closeSearch">
<uni-icons type="closeempty" size="24" color="#ffffff"></uni-icons>
</view>
<fui-form>
<fui-form-item label="学生姓名" required>
<fui-input :value="searchForm.name" placeholder="请输入学生姓名" @input="onNameInput" borderColor="#00d18c"></fui-input>
</fui-form-item>
<fui-form-item label="联系电话">
<fui-input :value="searchForm.phone" placeholder="请输入联系电话" type="number" @input="onPhoneInput" borderColor="#00d18c"></fui-input>
</fui-form-item>
<fui-form-item label="课时数量">
<fui-input :value="searchForm.lessonCount" placeholder="请输入课时数量" type="number" @input="onLessonCountInput" borderColor="#00d18c"></fui-input>
</fui-form-item>
<fui-form-item label="请假次数">
<fui-input :value="searchForm.leaveCount" placeholder="请输入请假次数" type="number" @input="onLeaveCountInput" borderColor="#00d18c"></fui-input>
</fui-form-item>
<fui-form-item label="课程名称">
<view class="custom-picker-input" @click="showCoursePicker = true">
<text>{{ selectedCourseName || '请选择' }}</text>
<fui-icon name="arrowdown" :size="32" color="#00d18c"></fui-icon>
</view>
<!-- 使用通用单选选择器组件 -->
<single-picker
:show.sync="showCoursePicker"
:data="courseList"
valueKey="id"
textKey="course_name"
title="选择课程"
@change="onCourseChange"
@cancel="showCoursePicker = false"
></single-picker>
</fui-form-item>
<fui-form-item label="班级">
<view class="custom-picker-input" @click="showClassPicker = true">
<text>{{ selectedClassName || '请选择' }}</text>
<fui-icon name="arrowdown" :size="32" color="#00d18c"></fui-icon>
</view>
<!-- 使用通用单选选择器组件 -->
<single-picker
:show.sync="showClassPicker"
:data="classList"
valueKey="id"
:textKey="['campus_name', 'class_name']"
textSeparator="-"
title="选择班级"
@change="onClassChange"
@cancel="showClassPicker = false"
></single-picker>
</fui-form-item>
</fui-form>
<view class="fui-btn__box">
<fui-button type="primary" @click="doSearch" background="#00d18c" color="#FFFFFF" radius="12">搜索</fui-button>
</view>
</view>
</fui-drawer>
<AQTabber />
</view>
</template>
<script>
import memberApi from '@/api/member.js';
import AQTabber from "@/components/AQ/AQTabber.vue"
import SinglePicker from "@/components/custom-picker/single-picker.vue"
export default {
components: {
AQTabber,
SinglePicker
},
data() {
return {
studentList: [],
showSearch: false,
showCoursePicker: false,
showClassPicker: false,
searchForm: {
name: '',
phone: '',
lessonCount: '',
leaveCount: '',
courseId: null,
classId: null,
},
selectedCourseName: '',
selectedClassName: '',
courseList: [],
classList: [],
}
},
onLoad() {
this.getStudentList();
this.getClassesList();
},
methods: {
navigateBack() {
uni.navigateBack();
},
async getStudentList() {
try {
// 注意:后端student_list接口只接受type参数,不接受搜索表单
const params = { type: 'all' };
const res = await memberApi.jlGetStudentList(Object.assign(params, this.searchForm));
console.log('获取学员列表响应:', res);
if(res.code == 1) {
this.studentList = res.data || [];
console.log('学员列表更新成功:', this.studentList);
} else {
console.error('API返回错误:', res);
uni.showToast({
title: res.msg || '获取学员列表失败',
icon: 'none'
});
}
}catch ( error) {
console.error('获取学员列表错误', error);
uni.showToast({
title: '获取学员列表失败',
icon: 'none'
});
return;
}
},
goToDetail(student) {
uni.navigateTo({
url: `/pages/market/clue/clue_info?resource_sharing_id=`+student.resource_sharing_id
});
},
getRemainingCourses(item) {
const totalHours = (item.total_hours || 0)
+ (item.gift_hours || 0);
const usedHours = (item.use_total_hours ||
0) + (item.use_gift_hours || 0);
return totalHours - usedHours;
},
// 输入处理方法
onNameInput(e) {
this.searchForm.name = e;
},
onPhoneInput(e) {
this.searchForm.phone = e;
},
onLessonCountInput(e) {
this.searchForm.lessonCount = e;
},
onLeaveCountInput(e) {
this.searchForm.leaveCount = e;
},
// 选择器变更处理
onCourseChange(e) {
this.searchForm.courseId = e.value;
this.selectedCourseName = e.text;
},
onClassChange(e) {
this.searchForm.classId = e.value;
this.selectedClassName = e.text;
},
// 关闭搜索窗口
closeSearch() {
this.showSearch = false;
},
// 监听遮罩层点击事件
onMaskClick() {
this.showSearch = false;
},
// 获取班级列表
async getClassesList() {
try {
const res = await memberApi.jlGetClassesList();
if (res.code == 1) {
// 确保API返回的数据是数组格式
this.classList = res.data.classes || [];
this.courseList = res.data.course || [];
} else {
uni.showToast({
title: res.msg || '获取班级列表失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取班级列表错误', error);
uni.showToast({
title: '获取班级列表失败',
icon: 'none'
});
}
},
doSearch() {
// 这里可以根据 searchForm 的内容进行筛选或请求
this.showSearch = false;
this.getStudentList()
}
}
}
</script>
<style lang="scss">
.container {
background-color: #18181c;
display: flex;
flex-direction: column;
}
.safe-area {
padding-top: var(--status-bar-height);
padding-bottom: 120rpx;
}
.search-bar {
display: flex;
align-items: center;
background: #23232a;
border-radius: 12rpx;
padding: 18rpx 24rpx;
margin: 24rpx 24rpx 0 24rpx;
color: #bdbdbd;
font-size: 28rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.08);
&:active {
background: #2a2a31;
}
}
.search-placeholder {
margin-left: 12rpx;
color: #bdbdbd;
flex: 1;
}
.content {
padding: 20rpx;
}
.empty-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 200rpx;
.empty-img {
width: 200rpx;
height: 200rpx;
}
.empty-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999;
}
}
.student-list {
.student-item {
margin-bottom: 20rpx;
}
.student-card {
display: flex;
align-items: center;
background-color: #23232a;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.12);
transition: box-shadow 0.2s;
&:active {
box-shadow: 0 4rpx 20rpx rgba(0,255,128,0.12);
}
}
.student-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
overflow: hidden;
margin-right: 30rpx;
.avatar-img {
width: 100%;
height: 100%;
}
}
.student-info {
flex: 1;
}
.student-name {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 10rpx;
color: #fff;
}
.info-row {
display: flex;
font-size: 26rpx;
margin-top: 8rpx;
.info-label {
color: #bdbdbd;
}
.info-value {
color: #fff;
}
}
.arrow-right {
padding-left: 20rpx;
}
}
.popup-content {
background: #23232a;
color: #fff;
padding: 32rpx 24rpx;
border-radius: 16rpx;
min-width: 300rpx;
text-align: left;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #00d18c;
margin-bottom: 24rpx;
text-align: center;
}
.picker-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18rpx 0;
border-bottom: 1px solid #333;
.picker-label {
color: #bdbdbd;
font-size: 28rpx;
}
.picker-value {
color: #fff;
font-size: 28rpx;
}
}
.search-btn {
width: 100%;
background: #00d18c;
color: #fff;
border: none;
border-radius: 12rpx;
font-size: 30rpx;
padding: 20rpx 0;
margin-top: 32rpx;
margin-bottom: 8rpx;
}
.fui-picker__input {
display: flex;
justify-content: space-between;
align-items: center;
height: 72rpx;
padding: 0 24rpx;
background-color: #2c2c34;
border-radius: 8rpx;
text {
font-size: 28rpx;
color: #fff;
}
}
.fui-btn__box {
margin-top: 50rpx;
padding: 0 30rpx;
}
.fui-page__bd {
padding: 30rpx;
padding-top: 70rpx;
background-color: #23232a;
position: relative;
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
}
.fui-section__title {
font-size: 36rpx;
color: #00d18c;
font-weight: bold;
margin-top: 30rpx;
text-align: center;
}
.search-close-icon {
position: absolute;
top: 24rpx;
right: 24rpx;
z-index: 10;
padding: 10rpx;
}
.custom-picker-input {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
border-radius: 8rpx;
border-bottom: 2rpx solid #00d18c;
}
</style>