pangu-user-platform/frontend/src/views/student/index.vue

284 lines
9.0 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>
<div class="app-container">
<el-row :gutter="16">
<!-- 左侧学校树 -->
<el-col :span="5">
<el-card shadow="never">
<template #header>
<span>学校筛选</span>
</template>
<el-input v-model="treeFilterText" placeholder="输入关键字过滤" clearable style="margin-bottom: 12px" />
<el-scrollbar height="calc(100vh - 260px)">
<el-tree
ref="treeRef"
:data="schoolTree"
:props="{ label: 'name', children: 'children' }"
node-key="id"
highlight-current
:filter-node-method="filterNode"
@node-click="handleNodeClick"
/>
</el-scrollbar>
</el-card>
</el-col>
<!-- 右侧列表 -->
<el-col :span="19">
<!-- 搜索区域 -->
<el-card shadow="never" class="search-wrapper">
<el-form :model="queryParams" :inline="true">
<el-form-item label="学生姓名">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable style="width: 150px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="学号">
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable style="width: 150px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="性别">
<el-select v-model="queryParams.gender" placeholder="全部" clearable style="width: 100px">
<el-option label="男" value="1" />
<el-option label="女" value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 表格区域 -->
<el-card shadow="never" style="margin-top: 12px">
<el-row :gutter="10" style="margin-bottom: 12px">
<el-col :span="1.5">
<el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" :icon="Upload" @click="handleImport">导入</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="tableData" border stripe :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" style="width: 100%">
<el-table-column prop="studentNo" label="学号" width="130" />
<el-table-column prop="studentName" label="姓名" width="100" />
<el-table-column prop="gender" label="性别" width="60" align="center">
<template #default="{ row }">
{{ row.gender === '1' ? '男' : row.gender === '2' ? '女' : '未知' }}
</template>
</el-table-column>
<el-table-column prop="birthday" label="出生日期" width="110">
<template #default="{ row }">
{{ row.birthday ? row.birthday.substring(0, 10) : '' }}
</template>
</el-table-column>
<el-table-column prop="schoolName" label="学校" min-width="150" show-overflow-tooltip />
<el-table-column prop="gradeName" label="年级" width="80" />
<el-table-column prop="className" label="班级" width="80" />
<el-table-column label="归属用户" width="120" show-overflow-tooltip>
<template #default="{ row }">
<template v-if="row.members && row.members.length > 0">
{{ row.members.map(m => m.nickname || m.phone).join(', ') }}
</template>
<span v-else style="color: #909399;">未绑定</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="160">
<template #default="{ row }">
{{ row.createTime ? row.createTime.substring(0, 19).replace('T', ' ') : '' }}
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right" align="center">
<template #default="{ row }">
<el-button type="primary" link :icon="Edit" @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" link :icon="Delete" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top: 16px; justify-content: flex-end"
@size-change="handleQuery"
@current-change="handleQuery"
/>
</el-card>
</el-col>
</el-row>
<!-- 新增/编辑弹窗 -->
<StudentDialog ref="studentDialogRef" @success="handleQuery" />
<!-- 导入弹窗 -->
<ImportDialog ref="importDialogRef" @success="handleQuery" />
</div>
</template>
<script setup>
/**
* 学生管理页面
* @author pangu
*/
import { Delete, Edit, Plus, Refresh, Search, Upload } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { onMounted, ref, watch } from 'vue'
import request from '@/utils/request'
import ImportDialog from './components/ImportDialog.vue'
import StudentDialog from './components/StudentDialog.vue'
// 学校树相关
const treeRef = ref()
const treeFilterText = ref('')
const schoolTree = ref([])
// 表格相关
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
// 查询参数
const queryParams = ref({
pageNum: 1,
pageSize: 10,
studentName: '',
studentNo: '',
gender: '',
schoolId: '',
schoolGradeId: '',
schoolClassId: ''
})
// 弹窗引用
const studentDialogRef = ref()
const importDialogRef = ref()
// 监听树过滤
watch(treeFilterText, (val) => {
treeRef.value?.filter(val)
})
// 树节点过滤
const filterNode = (value, data) => {
if (!value) return true
return data.name.includes(value)
}
// 获取学校树
const getSchoolTree = async () => {
const res = await request.get('/business/student/schoolTree')
if (res.code === 200) {
schoolTree.value = res.data
}
}
// 获取学生列表
const getList = async () => {
loading.value = true
try {
const res = await request.get('/business/student/list', { params: queryParams.value })
if (res.code === 200) {
tableData.value = res.rows
total.value = res.total
}
} finally {
loading.value = false
}
}
// 从节点 id 中提取数字 ID格式为 "school_1", "grade_2", "class_3"
const extractId = (nodeId) => {
if (!nodeId) return ''
const parts = nodeId.split('_')
return parts.length > 1 ? parts[1] : nodeId
}
// 树节点点击
const handleNodeClick = (data) => {
// 根据节点层级设置筛选条件,提取真正的数字 ID
if (data.type === 'school') {
queryParams.value.schoolId = extractId(data.id)
queryParams.value.schoolGradeId = ''
queryParams.value.schoolClassId = ''
} else if (data.type === 'grade') {
queryParams.value.schoolId = data.schoolId // 年级节点有 schoolId 字段
queryParams.value.schoolGradeId = extractId(data.id)
queryParams.value.schoolClassId = ''
} else if (data.type === 'class') {
queryParams.value.schoolId = data.schoolId // 班级节点有 schoolId 字段
queryParams.value.schoolGradeId = data.schoolGradeId // 班级节点有 schoolGradeId 字段
queryParams.value.schoolClassId = extractId(data.id)
}
queryParams.value.pageNum = 1
getList()
}
// 搜索
const handleQuery = () => {
queryParams.value.pageNum = 1
getList()
}
// 重置
const resetQuery = () => {
queryParams.value = {
pageNum: 1,
pageSize: 10,
studentName: '',
studentNo: '',
gender: '',
schoolId: '',
schoolGradeId: '',
schoolClassId: ''
}
treeRef.value?.setCurrentKey(null)
getList()
}
// 新增
const handleAdd = () => {
studentDialogRef.value?.open()
}
// 编辑
const handleEdit = (row) => {
studentDialogRef.value?.open(row)
}
// 导入
const handleImport = () => {
importDialogRef.value?.open()
}
// 删除
const handleDelete = (row) => {
ElMessageBox.confirm(`确定要删除学生"${row.studentName}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const res = await request.delete(`/business/student/${row.studentId}`)
if (res.code === 200) {
ElMessage.success('删除成功')
getList()
}
}).catch(() => {})
}
onMounted(() => {
getSchoolTree()
getList()
})
</script>
<style scoped>
.app-container {
padding: 16px;
}
.search-wrapper {
margin-bottom: 0;
}
</style>