guoyu/fronted_uniapp/pages/student/list.vue
2025-12-03 18:58:36 +08:00

320 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="student-list-container">
<!-- 顶部导航栏 -->
<custom-navbar title="学生管理"></custom-navbar>
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-box">
<u-icon name="search" color="#999" size="36"></u-icon>
<u-input
v-model="searchKeyword"
placeholder="搜索学生姓名、学号..."
:clearable="true"
@input="handleSearch"
/>
</view>
</view>
<!-- 班级筛选 -->
<view class="filter-section">
<view class="filter-item" @click="showClassPicker = true">
<text class="filter-label">班级:</text>
<text class="filter-value">{{ selectedClassName || '全部班级' }}</text>
<text class="filter-icon">▼</text>
</view>
</view>
<!-- 班级选择器 -->
<u-picker
:show="showClassPicker"
:columns="[classOptions]"
keyName="label"
@confirm="onClassConfirm"
@cancel="showClassPicker = false"
></u-picker>
<u-empty v-if="filteredStudentList.length === 0 && !loading" mode="data" text="暂无学生"></u-empty>
<view v-else class="student-list">
<view
v-for="student in filteredStudentList"
:key="student.userId"
class="student-item"
@click="goToStudentDetail(student)"
>
<view class="student-avatar">
<text class="avatar-text">{{ (student.nickName || student.userName || 'S').charAt(0) }}</text>
</view>
<view class="student-info">
<text class="student-name">{{ student.nickName || student.userName }}</text>
<text class="student-id">学号:{{ student.userName }}</text>
<text class="student-class" v-if="student.className">班级:{{ student.className }}</text>
</view>
<view class="student-actions">
<text class="arrow-icon"></text>
</view>
</view>
</view>
</view>
</template>
<script>
import { getAllStudents, getStudentsByClass } from '@/api/study/classUser.js'
import request from '@/utils/request.js'
import CustomNavbar from '@/components/custom-navbar/custom-navbar.vue'
export default {
components: {
CustomNavbar
},
data() {
return {
studentList: [],
filteredStudentList: [],
loading: false,
searchKeyword: '',
classList: [],
classOptions: [{ value: null, label: '全部班级' }],
selectedClassId: null,
selectedClassName: null,
showClassPicker: false
}
},
onLoad() {
this.loadClassList()
this.loadStudentList()
},
onShow() {
this.loadStudentList()
},
onPullDownRefresh() {
this.loadStudentList().finally(() => {
uni.stopPullDownRefresh()
})
},
methods: {
async loadClassList() {
try {
const response = await request.get('/study/class/list')
if (response.code === 200) {
this.classList = response.rows || response.data || []
// 构建班级选项
this.classOptions = [
{ value: null, label: '全部班级' },
...this.classList.map(cls => ({
value: cls.id,
label: cls.className
}))
]
}
} catch (error) {
console.error('加载班级列表失败', error)
}
},
async loadStudentList() {
this.loading = true
try {
let response
if (this.selectedClassId) {
// 按班级获取学生
response = await getStudentsByClass(this.selectedClassId)
} else {
// 获取所有学生
response = await getAllStudents()
}
if (response.code === 200) {
this.studentList = response.data || []
this.applyFilter()
} else {
uni.showToast({
title: response.msg || '加载失败',
icon: 'none'
})
}
} catch (error) {
console.error('加载学生列表失败', error)
uni.showToast({
title: error.message || '加载失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
applyFilter() {
let filtered = [...this.studentList]
// 按关键词搜索
if (this.searchKeyword) {
const keyword = this.searchKeyword.toLowerCase()
filtered = filtered.filter(student => {
const name = (student.nickName || student.userName || '').toLowerCase()
const username = (student.userName || '').toLowerCase()
return name.includes(keyword) || username.includes(keyword)
})
}
this.filteredStudentList = filtered
},
handleSearch(value) {
// 如果传入了值,更新搜索关键词
if (value !== undefined) {
this.searchKeyword = value
}
this.applyFilter()
},
onClassConfirm(e) {
const selected = e.value[0]
this.selectedClassId = selected.value
this.selectedClassName = selected.label
this.showClassPicker = false
this.loadStudentList()
},
goToStudentDetail(student) {
uni.navigateTo({
url: `/pages/student/detail?id=${student.userId}`
})
}
}
}
</script>
<style lang="scss" scoped>
.student-list-container {
padding: 30rpx;
padding-top: calc(30rpx + 88rpx + env(safe-area-inset-top));
background-color: #f5f7fa;
min-height: 100vh;
@media (min-width: 768px) {
padding: 60rpx;
max-width: 1200rpx;
margin: 0 auto;
}
}
.search-section {
margin-bottom: 30rpx;
.search-box {
background: #fff;
border-radius: 50rpx;
padding: 20rpx 30rpx;
display: flex;
align-items: center;
gap: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}
}
.filter-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
.filter-item {
display: flex;
align-items: center;
padding: 20rpx 24rpx;
background: #f5f7fa;
border-radius: 12rpx;
.filter-label {
font-size: 28rpx;
color: #666;
margin-right: 12rpx;
font-weight: 500;
}
.filter-value {
flex: 1;
font-size: 28rpx;
color: #1a1a1a;
font-weight: 500;
}
.filter-icon {
font-size: 20rpx;
color: #999;
margin-left: 12rpx;
}
}
}
.student-list {
.student-item {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 24rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
transition: transform 0.2s;
&:active {
transform: scale(0.98);
}
.student-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background: linear-gradient(135deg, rgb(55 140 224) 0%, rgb(45 120 200) 100%);
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
flex-shrink: 0;
.avatar-text {
font-size: 40rpx;
color: #fff;
font-weight: bold;
}
}
.student-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
.student-name {
font-size: 32rpx;
font-weight: bold;
color: #1a1a1a;
}
.student-id {
font-size: 26rpx;
color: #666;
}
.student-class {
font-size: 26rpx;
color: rgb(55 140 224);
}
}
.student-actions {
.arrow-icon {
font-size: 40rpx;
color: #d9d9d9;
}
}
}
}
</style>