若干前端bug修复

This commit is contained in:
2026-08-27 12:01:33 +08:00
parent c8990ab1a4
commit 26072ffe4e
9 changed files with 457 additions and 119 deletions
@@ -21,7 +21,7 @@ export function getApplication(bh) {
}) })
} }
// 新增学籍异动申请(请求体 XYXJYDSQB 实体;bh 需前端传入,创建/修改时间后端自动维护) // 新增学籍异动申请(编号、状态和创建/修改时间后端维护)
export function addApplication(data) { export function addApplication(data) {
return request({ return request({
url: '/student-records/application/add', url: '/student-records/application/add',
+9
View File
@@ -21,6 +21,15 @@ export function getTeam(xydbh) {
}) })
} }
// 根据是否为主体培训任务查询可选培训任务
export function listTrainingTasks(ztpxrw) {
return request({
url: '/student-records/training-tasks',
method: 'get',
params: { ztpxrw }
})
}
// 新增学员队(请求体 XYDB // 新增学员队(请求体 XYDB
export function addTeam(data) { export function addTeam(data) {
return request({ return request({
+146 -32
View File
@@ -21,7 +21,14 @@
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
<el-form-item label="学员队类型"> <el-form-item label="学员队类型">
<el-input v-model="searchForm.xydlx" placeholder="请输入学员队类型" clearable @keyup.enter.native="handleSearch" /> <el-select v-model="searchForm.xydlx" placeholder="请选择学员队类型" clearable filterable class="w-full">
<el-option
v-for="item in teamTypeOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
@@ -32,8 +39,8 @@
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
<el-form-item label="虚实类型"> <el-form-item label="虚实类型">
<el-select v-model="searchForm.xslx" placeholder="请选择虚实类型" clearable class="w-full"> <el-select v-model="searchForm.xslx" placeholder="请选择虚实类型" clearable class="w-full">
<el-option label="" :value="0" /> <el-option label="" :value="0" />
<el-option label="" :value="1" /> <el-option label="" :value="1" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -74,7 +81,7 @@
<el-table-column label="虚实类型" width="90" align="center"> <el-table-column label="虚实类型" width="90" align="center">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-tag :type="Number(row.xslx) === 1 ? 'success' : 'info'" size="mini"> <el-tag :type="Number(row.xslx) === 1 ? 'success' : 'info'" size="mini">
{{ Number(row.xslx) === 1 ? '' : '' }} {{ Number(row.xslx) === 1 ? '' : '' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
@@ -156,17 +163,38 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="学员队类型" prop="xydlx"> <el-form-item label="学员队类型" prop="xydlx">
<el-input v-model="form.xydlx" placeholder="请输入学员队类型" /> <el-select v-model="form.xydlx" placeholder="请选择学员队类型" filterable class="w-full">
<el-option
v-for="item in teamTypeOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="节次类别" prop="jclb"> <el-form-item label="节次类别" prop="jclb">
<el-input v-model="form.jclb" placeholder="请输入节次类别" /> <el-select v-model="form.jclb" placeholder="请选择节次类别" filterable class="w-full">
<el-option
v-for="item in sessionCategoryOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="系统模式" prop="xtms"> <el-form-item label="系统模式" prop="xtms">
<el-input v-model="form.xtms" placeholder="请输入系统模式" /> <el-select v-model="form.xtms" placeholder="请选择系统模式" filterable class="w-full">
<el-option
v-for="item in systemModeOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -176,7 +204,14 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="所属单位"> <el-form-item label="所属单位">
<el-input v-model="form.ssdw" placeholder="请输入所属单位" /> <el-select v-model="form.ssdw" placeholder="请选择所属单位" clearable filterable class="w-full">
<el-option
v-for="item in unitCategoryOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -196,14 +231,14 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="虚实类型" prop="xslx"> <el-form-item label="虚实类型" prop="xslx">
<el-select v-model="form.xslx" class="w-full"> <el-select v-model="form.xslx" class="w-full">
<el-option label="" :value="0" /> <el-option label="" :value="0" />
<el-option label="" :value="1" /> <el-option label="" :value="1" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="主体培训任务" prop="ztpxrw"> <el-form-item label="主体培训任务" prop="ztpxrw">
<el-select v-model="form.ztpxrw" class="w-full"> <el-select v-model="form.ztpxrw" class="w-full" @change="handlePrimaryTrainingTaskChange">
<el-option label="是" :value="1" /> <el-option label="是" :value="1" />
<el-option label="否" :value="0" /> <el-option label="否" :value="0" />
</el-select> </el-select>
@@ -211,12 +246,26 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="培训任务标识号"> <el-form-item label="培训任务标识号">
<el-input v-model="form.pxrwbsh" placeholder="请输入培训任务标识号" /> <el-select
v-model="form.pxrwbsh"
:loading="trainingTaskLoading"
placeholder="请选择培训任务"
clearable
filterable
class="w-full"
>
<el-option
v-for="item in trainingTaskOptions"
:key="item.bsh"
:label="formatTrainingTaskLabel(item)"
:value="item.bsh"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="在校状态"> <el-form-item label="在校状态">
<el-select v-model="form.zxzt" class="w-full"> <el-select v-model="form.zxzt" placeholder="请选择在校状态" clearable class="w-full">
<el-option label="在校" :value="1" /> <el-option label="在校" :value="1" />
<el-option label="毕业" :value="0" /> <el-option label="毕业" :value="0" />
</el-select> </el-select>
@@ -233,9 +282,6 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="JSON字段">
<el-input v-model="form.jsonzd" placeholder="请输入 JSON 字段" />
</el-form-item>
<el-form-item label="备注"> <el-form-item label="备注">
<el-input v-model="form.bz" type="textarea" :rows="2" placeholder="请输入备注" /> <el-input v-model="form.bz" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item> </el-form-item>
@@ -266,7 +312,7 @@
<el-descriptions-item label="任务类别">{{ detailForm.rwlb || '-' }}</el-descriptions-item> <el-descriptions-item label="任务类别">{{ detailForm.rwlb || '-' }}</el-descriptions-item>
<el-descriptions-item label="虚实类型"> <el-descriptions-item label="虚实类型">
<el-tag :type="Number(detailForm.xslx) === 1 ? 'success' : 'info'" size="mini"> <el-tag :type="Number(detailForm.xslx) === 1 ? 'success' : 'info'" size="mini">
{{ Number(detailForm.xslx) === 1 ? '' : '' }} {{ Number(detailForm.xslx) === 1 ? '' : '' }}
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="主体培训任务"> <el-descriptions-item label="主体培训任务">
@@ -282,7 +328,6 @@
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="入学日期">{{ detailForm.rxrq || '-' }}</el-descriptions-item> <el-descriptions-item label="入学日期">{{ detailForm.rxrq || '-' }}</el-descriptions-item>
<el-descriptions-item label="毕业日期">{{ detailForm.byrq || '-' }}</el-descriptions-item> <el-descriptions-item label="毕业日期">{{ detailForm.byrq || '-' }}</el-descriptions-item>
<el-descriptions-item label="JSON字段" :span="2">{{ detailForm.jsonzd || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ detailForm.bz || '-' }}</el-descriptions-item> <el-descriptions-item label="备注" :span="2">{{ detailForm.bz || '-' }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</div> </div>
@@ -301,10 +346,17 @@ import {
addTeam, addTeam,
updateTeam, updateTeam,
delTeam, delTeam,
listTrainingTasks,
importTeam, importTeam,
exportTeam, exportTeam,
downloadTeamTemplate downloadTeamTemplate
} from '@/api/studentRecords/team' } from '@/api/studentRecords/team'
import { getDicts } from '@/api/system/dict/data'
const TEAM_TYPE_DICT_CODE = 'stu_type'
const SESSION_CATEGORY_DICT_CODE = 'session_category'
const SYSTEM_MODE_DICT_CODE = 'system_mode'
const UNIT_CATEGORY_DICT_CODE = 'sys_unit_category'
export default { export default {
name: 'ShiftTeamIndex', name: 'ShiftTeamIndex',
@@ -319,6 +371,12 @@ export default {
rwlb: '', rwlb: '',
xslx: undefined xslx: undefined
}, },
teamTypeOptions: [],
sessionCategoryOptions: [],
systemModeOptions: [],
unitCategoryOptions: [],
trainingTaskOptions: [],
trainingTaskLoading: false,
// ==================== 文件导入 ==================== // ==================== 文件导入 ====================
selectedFile: null, selectedFile: null,
@@ -346,9 +404,9 @@ export default {
xslx: [{ required: true, message: '请选择虚实类型', trigger: 'change' }], xslx: [{ required: true, message: '请选择虚实类型', trigger: 'change' }],
rxrq: [{ required: true, message: '请选择入学日期', trigger: 'change' }], rxrq: [{ required: true, message: '请选择入学日期', trigger: 'change' }],
byrq: [{ required: true, message: '请选择毕业日期', trigger: 'change' }], byrq: [{ required: true, message: '请选择毕业日期', trigger: 'change' }],
xydlx: [{ required: true, message: '请输入学员队类型', trigger: 'blur' }], xydlx: [{ required: true, message: '请选择学员队类型', trigger: 'change' }],
jclb: [{ required: true, message: '请输入节次类别', trigger: 'blur' }], jclb: [{ required: true, message: '请选择节次类别', trigger: 'change' }],
xtms: [{ required: true, message: '请输入系统模式', trigger: 'blur' }], xtms: [{ required: true, message: '请选择系统模式', trigger: 'change' }],
ztpxrw: [{ required: true, message: '请选择主体培训任务', trigger: 'change' }] ztpxrw: [{ required: true, message: '请选择主体培训任务', trigger: 'change' }]
}, },
@@ -364,9 +422,25 @@ export default {
} }
}, },
mounted() { mounted() {
this.loadTeamDictionaries()
this.fetchList() this.fetchList()
}, },
methods: { methods: {
/** 加载学员队相关字典。 */
async loadTeamDictionaries() {
const emptyResponse = { data: [] }
const [teamTypeResponse, sessionCategoryResponse, systemModeResponse, unitCategoryResponse] = await Promise.all([
getDicts(TEAM_TYPE_DICT_CODE).catch(() => emptyResponse),
getDicts(SESSION_CATEGORY_DICT_CODE).catch(() => emptyResponse),
getDicts(SYSTEM_MODE_DICT_CODE).catch(() => emptyResponse),
getDicts(UNIT_CATEGORY_DICT_CODE).catch(() => emptyResponse)
])
this.teamTypeOptions = teamTypeResponse.data || []
this.sessionCategoryOptions = sessionCategoryResponse.data || []
this.systemModeOptions = systemModeResponse.data || []
this.unitCategoryOptions = unitCategoryResponse.data || []
},
createEmptyForm() { createEmptyForm() {
return { return {
xydbh: '', xydbh: '',
@@ -376,7 +450,7 @@ export default {
zydh: '', zydh: '',
zyjsbh: '', zyjsbh: '',
bz: '', bz: '',
zxzt: 1, zxzt: undefined,
xh: undefined, xh: undefined,
rwlb: '', rwlb: '',
xslx: 1, xslx: 1,
@@ -402,6 +476,17 @@ export default {
return val === null || val === undefined || val === '' ? '-' : val return val === null || val === undefined || val === '' ? '-' : val
}, },
normalizeSchoolStatus(value) {
if (value === 1 || value === '1' || value === '在校') {
return 1
}
if (value === 0 || value === '0' || value === '毕业') {
return 0
}
return undefined
},
/** 构建查询条件(不含分页),供列表查询与导出共用 */ /** 构建查询条件(不含分页),供列表查询与导出共用 */
buildQuery() { buildQuery() {
const params = {} const params = {}
@@ -464,6 +549,7 @@ export default {
this.isAdd = true this.isAdd = true
this.dialogTitle = '新增学员队' this.dialogTitle = '新增学员队'
this.form = this.createEmptyForm() this.form = this.createEmptyForm()
this.loadTrainingTaskOptions(this.form.ztpxrw)
this.formDialogVisible = true this.formDialogVisible = true
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate() this.$refs.formRef && this.$refs.formRef.clearValidate()
@@ -488,7 +574,7 @@ export default {
zydh: d.zydh || '', zydh: d.zydh || '',
zyjsbh: d.zyjsbh || '', zyjsbh: d.zyjsbh || '',
bz: d.bz || '', bz: d.bz || '',
zxzt: d.zxzt !== null && d.zxzt !== undefined ? Number(d.zxzt) : 1, zxzt: this.normalizeSchoolStatus(d.zxzt),
xh: d.xh !== null && d.xh !== undefined ? d.xh : undefined, xh: d.xh !== null && d.xh !== undefined ? d.xh : undefined,
rwlb: d.rwlb || '', rwlb: d.rwlb || '',
xslx: d.xslx !== null && d.xslx !== undefined ? Number(d.xslx) : 1, xslx: d.xslx !== null && d.xslx !== undefined ? Number(d.xslx) : 1,
@@ -503,9 +589,36 @@ export default {
ssdw: d.ssdw || '', ssdw: d.ssdw || '',
ztpxrw: d.ztpxrw !== null && d.ztpxrw !== undefined ? Number(d.ztpxrw) : 1 ztpxrw: d.ztpxrw !== null && d.ztpxrw !== undefined ? Number(d.ztpxrw) : 1
} }
this.loadTrainingTaskOptions(this.form.ztpxrw)
}).catch(() => {}) }).catch(() => {})
}, },
/** 按主体培训任务标志加载后端培训任务选项。 */
async loadTrainingTaskOptions(ztpxrw) {
this.trainingTaskLoading = true
try {
const response = await listTrainingTasks(ztpxrw)
this.trainingTaskOptions = Array.isArray(response.data) ? response.data : []
} catch (error) {
this.trainingTaskOptions = []
} finally {
this.trainingTaskLoading = false
}
},
handlePrimaryTrainingTaskChange(ztpxrw) {
this.form.pxrwbsh = ''
this.loadTrainingTaskOptions(ztpxrw)
},
formatTrainingTaskLabel(item) {
if (!item.mc) {
return item.bsh
}
return `${item.mc}${item.bsh}`
},
buildPayload() { buildPayload() {
const f = this.form const f = this.form
const payload = { const payload = {
@@ -516,16 +629,17 @@ export default {
xydlx: f.xydlx, xydlx: f.xydlx,
jclb: f.jclb, jclb: f.jclb,
xtms: f.xtms, xtms: f.xtms,
zxzt: Number(f.zxzt),
xslx: Number(f.xslx), xslx: Number(f.xslx),
ztpxrw: Number(f.ztpxrw) ztpxrw: Number(f.ztpxrw)
} }
// 数值字段 // 数值字段
if (f.xydrs !== '' && f.xydrs !== null && f.xydrs !== undefined) payload.xydrs = Number(f.xydrs) if (f.xydrs !== '' && f.xydrs !== null && f.xydrs !== undefined) payload.xydrs = Number(f.xydrs)
if (f.xh !== '' && f.xh !== null && f.xh !== undefined) payload.xh = Number(f.xh) // 字符串字段
// 日期字段 if (f.zxzt !== '' && f.zxzt !== null && f.zxzt !== undefined) payload.zxzt = String(f.zxzt)
if (f.rxrq) payload.rxrq = f.rxrq if (f.xh !== '' && f.xh !== null && f.xh !== undefined) payload.xh = String(f.xh)
if (f.byrq) payload.byrq = f.byrq // 后端字段为 LocalDateTime,日期选择器值统一补齐当天零点。
if (f.rxrq) payload.rxrq = `${this.formatDate(f.rxrq)}T00:00:00`
if (f.byrq) payload.byrq = `${this.formatDate(f.byrq)}T00:00:00`
// 其余文本字段非空才传 // 其余文本字段非空才传
;['nj', 'zyjsbh', 'pxrwbsh', 'jsonzd', 'jc', 'ssdw', 'bz'].forEach(key => { ;['nj', 'zyjsbh', 'pxrwbsh', 'jsonzd', 'jc', 'ssdw', 'bz'].forEach(key => {
if (f[key] !== '' && f[key] !== null && f[key] !== undefined) { if (f[key] !== '' && f[key] !== null && f[key] !== undefined) {
@@ -635,14 +749,14 @@ export default {
} }
.shift-team-page { .shift-team-page {
.w-full {
width: 100%;
}
.search-card { .search-card {
margin-bottom: 16px; margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions-row { .search-actions-row {
margin-top: 2px; margin-top: 2px;
border-top: 1px dashed #ebeef5; border-top: 1px dashed #ebeef5;
@@ -106,9 +106,6 @@
@update:visible="val => formDialogVisible = val" @update:visible="val => formDialogVisible = val"
> >
<el-form ref="formRef" :model="form" :rules="formRules" label-width="110px" class="add-form"> <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="xh"> <el-form-item label="学号" prop="xh">
<el-input <el-input
ref="studentNoInput" ref="studentNoInput"
@@ -134,11 +131,6 @@
<el-form-item label="备注"> <el-form-item label="备注">
<el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" /> <el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item> </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> </el-form>
<div slot="footer"> <div slot="footer">
<el-button @click="formDialogVisible = false">取消</el-button> <el-button @click="formDialogVisible = false">取消</el-button>
@@ -270,11 +262,13 @@ export default {
verifiedStudentNo: '', verifiedStudentNo: '',
form: this.createEmptyForm(), form: this.createEmptyForm(),
formRules: { formRules: {
bh: [{ required: true, message: '请输入编号', trigger: 'blur' }], xh: [
xh: [{ required: true, message: '请输入学号', trigger: 'blur' }], { required: true, message: '请输入学号', trigger: 'blur' },
{ max: 50, message: '学号不能超过50个字符', trigger: 'blur' },
{ pattern: /^[A-Za-z0-9]+$/, message: '学号只能包含字母和数字', trigger: 'blur' }
],
sqlx: [{ required: true, message: '请选择申请类型', trigger: 'change' }], sqlx: [{ required: true, message: '请选择申请类型', trigger: 'change' }],
sy: [{ required: true, message: '请输入事由', trigger: 'blur' }], sy: [{ required: true, message: '请输入事由', trigger: 'blur' }]
zt: [{ required: true, message: '请选择状态', trigger: 'change' }]
}, },
// ==================== 详情 ==================== // ==================== 详情 ====================
@@ -543,11 +537,16 @@ export default {
buildPayload() { buildPayload() {
const f = this.form const f = this.form
const payload = { const payload = {
bh: f.bh,
xybh: f.xybh, xybh: f.xybh,
sqlx: f.sqlx, sqlx: f.sqlx,
sy: f.sy, sy: f.sy
zt: Number(f.zt) }
// 新增编号和状态由后端生成;编辑时仅回传记录定位编号和原状态。
if (!this.isAdd) {
payload.bh = f.bh
if (f.zt !== null && f.zt !== undefined && f.zt !== '') {
payload.zt = Number(f.zt)
}
} }
// 备注留空则移除 // 备注留空则移除
if (f.bz !== '' && f.bz !== null && f.bz !== undefined) { if (f.bz !== '' && f.bz !== null && f.bz !== undefined) {
+230 -30
View File
@@ -77,8 +77,15 @@
<el-form-item label="本科毕业院校"> <el-form-item label="本科毕业院校">
<el-input v-model="searchForm.bkbyyx" placeholder="请输入本科毕业院校" clearable /> <el-input v-model="searchForm.bkbyyx" placeholder="请输入本科毕业院校" clearable />
</el-form-item> </el-form-item>
<el-form-item label="标签"> <el-form-item label="学员类别">
<el-input v-model="searchForm.bq" placeholder="请输入标签" clearable /> <el-select v-model="searchForm.xylb" placeholder="请选择学员类别" clearable filterable class="full-width">
<el-option
v-for="item in studentCategoryOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="联系电话"> <el-form-item label="联系电话">
<el-input v-model="searchForm.lxdh" placeholder="请输入联系电话" clearable /> <el-input v-model="searchForm.lxdh" placeholder="请输入联系电话" clearable />
@@ -150,7 +157,7 @@
@update:visible="val => dialogVisible = val" @update:visible="val => dialogVisible = val"
> >
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px"> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px">
<el-row :gutter="20"> <el-row v-if="dialogTitle !== '新增学员'" :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="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-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>
@@ -160,15 +167,59 @@
</el-row> </el-row>
<el-row :gutter="20"> <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="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-col :span="12">
<el-form-item label="民族" prop="mz">
<el-select v-model="formData.mz" placeholder="请选择民族" filterable class="full-width">
<el-option
v-for="item in nationOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-row :gutter="20"> <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="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-col :span="12">
<el-form-item label="政治面貌" prop="zzmm">
<el-select v-model="formData.zzmm" placeholder="请选择政治面貌" filterable class="full-width">
<el-option
v-for="item in politicalStatusOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-row :gutter="20"> <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-col :span="12"><el-form-item label="学员类别" prop="xylb"><el-input v-model="formData.xylb" placeholder="请输入学员类别" /></el-form-item></el-col> <el-form-item label="文化程度" prop="whcd">
<el-select v-model="formData.whcd" placeholder="请选择文化程度" filterable class="full-width">
<el-option
v-for="item in educationLevelOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学员类别" prop="xylb">
<el-select v-model="formData.xylb" placeholder="请选择学员类别" filterable class="full-width">
<el-option
v-for="item in studentCategoryOptions"
:key="item.dictCode || item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-row :gutter="20"> <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="xydqbh"><el-input v-model="formData.xydqbh" placeholder="请输入学员队期编号" /></el-form-item></el-col>
@@ -180,12 +231,12 @@
</el-row> </el-row>
<el-row :gutter="20"> <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="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-col v-if="dialogTitle !== '新增学员'" :span="12"><el-form-item label="退学状态" prop="txzt"><el-input v-model="formData.txzt" placeholder="请输入退学状态" /></el-form-item></el-col>
</el-row> </el-row>
<el-row :gutter="20"> <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="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 v-if="dialogTitle !== '新增学员'" :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-col v-if="dialogTitle !== '新增学员'" :span="8"><el-form-item label="分班状态" prop="fbzt"><el-input v-model="formData.fbzt" placeholder="请输入" /></el-form-item></el-col>
</el-row> </el-row>
<el-row :gutter="20"> <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="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>
@@ -217,10 +268,21 @@
<div class="student-summary"> <div class="student-summary">
<span><strong>学员</strong>{{ gradesStudent || '-' }}</span> <span><strong>学员</strong>{{ gradesStudent || '-' }}</span>
<span><strong>学号</strong>{{ gradesStudentNo || '-' }}</span> <span><strong>学号</strong>{{ gradesStudentNo || '-' }}</span>
<div class="grades-year-filter">
<span class="filter-label">年度</span>
<el-select v-model="gradesYear" size="small" clearable placeholder="全部年度">
<el-option
v-for="year in gradeYearOptions"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
</div> </div>
<el-tabs v-model="gradesTab"> <el-tabs v-model="gradesTab">
<el-tab-pane label="成绩" name="grades"> <el-tab-pane label="成绩" name="grades">
<el-table v-loading="gradesLoading" :data="gradesData" stripe border max-height="420"> <el-table v-loading="gradesLoading" :data="filteredGradesData" stripe border max-height="420">
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="nd" label="年度" width="85" align="center" /> <el-table-column prop="nd" label="年度" width="85" align="center" />
<el-table-column prop="kmbh" label="科目编号" min-width="120" align="center" show-overflow-tooltip /> <el-table-column prop="kmbh" label="科目编号" min-width="120" align="center" show-overflow-tooltip />
@@ -235,11 +297,10 @@
<el-table-column label="考试结果" width="90" align="center"> <el-table-column label="考试结果" width="90" align="center">
<template slot-scope="{ row }">{{ formatPassStatus(row.ytg) }}</template> <template slot-scope="{ row }">{{ formatPassStatus(row.ytg) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="bz" label="备注" min-width="120" align="center" show-overflow-tooltip />
</el-table> </el-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="进程成绩" name="process"> <el-tab-pane label="进程成绩" name="process">
<el-table v-loading="gradesLoading" :data="processGradesData" stripe border max-height="420"> <el-table v-loading="gradesLoading" :data="filteredProcessGradesData" stripe border max-height="420">
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="nd" label="年度" width="85" align="center" /> <el-table-column prop="nd" label="年度" width="85" align="center" />
<el-table-column prop="kmbh" label="科目编号" min-width="120" align="center" show-overflow-tooltip /> <el-table-column prop="kmbh" label="科目编号" min-width="120" align="center" show-overflow-tooltip />
@@ -251,7 +312,6 @@
<el-table-column prop="bkcj3" label="补考成绩3" width="100" align="center" /> <el-table-column prop="bkcj3" label="补考成绩3" width="100" align="center" />
<el-table-column prop="bkcs" label="补考次数" width="90" align="center" /> <el-table-column prop="bkcs" label="补考次数" width="90" align="center" />
<el-table-column prop="ksqk" label="考试情况" width="100" align="center" /> <el-table-column prop="ksqk" label="考试情况" width="100" align="center" />
<el-table-column prop="bz" label="备注" min-width="120" align="center" show-overflow-tooltip />
</el-table> </el-table>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@@ -277,26 +337,82 @@ import {
exportStudentProcessGrades exportStudentProcessGrades
} from "@/api/studentRecords/studentRecords" } from "@/api/studentRecords/studentRecords"
import { getDicts } from '@/api/system/dict/data' import { getDicts } from '@/api/system/dict/data'
import { optionselect } from '@/api/system/dict/type'
const POLITICAL_STATUS_DICT_CODE = 'sys_political_status' const POLITICAL_STATUS_DICT_CODE = 'sys_political_status'
const NATION_DICT_CODE = 'nation_type' const NATION_DICT_CODE = 'nation_type'
const DEGREE_DICT_CODE = 'sys_degree_type' const DEGREE_DICT_CODE = 'sys_degree_type'
const EDUCATION_LEVEL_DICT_CODE = 'sys_edu_level' const EDUCATION_LEVEL_DICT_CODE = 'sys_edu_level'
const GRADES_VIEW_DISABLED_VALUES = new Set(['0', 'false', '否', '不允许'])
const RESIDENT_IDENTITY_CARD_TYPES = new Set(['居民身份证', '身份证'])
const IDENTITY_CARD_CHECK_CODES = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
const IDENTITY_CARD_WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const PHONE_NUMBER_PATTERN = /^(1[3-9]\d{9}|0\d{2,3}-?\d{7,8})$/
function isResidentIdentityCardType(certificateType) {
return RESIDENT_IDENTITY_CARD_TYPES.has(String(certificateType || '').trim())
}
function isValidIdentityCard(identityCard) {
const normalizedValue = String(identityCard || '').trim().toUpperCase()
if (!/^\d{17}[\dX]$/.test(normalizedValue)) {
return false
}
const year = Number(normalizedValue.slice(6, 10))
const month = Number(normalizedValue.slice(10, 12))
const day = Number(normalizedValue.slice(12, 14))
const birthDate = new Date(year, month - 1, day)
const isValidDate = birthDate.getFullYear() === year &&
birthDate.getMonth() === month - 1 && birthDate.getDate() === day
if (!isValidDate || birthDate > new Date()) {
return false
}
const checksum = IDENTITY_CARD_WEIGHTS.reduce((total, weight, index) => {
return total + Number(normalizedValue[index]) * weight
}, 0)
return IDENTITY_CARD_CHECK_CODES[checksum % 11] === normalizedValue[17]
}
export default { export default {
name: 'StudentInfoIndex', name: 'StudentInfoIndex',
data() { data() {
const validateCertificateNumber = (rule, value, callback) => {
if (value && isResidentIdentityCardType(this.formData.jrzjlx) && !isValidIdentityCard(value)) {
callback(new Error('请输入合法的18位居民身份证号码'))
return
}
callback()
}
const validateBirthDate = (rule, value, callback) => {
if (value && new Date(`${value}T00:00:00`) > new Date()) {
callback(new Error('出生日期不能晚于今天'))
return
}
callback()
}
const validatePhoneNumber = (rule, value, callback) => {
if (value && !PHONE_NUMBER_PATTERN.test(String(value).trim())) {
callback(new Error('请输入正确的手机号码或固定电话号码'))
return
}
callback()
}
return { return {
// ==================== 查询条件 ==================== // ==================== 查询条件 ====================
// 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件 // 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件
searchForm: { searchForm: {
xh: '', xm: '', xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '', xh: '', xm: '', xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '',
ybzb: '', sfzh: '', whcd: '', bkbyyx: '', bq: '', lxdh: '', txdz: '' ybzb: '', sfzh: '', whcd: '', bkbyyx: '', xylb: '', lxdh: '', txdz: ''
}, },
politicalStatusOptions: [], politicalStatusOptions: [],
nationOptions: [], nationOptions: [],
degreeOptions: [], degreeOptions: [],
educationLevelOptions: [], educationLevelOptions: [],
studentCategoryOptions: [],
// ==================== 数据表格 ==================== // ==================== 数据表格 ====================
loading: false, loading: false,
@@ -309,27 +425,29 @@ export default {
submitting: false, submitting: false,
formData: this.createEmptyForm(), formData: this.createEmptyForm(),
formRules: { formRules: {
bh: [{ required: true, message: '请输入编号', trigger: 'blur' }],
xh: [{ required: true, message: '请输入学号', trigger: 'blur' }],
xm: [{ required: true, message: '请输入姓名', trigger: 'blur' }], xm: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
xydqbh: [{ required: true, message: '请输入学员队期编号', trigger: 'blur' }], xydqbh: [{ required: true, message: '请输入学员队期编号', trigger: 'blur' }],
zjhm: [{ required: true, message: '请输入证件号码', trigger: 'blur' }], zjhm: [
zzmm: [{ required: true, message: '请输入政治面貌', trigger: 'blur' }], { required: true, message: '请输入证件号码', trigger: 'blur' },
{ validator: validateCertificateNumber, trigger: 'blur' }
],
zzmm: [{ required: true, message: '请选择政治面貌', trigger: 'change' }],
xb: [{ required: true, message: '请选择性别', trigger: 'change' }], xb: [{ required: true, message: '请选择性别', trigger: 'change' }],
csrq: [{ required: true, message: '请选择出生日期', trigger: 'change' }], csrq: [
mz: [{ required: true, message: '请输入民族', trigger: 'blur' }], { required: true, message: '请选择出生日期', trigger: 'change' },
{ validator: validateBirthDate, trigger: 'change' }
],
mz: [{ required: true, message: '请选择民族', trigger: 'change' }],
jg: [{ required: true, message: '请输入籍贯', trigger: 'blur' }], jg: [{ required: true, message: '请输入籍贯', trigger: 'blur' }],
whcd: [{ required: true, message: '请输入文化程度', trigger: 'blur' }], whcd: [{ required: true, message: '请选择文化程度', trigger: 'change' }],
xylb: [{ required: true, message: '请输入学员类别', trigger: 'blur' }], xylb: [{ required: true, message: '请选择学员类别', trigger: 'change' }],
ssjq: [{ required: true, message: '请输入所属军区', trigger: 'blur' }], ssjq: [{ required: true, message: '请输入所属军区', trigger: 'blur' }],
gfs: [{ required: true, message: '请选择国防生', trigger: 'change' }], 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' }], yxckcj: [{ required: true, message: '请选择允许查看成绩', trigger: 'change' }],
dqbzbh: [{ required: true, message: '请输入当前班次编号', trigger: 'blur' }], dqbzbh: [{ required: true, message: '请输入当前班次编号', trigger: 'blur' }],
yzc: [{ required: true, message: '请选择已注册', trigger: 'change' }], yzc: [{ required: true, message: '请选择已注册', trigger: 'change' }],
jrzjlx: [{ required: true, message: '请输入军人证件类型', trigger: 'blur' }] jrzjlx: [{ required: true, message: '请输入军人证件类型', trigger: 'blur' }],
lxdh: [{ validator: validatePhoneNumber, trigger: 'blur' }]
}, },
// ==================== 成绩弹窗 ==================== // ==================== 成绩弹窗 ====================
@@ -337,6 +455,7 @@ export default {
gradesTab: 'grades', gradesTab: 'grades',
gradesData: [], gradesData: [],
processGradesData: [], processGradesData: [],
gradesYear: '',
gradesStudent: '', gradesStudent: '',
gradesStudentNo: '', gradesStudentNo: '',
currentBh: '', currentBh: '',
@@ -344,6 +463,22 @@ export default {
gradesExporting: false gradesExporting: false
} }
}, },
computed: {
gradeYearOptions() {
const years = [...this.gradesData, ...this.processGradesData]
.map(item => item.nd)
.filter(year => year !== '' && year !== null && year !== undefined)
.map(String)
return [...new Set(years)].sort((firstYear, secondYear) => secondYear.localeCompare(firstYear))
},
filteredGradesData() {
return this.filterGradesByYear(this.gradesData)
},
filteredProcessGradesData() {
return this.filterGradesByYear(this.processGradesData)
}
},
created() { created() {
this.loadStudentDictionaries() this.loadStudentDictionaries()
}, },
@@ -354,27 +489,45 @@ export default {
/** 加载学员基础信息字典,业务字段按字典标签查询和提交。 */ /** 加载学员基础信息字典,业务字段按字典标签查询和提交。 */
async loadStudentDictionaries() { async loadStudentDictionaries() {
const emptyResponse = { data: [] } const emptyResponse = { data: [] }
const [politicalStatusResponse, nationResponse, degreeResponse, educationLevelResponse] = const [politicalStatusResponse, nationResponse, degreeResponse, educationLevelResponse, dictTypeResponse] =
await Promise.all([ await Promise.all([
getDicts(POLITICAL_STATUS_DICT_CODE).catch(() => emptyResponse), getDicts(POLITICAL_STATUS_DICT_CODE).catch(() => emptyResponse),
getDicts(NATION_DICT_CODE).catch(() => emptyResponse), getDicts(NATION_DICT_CODE).catch(() => emptyResponse),
getDicts(DEGREE_DICT_CODE).catch(() => emptyResponse), getDicts(DEGREE_DICT_CODE).catch(() => emptyResponse),
getDicts(EDUCATION_LEVEL_DICT_CODE).catch(() => emptyResponse) getDicts(EDUCATION_LEVEL_DICT_CODE).catch(() => emptyResponse),
optionselect().catch(() => emptyResponse)
]) ])
this.politicalStatusOptions = politicalStatusResponse.data || [] this.politicalStatusOptions = politicalStatusResponse.data || []
this.nationOptions = nationResponse.data || [] this.nationOptions = nationResponse.data || []
this.degreeOptions = degreeResponse.data || [] this.degreeOptions = degreeResponse.data || []
this.educationLevelOptions = educationLevelResponse.data || [] this.educationLevelOptions = educationLevelResponse.data || []
this.studentCategoryOptions = await this.loadNamedDictionary(dictTypeResponse.data || [], '学员类别')
this.mergeExistingDictionaryOptions() this.mergeExistingDictionaryOptions()
}, },
/** 根据字典名称匹配类型编码,避免业务页面硬编码数据库配置。 */
async loadNamedDictionary(dictTypes, dictName) {
const dictType = dictTypes.find(item => item.dictName === dictName) ||
dictTypes.find(item => String(item.dictName || '').includes(dictName))
if (!dictType || !dictType.dictType) {
return []
}
try {
const response = await getDicts(dictType.dictType)
return response.data || []
} catch (error) {
return []
}
},
/** 字典缺项时保留列表已有值,避免历史数据无法作为查询条件。 */ /** 字典缺项时保留列表已有值,避免历史数据无法作为查询条件。 */
mergeExistingDictionaryOptions() { mergeExistingDictionaryOptions() {
this.politicalStatusOptions = this.mergeFieldOptions(this.politicalStatusOptions, 'zzmm') this.politicalStatusOptions = this.mergeFieldOptions(this.politicalStatusOptions, 'zzmm')
this.nationOptions = this.mergeFieldOptions(this.nationOptions, 'mz') this.nationOptions = this.mergeFieldOptions(this.nationOptions, 'mz')
this.degreeOptions = this.mergeFieldOptions(this.degreeOptions, 'xw') this.degreeOptions = this.mergeFieldOptions(this.degreeOptions, 'xw')
this.educationLevelOptions = this.mergeFieldOptions(this.educationLevelOptions, 'whcd') this.educationLevelOptions = this.mergeFieldOptions(this.educationLevelOptions, 'whcd')
this.studentCategoryOptions = this.mergeFieldOptions(this.studentCategoryOptions, 'xylb')
}, },
mergeFieldOptions(dictionaryOptions, fieldName) { mergeFieldOptions(dictionaryOptions, fieldName) {
@@ -427,7 +580,9 @@ export default {
/** 组装查询参数:仅传后端 XYXX 实体支持的字符串字段,空值忽略 */ /** 组装查询参数:仅传后端 XYXX 实体支持的字符串字段,空值忽略 */
buildQueryParams(params) { buildQueryParams(params) {
const textFields = ['xh', 'xm', 'zjhm', 'zzmm', 'mz', 'jg', 'xw', 'ybzb', 'sfzh', 'whcd', 'bkbyyx', 'bq', 'lxdh', 'txdz'] const textFields = [
'xh', 'xm', 'zjhm', 'zzmm', 'mz', 'jg', 'xw', 'ybzb', 'sfzh', 'whcd', 'bkbyyx', 'xylb', 'lxdh', 'txdz'
]
textFields.forEach(key => { textFields.forEach(key => {
const v = this.searchForm[key] const v = this.searchForm[key]
if (v !== '' && v !== null && v !== undefined) params[key] = v.trim() if (v !== '' && v !== null && v !== undefined) params[key] = v.trim()
@@ -488,6 +643,13 @@ export default {
this.submitting = true this.submitting = true
const isAdd = this.dialogTitle === '新增学员' const isAdd = this.dialogTitle === '新增学员'
const payload = { ...this.formData } const payload = { ...this.formData }
if (isAdd) {
delete payload.bh
delete payload.xh
delete payload.txzt
delete payload.ljzt
delete payload.fbzt
}
const request = isAdd ? addStudentRecord(payload) : updateStudentRecord(payload) const request = isAdd ? addStudentRecord(payload) : updateStudentRecord(payload)
request.then(() => { request.then(() => {
this.$message.success(isAdd ? '新增成功' : '编辑成功') this.$message.success(isAdd ? '新增成功' : '编辑成功')
@@ -516,11 +678,20 @@ export default {
// ==================== 成绩弹窗 ==================== // ==================== 成绩弹窗 ====================
async handleGrades(row) { async handleGrades(row) {
if (this.isGradesViewDisabled(row.yxckcj)) {
this.$alert('不允许查看该学员成绩', '提示', {
confirmButtonText: '确定',
type: 'warning'
}).catch(() => {})
return
}
this.gradesStudent = row.xm || '' this.gradesStudent = row.xm || ''
this.gradesStudentNo = row.xh || '' this.gradesStudentNo = row.xh || ''
this.currentBh = row.bh || '' this.currentBh = row.bh || ''
this.gradesData = [] this.gradesData = []
this.processGradesData = [] this.processGradesData = []
this.gradesYear = ''
this.gradesTab = 'grades' this.gradesTab = 'grades'
this.gradesVisible = true this.gradesVisible = true
this.gradesLoading = true this.gradesLoading = true
@@ -549,6 +720,18 @@ export default {
return '-' return '-'
}, },
isGradesViewDisabled(value) {
return GRADES_VIEW_DISABLED_VALUES.has(String(value).trim().toLowerCase())
},
filterGradesByYear(grades) {
if (!this.gradesYear) {
return grades
}
return grades.filter(item => String(item.nd) === this.gradesYear)
},
downloadGradesFile(blob, fileName) { downloadGradesFile(blob, fileName) {
const link = document.createElement('a') const link = document.createElement('a')
link.href = URL.createObjectURL(blob) link.href = URL.createObjectURL(blob)
@@ -661,10 +844,27 @@ export default {
.student-summary { .student-summary {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center;
gap: 32px; gap: 32px;
margin-bottom: 8px; margin-bottom: 8px;
color: #303133; color: #303133;
line-height: 24px; line-height: 24px;
.grades-year-filter {
display: flex;
align-items: center;
margin-left: auto;
.filter-label {
flex-shrink: 0;
margin-right: 8px;
}
.el-select {
width: 160px;
}
}
} }
} }
@@ -11,12 +11,26 @@
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
<el-form-item label="培训类型"> <el-form-item label="培训类型">
<el-input v-model="searchForm.pxlx" placeholder="请输入培训类型" clearable @keyup.enter.native="handleSearch" /> <el-select v-model="searchForm.pxlx" placeholder="请选择培训类型" clearable filterable style="width: 100%">
<el-option
v-for="item in trainingTypeOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
<el-form-item label="培训层次"> <el-form-item label="培训层次">
<el-input v-model="searchForm.pxcc" placeholder="请输入培训层次" clearable @keyup.enter.native="handleSearch" /> <el-select v-model="searchForm.pxcc" placeholder="请选择培训层次" clearable filterable style="width: 100%">
<el-option
v-for="item in trainingLevelOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8"> <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
@@ -101,12 +115,26 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="培训类型" prop="pxlx"> <el-form-item label="培训类型" prop="pxlx">
<el-input v-model="form.pxlx" placeholder="请输入培训类型" /> <el-select v-model="form.pxlx" placeholder="请选择培训类型" filterable style="width: 100%">
<el-option
v-for="item in trainingTypeOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="培训层次" prop="pxcc"> <el-form-item label="培训层次" prop="pxcc">
<el-input v-model="form.pxcc" placeholder="请输入培训层次" /> <el-select v-model="form.pxcc" placeholder="请选择培训层次" filterable style="width: 100%">
<el-option
v-for="item in trainingLevelOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictLabel"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -116,12 +144,10 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="停用" prop="ty"> <el-form-item label="停用" prop="ty">
<el-switch v-model="form.ty" :active-value="1" :inactive-value="0" active-text="是" inactive-text="否" /> <el-radio-group v-model="form.ty">
</el-form-item> <el-radio :label="0"></el-radio>
</el-col> <el-radio :label="1"></el-radio>
<el-col :span="12"> </el-radio-group>
<el-form-item label="修改时间" prop="xgsj">
<el-date-picker v-model="form.xgsj" type="datetime" placeholder="请选择修改时间" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -243,6 +269,10 @@ import {
addWarningCondition, addWarningCondition,
updateWarningCondition updateWarningCondition
} from "@/api/studentRecords/warningCondition" } from "@/api/studentRecords/warningCondition"
import { getDicts } from '@/api/system/dict/data'
const TRAINING_TYPE_DICT_CODE = 'train_type'
const TRAINING_LEVEL_DICT_CODE = 'train_level'
export default { export default {
name: "WarningCondition", name: "WarningCondition",
@@ -255,6 +285,8 @@ export default {
pxcc: '', pxcc: '',
ty: 0 ty: 0
}, },
trainingTypeOptions: [],
trainingLevelOptions: [],
// ==================== 列表数据 ==================== // ==================== 列表数据 ====================
loading: false, loading: false,
@@ -272,8 +304,7 @@ export default {
formRules: { formRules: {
mc: [{ required: true, message: "名称不能为空", trigger: "blur" }], mc: [{ required: true, message: "名称不能为空", trigger: "blur" }],
ty: [{ required: true, message: "停用不能为空", trigger: "change" }], ty: [{ required: true, message: "停用不能为空", trigger: "change" }],
bb: [{ required: true, message: "版本不能为空", trigger: "blur" }], bb: [{ required: true, message: "版本不能为空", trigger: "blur" }]
xgsj: [{ required: true, message: "修改时间不能为空", trigger: "change" }]
}, },
// ==================== 详情 ==================== // ==================== 详情 ====================
@@ -283,9 +314,21 @@ export default {
} }
}, },
created() { created() {
this.loadTrainingDictionaries()
this.fetchList() this.fetchList()
}, },
methods: { methods: {
/** 加载培训类型、培训层次字典。 */
async loadTrainingDictionaries() {
const emptyResponse = { data: [] }
const [typeResponse, levelResponse] = await Promise.all([
getDicts(TRAINING_TYPE_DICT_CODE).catch(() => emptyResponse),
getDicts(TRAINING_LEVEL_DICT_CODE).catch(() => emptyResponse)
])
this.trainingTypeOptions = typeResponse.data || []
this.trainingLevelOptions = levelResponse.data || []
},
/** 创建空表单 */ /** 创建空表单 */
createEmptyForm() { createEmptyForm() {
return { return {
@@ -305,8 +348,7 @@ export default {
qbbjgmssx: undefined, qbbjgmssx: undefined,
qbbjgmsxx: undefined, qbbjgmsxx: undefined,
ty: 0, ty: 0,
bb: '', bb: ''
xgsj: ''
} }
}, },
@@ -398,7 +440,7 @@ export default {
'qbksbjgmssx', 'qbksbjgmsxx', 'qbksbjgmssx', 'qbksbjgmsxx',
'qbkcbjgmssx', 'qbkcbjgmsxx', 'qbkcbjgmssx', 'qbkcbjgmsxx',
'qbbjgmssx', 'qbbjgmsxx', 'qbbjgmssx', 'qbbjgmsxx',
'bb', 'xgsj' 'bb'
] ]
const result = this.createEmptyForm() const result = this.createEmptyForm()
fieldKeys.forEach(key => { fieldKeys.forEach(key => {
@@ -191,13 +191,6 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="JSON字段">
<el-input v-model="form.jsonzd" placeholder="请输入JSON字段" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注"> <el-form-item label="备注">
<el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" /> <el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item> </el-form-item>
@@ -233,7 +226,6 @@
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="停用时间">{{ detailForm.tysj || '-' }}</el-descriptions-item> <el-descriptions-item label="停用时间">{{ detailForm.tysj || '-' }}</el-descriptions-item>
<el-descriptions-item label="JSON字段" :span="2">{{ detailForm.jsonzd || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ detailForm.bz || '-' }}</el-descriptions-item> <el-descriptions-item label="备注" :span="2">{{ detailForm.bz || '-' }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</div> </div>
@@ -253,11 +253,6 @@
<el-input-number v-model="form.xhbs" :min="0" controls-position="right" style="width: 100%" placeholder="请输入序号标识" /> <el-input-number v-model="form.xhbs" :min="0" controls-position="right" style="width: 100%" placeholder="请输入序号标识" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="JSON字段">
<el-input v-model="form.jsonzd" placeholder="请输入JSON字段" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="停用" prop="ty"> <el-form-item label="停用" prop="ty">
<el-switch v-model="form.ty" :active-value="1" :inactive-value="0" active-text="是" inactive-text="否" /> <el-switch v-model="form.ty" :active-value="1" :inactive-value="0" active-text="是" inactive-text="否" />
@@ -330,7 +325,6 @@
{{ viewForm.ty === 1 || viewForm.ty === true ? '是' : '否' }} {{ viewForm.ty === 1 || viewForm.ty === true ? '是' : '否' }}
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="JSON字段">{{ viewForm.jsonzd || '-' }}</el-descriptions-item>
<el-descriptions-item label="培养目标" :span="2">{{ viewForm.pymb || '-' }}</el-descriptions-item> <el-descriptions-item label="培养目标" :span="2">{{ viewForm.pymb || '-' }}</el-descriptions-item>
<el-descriptions-item label="专业备注" :span="2">{{ viewForm.zybz || '-' }}</el-descriptions-item> <el-descriptions-item label="专业备注" :span="2">{{ viewForm.zybz || '-' }}</el-descriptions-item>
<el-descriptions-item label="专业规范" :span="2">{{ viewForm.zygf || '-' }}</el-descriptions-item> <el-descriptions-item label="专业规范" :span="2">{{ viewForm.zygf || '-' }}</el-descriptions-item>
-12
View File
@@ -624,11 +624,6 @@
<el-form-item label="备注"><el-input v-model="stockForm.bz" type="textarea" :rows="2" placeholder="请输入" /></el-form-item> <el-form-item label="备注"><el-input v-model="stockForm.bz" type="textarea" :rows="2" placeholder="请输入" /></el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="JSONZD"><el-input v-model="stockForm.jsonzd" placeholder="请输入" /></el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
</div> </div>
<div slot="footer"> <div slot="footer">
@@ -657,7 +652,6 @@
<el-descriptions-item label="审批人编号">{{ stockDetailData.sprbh || '-' }}</el-descriptions-item> <el-descriptions-item label="审批人编号">{{ stockDetailData.sprbh || '-' }}</el-descriptions-item>
<el-descriptions-item label="状态">{{ stockDetailData.zt || '-' }}</el-descriptions-item> <el-descriptions-item label="状态">{{ stockDetailData.zt || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ stockDetailData.bz || '-' }}</el-descriptions-item> <el-descriptions-item label="备注">{{ stockDetailData.bz || '-' }}</el-descriptions-item>
<el-descriptions-item label="JSONZD">{{ stockDetailData.jsonzd || '-' }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ fmtDateTime(stockDetailData.cjsj) || '-' }}</el-descriptions-item> <el-descriptions-item label="创建时间">{{ fmtDateTime(stockDetailData.cjsj) || '-' }}</el-descriptions-item>
<el-descriptions-item label="修改时间">{{ fmtDateTime(stockDetailData.xgsj) || '-' }}</el-descriptions-item> <el-descriptions-item label="修改时间">{{ fmtDateTime(stockDetailData.xgsj) || '-' }}</el-descriptions-item>
<el-descriptions-item label="提交时间">{{ fmtDateTime(stockDetailData.tjsj) || '-' }}</el-descriptions-item> <el-descriptions-item label="提交时间">{{ fmtDateTime(stockDetailData.tjsj) || '-' }}</el-descriptions-item>
@@ -720,11 +714,6 @@
<el-form-item label="备注"><el-input v-model="detailForm.bz" type="textarea" :rows="2" placeholder="请输入" /></el-form-item> <el-form-item label="备注"><el-input v-model="detailForm.bz" type="textarea" :rows="2" placeholder="请输入" /></el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="JSONZD"><el-input v-model="detailForm.jsonzd" placeholder="请输入" /></el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
</div> </div>
<div slot="footer"> <div slot="footer">
@@ -752,7 +741,6 @@
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="还回完毕时间">{{ fmtDateTime(detailViewData.hwbwsj) || '-' }}</el-descriptions-item> <el-descriptions-item label="还回完毕时间">{{ fmtDateTime(detailViewData.hwbwsj) || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ detailViewData.bz || '-' }}</el-descriptions-item> <el-descriptions-item label="备注">{{ detailViewData.bz || '-' }}</el-descriptions-item>
<el-descriptions-item label="JSONZD">{{ detailViewData.jsonzd || '-' }}</el-descriptions-item>
<el-descriptions-item label="快照_事务后库存数量">{{ fmtVal(detailViewData.kzswHkcsl) }}</el-descriptions-item> <el-descriptions-item label="快照_事务后库存数量">{{ fmtVal(detailViewData.kzswHkcsl) }}</el-descriptions-item>
<el-descriptions-item label="快照_事务后借出数量">{{ fmtVal(detailViewData.kzswHjcsl) }}</el-descriptions-item> <el-descriptions-item label="快照_事务后借出数量">{{ fmtVal(detailViewData.kzswHjcsl) }}</el-descriptions-item>
<el-descriptions-item label="快照_事务前库存数量">{{ fmtVal(detailViewData.kzswQkcsl) }}</el-descriptions-item> <el-descriptions-item label="快照_事务前库存数量">{{ fmtVal(detailViewData.kzswQkcsl) }}</el-descriptions-item>