Files
education/frontend/src/views/student/studentInfo/index.vue
T

499 lines
21 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 student-info-page">
<!-- ==================== 1. 查询条件区域 ==================== -->
<el-card shadow="never" class="search-card">
<el-form :model="searchForm" label-width="110px" class="search-form">
<el-row :gutter="24">
<!-- 左栏 -->
<el-col :xs="24" :md="12">
<el-form-item label="学号">
<el-input v-model="searchForm.xh" placeholder="请输入学号" clearable />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="searchForm.xm" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item label="性别">
<el-select v-model="searchForm.xb" placeholder="请选择性别" clearable class="full-width">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
</el-form-item>
<el-form-item label="证件号码">
<el-input v-model="searchForm.zjhm" placeholder="请输入证件号码" clearable />
</el-form-item>
<el-form-item label="政治面貌">
<el-input v-model="searchForm.zzmm" placeholder="请输入政治面貌" clearable />
</el-form-item>
<el-form-item label="民族">
<el-input v-model="searchForm.mz" placeholder="请输入民族" clearable />
</el-form-item>
<el-form-item label="籍贯">
<el-input v-model="searchForm.jg" placeholder="请输入籍贯" clearable />
</el-form-item>
<el-form-item label="学位">
<el-input v-model="searchForm.xw" placeholder="请输入学位" clearable />
</el-form-item>
</el-col>
<!-- 右栏 -->
<el-col :xs="24" :md="12">
<el-form-item label="原部职别">
<el-input v-model="searchForm.ybzb" placeholder="请输入原部职别" clearable />
</el-form-item>
<el-form-item label="身份证号">
<el-input v-model="searchForm.sfzh" placeholder="请输入身份证号" clearable />
</el-form-item>
<el-form-item label="文化程度">
<el-input v-model="searchForm.whcd" placeholder="请输入文化程度" clearable />
</el-form-item>
<el-form-item label="本科毕业院校">
<el-input v-model="searchForm.bkbyyx" placeholder="请输入本科毕业院校" clearable />
</el-form-item>
<el-form-item label="标签">
<el-input v-model="searchForm.bq" placeholder="请输入标签" clearable />
</el-form-item>
<el-form-item label="联系电话">
<el-input v-model="searchForm.lxdh" placeholder="请输入联系电话" clearable />
</el-form-item>
<el-form-item label="通信地址">
<el-input v-model="searchForm.txdz" placeholder="请输入通信地址" clearable />
</el-form-item>
</el-col>
</el-row>
<div class="search-actions">
<el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
</div>
</el-form>
</el-card>
<!-- ==================== 2. 数据表格区域 ==================== -->
<el-card shadow="never" class="table-card">
<div class="list-header">
<div class="list-title">学员信息列表</div>
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增学员</el-button>
</div>
<el-table v-loading="loading" :data="tableData" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="xh" label="学号" width="55" show-overflow-tooltip />
<el-table-column prop="xm" label="姓名" width="55" />
<el-table-column prop="xb" label="性别" width="55" align="center" />
<el-table-column prop="nj" label="年级" width="55" align="center" />
<el-table-column prop="zy" label="专业" width="55" show-overflow-tooltip />
<el-table-column prop="db" label="队别" width="55" align="center" />
<el-table-column prop="bc" label="班次" width="55" align="center" />
<el-table-column prop="pxlx" label="培训类型" width="85" show-overflow-tooltip />
<el-table-column prop="pxcc" label="培训层次" width="85" align="center" />
<el-table-column prop="zzmm" label="政治面貌" width="85" align="center" />
<el-table-column prop="mz" label="民族" width="55" align="center" />
<el-table-column prop="jg" label="籍贯" width="90" align="center" show-overflow-tooltip />
<el-table-column prop="xw" label="学位" width="55" align="center" />
<el-table-column prop="zczt" label="注册状态" width="85" align="center" />
<el-table-column prop="xjyd" label="学籍异动状态" width="110" align="center" />
<el-table-column prop="ksqk" label="考试情况" width="85" align="center" />
<el-table-column prop="bjgm" label="不及格门数" width="110" align="center" />
<el-table-column prop="gljg" label="管理机构" width="85" align="center" />
<el-table-column label="操作" align="center" fixed="right">
<template slot-scope="{ row }">
<el-button type="text" class="text-primary" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" class="text-success" @click="handleGrades(row)">成绩</el-button>
<el-button type="text" class="danger-text" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
:current-page="pagination.pageNum"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
background
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</div>
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog
:visible="dialogVisible"
:title="dialogTitle"
width="780px"
:close-on-click-modal="false"
@update:visible="val => dialogVisible = val"
>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="编号" prop="bh"><el-input v-model="formData.bh" placeholder="请输入编号" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="学号" prop="xh"><el-input v-model="formData.xh" placeholder="请输入学号" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="姓名" prop="xm"><el-input v-model="formData.xm" placeholder="请输入姓名" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="性别" prop="xb"><el-select v-model="formData.xb" placeholder="请选择" class="full-width"><el-option label="男" value="1" /><el-option label="女" value="0" /></el-select></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="出生日期" prop="csrq"><el-date-picker v-model="formData.csrq" type="date" placeholder="请选择" value-format="yyyy-MM-dd" class="full-width" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="民族" prop="mz"><el-input v-model="formData.mz" placeholder="请输入民族" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="籍贯" prop="jg"><el-input v-model="formData.jg" placeholder="请输入籍贯" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="政治面貌" prop="zzmm"><el-input v-model="formData.zzmm" placeholder="请输入政治面貌" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="文化程度" prop="whcd"><el-input v-model="formData.whcd" placeholder="请输入文化程度" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="学员类别" prop="xylb"><el-input v-model="formData.xylb" placeholder="请输入学员类别" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="学员队期编号" prop="xydqbh"><el-input v-model="formData.xydqbh" placeholder="请输入学员队期编号" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="证件号码" prop="zjhm"><el-input v-model="formData.zjhm" placeholder="请输入证件号码" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="所属军区" prop="ssjq"><el-input v-model="formData.ssjq" placeholder="请输入所属军区" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="当前班次编号" prop="dqbzbh"><el-input v-model="formData.dqbzbh" placeholder="请输入当前班次编号" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="军人证件类型" prop="jrzjlx"><el-input v-model="formData.jrzjlx" placeholder="请输入军人证件类型" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="退学状态" prop="txzt"><el-input v-model="formData.txzt" placeholder="请输入退学状态" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8"><el-form-item label="国防生" prop="gfs"><el-select v-model="formData.gfs" placeholder="请选择" class="full-width"><el-option label="是" value="1" /><el-option label="否" value="0" /></el-select></el-form-item></el-col>
<el-col :span="8"><el-form-item label="留级状态" prop="ljzt"><el-input v-model="formData.ljzt" placeholder="请输入" /></el-form-item></el-col>
<el-col :span="8"><el-form-item label="分班状态" prop="fbzt"><el-input v-model="formData.fbzt" placeholder="请输入" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8"><el-form-item label="允许查看成绩" prop="yxckcj"><el-select v-model="formData.yxckcj" placeholder="请选择" class="full-width"><el-option label="是" value="1" /><el-option label="否" value="0" /></el-select></el-form-item></el-col>
<el-col :span="8"><el-form-item label="已注册" prop="yzc"><el-select v-model="formData.yzc" placeholder="请选择" class="full-width"><el-option label="是" value="1" /><el-option label="否" value="0" /></el-select></el-form-item></el-col>
<el-col :span="8" />
</el-row>
<el-row :gutter="20">
<el-col :span="12"><el-form-item label="联系电话" prop="lxdh"><el-input v-model="formData.lxdh" placeholder="请输入联系电话" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="通讯地址" prop="txdz"><el-input v-model="formData.txdz" placeholder="请输入通讯地址" /></el-form-item></el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24"><el-form-item label="备注" prop="bz"><el-input v-model="formData.bz" type="textarea" :rows="2" placeholder="请输入备注" /></el-form-item></el-col>
</el-row>
</el-form>
<div slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
</div>
</el-dialog>
<!-- 成绩弹窗 -->
<el-dialog
:visible="gradesVisible"
title="学员成绩"
width="600px"
:close-on-click-modal="false"
@update:visible="val => gradesVisible = val"
>
<p><strong>学员</strong>{{ gradesStudent }}</p>
<el-tabs v-model="gradesTab">
<el-tab-pane label="成绩" name="grades">
<div v-loading="gradesLoading">
<pre v-if="gradesData">{{ gradesData }}</pre>
</div>
</el-tab-pane>
<el-tab-pane label="进程成绩" name="process">
<div v-loading="gradesLoading">
<pre v-if="processGradesData">{{ processGradesData }}</pre>
</div>
</el-tab-pane>
</el-tabs>
<div slot="footer">
<el-button type="primary" @click="handleExportGrades">导出成绩</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listStudentRecord,
getStudentRecord,
addStudentRecord,
updateStudentRecord,
delStudentRecord
} from "@/api/studentRecords/studentRecords"
export default {
name: 'StudentInfoIndex',
data() {
return {
// ==================== 查询条件 ====================
// 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件
searchForm: {
xh: '', xm: '', xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '',
ybzb: '', sfzh: '', whcd: '', bkbyyx: '', bq: '', lxdh: '', txdz: ''
},
// ==================== 数据表格 ====================
loading: false,
tableData: [],
pagination: { pageNum: 1, pageSize: 20, total: 0 },
// ==================== 新增/编辑弹窗 ====================
dialogVisible: false,
dialogTitle: '新增学员',
submitting: false,
formData: this.createEmptyForm(),
formRules: {
bh: [{ required: true, message: '请输入编号', trigger: 'blur' }],
xh: [{ required: true, message: '请输入学号', trigger: 'blur' }],
xm: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
xydqbh: [{ required: true, message: '请输入学员队期编号', trigger: 'blur' }],
zjhm: [{ required: true, message: '请输入证件号码', trigger: 'blur' }],
zzmm: [{ required: true, message: '请输入政治面貌', trigger: 'blur' }],
xb: [{ required: true, message: '请选择性别', trigger: 'change' }],
csrq: [{ required: true, message: '请选择出生日期', trigger: 'change' }],
mz: [{ required: true, message: '请输入民族', trigger: 'blur' }],
jg: [{ required: true, message: '请输入籍贯', trigger: 'blur' }],
whcd: [{ required: true, message: '请输入文化程度', trigger: 'blur' }],
xylb: [{ required: true, message: '请输入学员类别', trigger: 'blur' }],
ssjq: [{ required: true, message: '请输入所属军区', trigger: 'blur' }],
gfs: [{ required: true, message: '请选择国防生', trigger: 'change' }],
txzt: [{ required: true, message: '请输入退学状态', trigger: 'blur' }],
ljzt: [{ required: true, message: '请输入留级状态', trigger: 'blur' }],
fbzt: [{ required: true, message: '请输入分班状态', trigger: 'blur' }],
yxckcj: [{ required: true, message: '请选择允许查看成绩', trigger: 'change' }],
dqbzbh: [{ required: true, message: '请输入当前班次编号', trigger: 'blur' }],
yzc: [{ required: true, message: '请选择已注册', trigger: 'change' }],
jrzjlx: [{ required: true, message: '请输入军人证件类型', trigger: 'blur' }]
},
// ==================== 成绩弹窗 ====================
gradesVisible: false,
gradesTab: 'grades',
gradesData: null,
processGradesData: null,
gradesStudent: '',
currentBh: '',
gradesLoading: false
}
},
mounted() {
this.loadData()
},
methods: {
/** 创建空白表单 */
createEmptyForm() {
return {
bh: '', xh: '', xm: '', xydqbh: '', zjhm: '', zzmm: '', xb: '', csrq: '', mz: '', jg: '',
whcd: '', xylb: '', ssjq: '', gfs: '', txzt: '', ljzt: '', fbzt: '', yxckcj: '', dqbzbh: '', yzc: '',
jrzjlx: '', sfzh: '', lxdh: '', txdz: '', bz: '', dtsj: ''
}
},
// ==================== 列表加载 ====================
loadData() {
this.loading = true
const params = {
pageNum: this.pagination.pageNum,
pageSize: this.pagination.pageSize
}
this.buildQueryParams(params)
listStudentRecord(params).then(res => {
const data = res.data || {}
this.tableData = data.records || []
this.pagination.total = data.total || 0
this.loading = false
}).catch(() => {
this.tableData = []
this.pagination.total = 0
this.loading = false
})
},
/** 组装查询参数:仅传后端 XYXX 实体支持的字符串字段,空值忽略 */
buildQueryParams(params) {
const textFields = ['xh', 'xm', 'zjhm', 'zzmm', 'mz', 'jg', 'xw', 'ybzb', 'sfzh', 'whcd', 'bkbyyx', 'bq', 'lxdh', 'txdz']
textFields.forEach(key => {
const v = this.searchForm[key]
if (v !== '' && v !== null && v !== undefined) params[key] = v.trim()
})
if (this.searchForm.xb) params.xb = this.searchForm.xb
},
// ==================== 查询/分页 ====================
handleSearch() {
this.pagination.pageNum = 1
this.loadData()
},
handlePageChange(page) {
this.pagination.pageNum = page
this.loadData()
},
handleSizeChange(size) {
this.pagination.pageSize = size
this.pagination.pageNum = 1
this.loadData()
},
// ==================== 新增/编辑弹窗 ====================
resetForm() {
Object.assign(this.formData, this.createEmptyForm())
this.$nextTick(() => {
if (this.$refs.formRef) {
this.$refs.formRef.clearValidate()
}
})
},
handleAdd() {
this.dialogTitle = '新增学员'
this.resetForm()
this.dialogVisible = true
},
handleEdit(row) {
this.dialogTitle = '编辑学员'
this.resetForm()
if (!row.bh) {
Object.assign(this.formData, this.createEmptyForm(), row)
this.dialogVisible = true
return
}
getStudentRecord(row.bh).then(res => {
const data = res.data || {}
Object.assign(this.formData, this.createEmptyForm(), data)
this.dialogVisible = true
}).catch(() => {})
},
// ==================== 新增/编辑提交 ====================
handleSubmit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.submitting = true
const isAdd = this.dialogTitle === '新增学员'
const payload = { ...this.formData }
const request = isAdd ? addStudentRecord(payload) : updateStudentRecord(payload)
request.then(() => {
this.$message.success(isAdd ? '新增成功' : '编辑成功')
this.dialogVisible = false
this.loadData()
}).catch(() => {
}).finally(() => {
this.submitting = false
})
})
},
// ==================== 删除 ====================
handleDelete(row) {
this.$confirm(`确定要删除"${row.xm}"吗?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delStudentRecord(row.bh)
}).then(() => {
this.$message.success('删除成功')
this.loadData()
}).catch(() => {})
},
// ==================== 成绩弹窗 ====================
// TODO: 后端接口未提供,成绩数据为前端模拟;接口就绪后替换为 getStudentGrades / getStudentProcessGrades
handleGrades(row) {
this.gradesStudent = row.xm || ''
this.currentBh = row.bh || ''
this.gradesData = null
this.processGradesData = null
this.gradesTab = 'grades'
this.gradesVisible = true
this.gradesLoading = true
setTimeout(() => {
this.gradesData = { 学员: row.xm, 学号: row.xh, 课程: '通信原理', 成绩: 92, 学分: 3.0 }
this.processGradesData = { 进程成绩: [{ 名称: '平时成绩', 得分: 95 }, { 名称: '期末成绩', 得分: 88 }] }
this.gradesLoading = false
}, 300)
},
// TODO: 后端接口未提供,导出为前端模拟;接口就绪后替换为 exportStudentGrades
handleExportGrades() {
this.$message.success(`已导出学员${this.gradesStudent}成绩(前端模拟)`)
}
}
}
</script>
<style scoped lang="scss">
.student-info-page {
.search-card {
.search-form {
.range-control {
display: flex;
align-items: center;
gap: 6px;
width: 100%;
.el-input {
flex: 1;
}
.range-sep {
flex-shrink: 0;
font-size: 12px;
color: #606266;
}
}
.search-tip {
font-size: 12px;
color: #f56c6c;
margin-top: 8px;
margin-bottom: 8px;
}
.search-actions {
display: flex;
justify-content: flex-end;
padding-top: 12px;
border-top: 1px solid #ebeef5;
}
}
}
.table-card {
.list-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
.list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
}
.el-table {
width: 100%;
}
}
.text-primary {
color: #409eff;
padding: 0;
}
.text-success {
color: #67c23a;
padding: 0;
}
.danger-text {
color: #f56c6c;
padding: 0;
}
.full-width {
width: 100%;
}
}
</style>