Files
education/frontend/src/views/student/statusChange/index.vue
T
2026-08-23 17:23:17 +08:00

480 lines
17 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 status-change-page">
<!-- ==================== 1. 查询条件 ==================== -->
<el-card shadow="never" class="search-card">
<el-form ref="searchFormRef" :model="searchForm" label-width="90px" class="search-form">
<el-row :gutter="24">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="编号">
<el-input v-model="searchForm.bh" placeholder="请输入编号" clearable @keyup.enter.native="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="学员编号">
<el-input v-model="searchForm.xybh" placeholder="请输入学员编号" clearable @keyup.enter.native="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="申请类型">
<el-select v-model="searchForm.sqlx" placeholder="请选择申请类型" clearable class="w-full">
<el-option v-for="item in applyTypeOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="状态">
<el-select v-model="searchForm.zt" placeholder="请选择状态" clearable class="w-full">
<el-option v-for="(item, key) in statusMap" :key="key" :label="item.label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24" class="search-actions">
<div class="search-buttons">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</div>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- ==================== 2. 列表 ==================== -->
<el-card shadow="never" class="table-card">
<div class="table-header">
<span class="table-title">学籍异动申请列表</span>
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增学籍异动申请</el-button>
</div>
<el-table v-loading="loading" :data="tableData" stripe border highlight-current-row>
<el-table-column prop="bh" label="编号" min-width="140" show-overflow-tooltip />
<el-table-column prop="xybh" label="学员编号" min-width="120" show-overflow-tooltip />
<el-table-column prop="sqlx" label="申请类型" width="100" align="center" />
<el-table-column prop="sy" label="事由" min-width="140" show-overflow-tooltip />
<el-table-column prop="bz" label="备注" min-width="140" show-overflow-tooltip />
<el-table-column label="状态" width="90" align="center">
<template slot-scope="{ row }">
<el-tag :type="statusTagType(row.zt)" size="mini">{{ statusLabel(row.zt) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="cjsj" label="创建时间" width="160" show-overflow-tooltip />
<el-table-column prop="xgsj" label="修改时间" width="160" show-overflow-tooltip />
<el-table-column label="操作" width="230" align="center" fixed="right">
<template slot-scope="{ row }">
<el-button type="text" size="small" icon="el-icon-upload2" @click="handleSubmit(row)">提交</el-button>
<el-button type="text" size="small" icon="el-icon-view" @click="handleDetail(row)">详情</el-button>
<el-button type="text" size="small" icon="el-icon-edit" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" size="small" class="text-danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
class="pagination-wrapper"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</el-card>
<!-- ==================== 3. 新增/编辑对话框 ==================== -->
<el-dialog
:visible="formDialogVisible"
:title="dialogTitle"
width="600px"
:close-on-click-modal="false"
@update:visible="val => formDialogVisible = val"
>
<el-form ref="formRef" :model="form" :rules="formRules" label-width="110px" class="add-form">
<el-form-item label="编号" prop="bh">
<el-input v-model="form.bh" placeholder="请输入编号" :disabled="!isAdd" />
</el-form-item>
<el-form-item label="学员编号" prop="xybh">
<el-input v-model="form.xybh" placeholder="请输入学员编号" />
</el-form-item>
<el-form-item label="申请类型" prop="sqlx">
<el-select v-model="form.sqlx" placeholder="请选择申请类型" class="w-full">
<el-option v-for="item in applyTypeOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="事由" prop="sy">
<el-input v-model="form.sy" type="textarea" :rows="3" placeholder="请输入事由" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="状态" prop="zt">
<el-select v-model="form.zt" placeholder="请选择状态" class="w-full">
<el-option v-for="(item, key) in statusMap" :key="key" :label="item.label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="formDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="formSaving" @click="handleFormSubmit">确定</el-button>
</div>
</el-dialog>
<!-- ==================== 4. 详情对话框 ==================== -->
<el-dialog title="学籍异动申请详情" :visible="detailDialogVisible" width="760px" :close-on-click-modal="false"
@update:visible="val => detailDialogVisible = val">
<div v-loading="detailLoading" class="detail-body">
<el-descriptions :column="2" border>
<el-descriptions-item label="编号">{{ detailForm.bh || '-' }}</el-descriptions-item>
<el-descriptions-item label="学员编号">{{ detailForm.xybh || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请类型">{{ detailForm.sqlx || '-' }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="statusTagType(detailForm.zt)" size="mini">{{ statusLabel(detailForm.zt) }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="事由" :span="2">{{ detailForm.sy || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ detailForm.bz || '-' }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ detailForm.cjsj || '-' }}</el-descriptions-item>
<el-descriptions-item label="修改时间">{{ detailForm.xgsj || '-' }}</el-descriptions-item>
<el-descriptions-item label="提交时间">{{ detailForm.tjsj || '-' }}</el-descriptions-item>
<el-descriptions-item label="学员队审核意见">{{ detailForm.xydshyj || '-' }}</el-descriptions-item>
<el-descriptions-item label="学员队干部编号">{{ detailForm.xydgbbh || '-' }}</el-descriptions-item>
<el-descriptions-item label="学员队干部审核时间">{{ detailForm.xydshsj || '-' }}</el-descriptions-item>
<el-descriptions-item label="管理员账户编号">{{ detailForm.glyzhbh || '-' }}</el-descriptions-item>
<el-descriptions-item label="管理员审核意见">{{ detailForm.glyshyj || '-' }}</el-descriptions-item>
<el-descriptions-item label="管理员审核时间">{{ detailForm.glyshsj || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div slot="footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listApplication,
getApplication,
addApplication,
updateApplication,
delApplication
} from '@/api/studentRecords/application'
export default {
name: 'StatusChangeIndex',
data() {
return {
// ==================== 申请类型选项(学籍异动) ====================
applyTypeOptions: ['休学', '复学', '退学', '转学', '留级', '转专业'],
// ==================== 状态映射:0-待审核 1-已审核 2-驳回等 ====================
statusMap: {
0: { label: '待审核', type: 'warning' },
1: { label: '已审核', type: 'success' },
2: { label: '驳回', type: 'danger' }
},
// ==================== 查询条件 ====================
searchForm: {
bh: '',
xybh: '',
sqlx: '',
zt: undefined
},
// ==================== 列表数据 ====================
loading: false,
tableData: [],
total: 0,
pageNum: 1,
pageSize: 20,
// ==================== 新增/编辑 ====================
formDialogVisible: false,
dialogTitle: '新增学籍异动申请',
isAdd: true,
formSaving: false,
form: this.createEmptyForm(),
formRules: {
bh: [{ required: true, message: '请输入编号', trigger: 'blur' }],
xybh: [{ required: true, message: '请输入学员编号', trigger: 'blur' }],
sqlx: [{ required: true, message: '请选择申请类型', trigger: 'change' }],
sy: [{ required: true, message: '请输入事由', trigger: 'blur' }],
zt: [{ required: true, message: '请选择状态', trigger: 'change' }]
},
// ==================== 详情 ====================
detailDialogVisible: false,
detailLoading: false,
detailForm: {}
}
},
mounted() {
this.fetchList()
},
methods: {
createEmptyForm() {
return {
bh: '',
xybh: '',
sqlx: '',
sy: '',
bz: '',
zt: 0
}
},
// ==================== 状态展示 ====================
statusLabel(zt) {
const item = this.statusMap[zt]
return item ? item.label : (zt !== null && zt !== undefined ? String(zt) : '-')
},
statusTagType(zt) {
const item = this.statusMap[zt]
return item ? item.type : 'info'
},
// ==================== 查询列表 ====================
fetchList() {
this.loading = true
const params = {
pageNum: this.pageNum,
pageSize: this.pageSize
}
// 等值筛选,留空不传
;['bh', 'xybh', 'sqlx'].forEach(key => {
const value = this.searchForm[key]
if (value !== '' && value !== null && value !== undefined) {
params[key] = String(value).trim()
}
})
if (this.searchForm.zt !== undefined && this.searchForm.zt !== '' && this.searchForm.zt !== null) {
params.zt = this.searchForm.zt
}
listApplication(params).then(response => {
const data = response.data || {}
this.tableData = data.records || []
this.total = data.total || 0
this.loading = false
}).catch(() => {
this.tableData = []
this.total = 0
this.loading = false
})
},
handleSearch() {
this.pageNum = 1
this.fetchList()
},
handleReset() {
this.$refs.searchFormRef.resetFields()
this.pageNum = 1
this.fetchList()
},
handlePageChange(current) {
this.pageNum = current
this.fetchList()
},
handleSizeChange(size) {
this.pageSize = size
this.pageNum = 1
this.fetchList()
},
// ==================== 新增/编辑 ====================
handleAdd() {
this.isAdd = true
this.dialogTitle = '新增学籍异动申请'
this.form = this.createEmptyForm()
this.formDialogVisible = true
this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate()
})
},
handleEdit(row) {
this.isAdd = false
this.dialogTitle = '编辑学籍异动申请'
this.form = this.createEmptyForm()
this.formDialogVisible = true
this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate()
})
getApplication(row.bh).then(response => {
const data = response.data || {}
this.form = {
bh: data.bh || '',
xybh: data.xybh || '',
sqlx: data.sqlx || '',
sy: data.sy || '',
bz: data.bz || '',
zt: data.zt !== null && data.zt !== undefined ? Number(data.zt) : 0
}
}).catch(() => {})
},
buildPayload() {
const f = this.form
const payload = {
bh: f.bh,
xybh: f.xybh,
sqlx: f.sqlx,
sy: f.sy,
zt: Number(f.zt)
}
// 备注留空则移除
if (f.bz !== '' && f.bz !== null && f.bz !== undefined) {
payload.bz = f.bz
}
return payload
},
handleFormSubmit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.formSaving = true
const payload = this.buildPayload()
const request = this.isAdd ? addApplication(payload) : updateApplication(payload)
request.then(() => {
this.$message.success(this.isAdd ? '新增成功' : '修改成功')
this.formDialogVisible = false
this.fetchList()
}).catch(() => {
}).finally(() => {
this.formSaving = false
})
})
},
// ==================== 提交 ====================
// 无独立提交接口,通过编辑接口写入提交时间 tjsj(zt 保持原值不变)
formatNow() {
const d = new Date()
const pad = n => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
},
handleSubmit(row) {
this.$confirm(`确定要提交编号为「${row.bh}」的学籍异动申请吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const payload = {
bh: row.bh,
xybh: row.xybh,
sqlx: row.sqlx,
sy: row.sy,
zt: row.zt !== null && row.zt !== undefined ? Number(row.zt) : 0,
tjsj: this.formatNow()
}
if (row.bz) {
payload.bz = row.bz
}
return updateApplication(payload)
}).then(() => {
this.$message.success('提交成功')
this.fetchList()
}).catch(() => {})
},
// ==================== 删除 ====================
handleDelete(row) {
this.$confirm(`确定要删除编号为「${row.bh}」的学籍异动申请吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delApplication(row.bh)
}).then(() => {
this.$message.success('删除成功')
this.fetchList()
}).catch(() => {})
},
// ==================== 详情 ====================
handleDetail(row) {
this.detailDialogVisible = true
this.detailLoading = true
this.detailForm = {}
getApplication(row.bh).then(response => {
this.detailForm = response.data || {}
this.detailLoading = false
}).catch(() => {
this.detailLoading = false
})
}
}
}
</script>
<style scoped lang="scss">
.app-container {
padding: 20px;
}
.status-change-page {
.search-card {
margin-bottom: 16px;
}
.search-form {
.w-full {
width: 100%;
}
.search-actions {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 8px;
.search-tip {
font-size: 12px;
color: #909399;
}
.search-buttons {
display: flex;
gap: 12px;
}
}
}
.table-card {
.table-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
.table-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
}
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
}
.add-form {
max-height: 60vh;
overflow-y: auto;
padding-right: 4px;
}
.text-danger {
color: #f56c6c;
padding: 0;
}
}
</style>