diff --git a/frontend/src/api/studentRecords/application.js b/frontend/src/api/studentRecords/application.js index 33e5250d..1c64ebcc 100644 --- a/frontend/src/api/studentRecords/application.js +++ b/frontend/src/api/studentRecords/application.js @@ -21,7 +21,7 @@ export function getApplication(bh) { }) } -// 新增学籍异动申请(请求体 XYXJYDSQB 实体;bh 需前端传入,创建/修改时间后端自动维护) +// 新增学籍异动申请(编号、状态和创建/修改时间由后端维护) export function addApplication(data) { return request({ url: '/student-records/application/add', diff --git a/frontend/src/api/studentRecords/team.js b/frontend/src/api/studentRecords/team.js index 65e27b14..b36d8bc4 100644 --- a/frontend/src/api/studentRecords/team.js +++ b/frontend/src/api/studentRecords/team.js @@ -21,6 +21,15 @@ export function getTeam(xydbh) { }) } +// 根据是否为主体培训任务查询可选培训任务 +export function listTrainingTasks(ztpxrw) { + return request({ + url: '/student-records/training-tasks', + method: 'get', + params: { ztpxrw } + }) +} + // 新增学员队(请求体 XYDB) export function addTeam(data) { return request({ diff --git a/frontend/src/layout/components/SemesterBar.vue b/frontend/src/layout/components/SemesterBar.vue index c028415c..5f99f3a5 100644 --- a/frontend/src/layout/components/SemesterBar.vue +++ b/frontend/src/layout/components/SemesterBar.vue @@ -27,6 +27,7 @@ :value="activeSemester ? activeSemester.nd : ''" placeholder="请选择学期" size="small" + filterable class="semester-select" @change="handleSwitch" > diff --git a/frontend/src/views/student/shiftTeam/index.vue b/frontend/src/views/student/shiftTeam/index.vue index 620b4892..7c3c710f 100644 --- a/frontend/src/views/student/shiftTeam/index.vue +++ b/frontend/src/views/student/shiftTeam/index.vue @@ -21,7 +21,14 @@ - + + + @@ -32,8 +39,8 @@ - - + + @@ -74,7 +81,7 @@ @@ -146,7 +153,21 @@ - + + + @@ -156,17 +177,38 @@ - + + + - + + + - + + + @@ -176,12 +218,14 @@ - - - - - - + + + @@ -196,14 +240,14 @@ - - + + - + @@ -211,12 +255,26 @@ - + + + - + @@ -233,9 +291,6 @@ - - - @@ -262,11 +317,10 @@ {{ detailForm.xtms || '-' }} {{ detailForm.jc || '-' }} {{ detailForm.ssdw || '-' }} - {{ fmtValue(detailForm.xh) }} {{ detailForm.rwlb || '-' }} - {{ Number(detailForm.xslx) === 1 ? '实' : '虚' }} + {{ Number(detailForm.xslx) === 1 ? '是' : '否' }} @@ -282,7 +336,6 @@ {{ detailForm.rxrq || '-' }} {{ detailForm.byrq || '-' }} - {{ detailForm.jsonzd || '-' }} {{ detailForm.bz || '-' }} @@ -301,10 +354,19 @@ import { addTeam, updateTeam, delTeam, + listTrainingTasks, importTeam, exportTeam, downloadTeamTemplate } from '@/api/studentRecords/team' +import { getDicts } from '@/api/system/dict/data' +import { listMajor } from '@/api/subjectMajor/major' + +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' +const MAJOR_OPTION_PAGE_SIZE = 10000 export default { name: 'ShiftTeamIndex', @@ -319,6 +381,14 @@ export default { rwlb: '', xslx: undefined }, + teamTypeOptions: [], + sessionCategoryOptions: [], + systemModeOptions: [], + unitCategoryOptions: [], + majorOptions: [], + majorOptionsLoading: false, + trainingTaskOptions: [], + trainingTaskLoading: false, // ==================== 文件导入 ==================== selectedFile: null, @@ -341,14 +411,14 @@ export default { xydbh: [{ required: true, message: '请输入学员队编号', trigger: 'blur' }], xydmc: [{ required: true, message: '请输入学员队名称', trigger: 'blur' }], xydrs: [{ required: true, message: '请输入学员队人数', trigger: 'change' }], - zydh: [{ required: true, message: '请输入专业代号', trigger: 'blur' }], + zydh: [{ required: true, message: '请选择专业', trigger: 'change' }], rwlb: [{ required: true, message: '请输入任务类别', trigger: 'blur' }], xslx: [{ required: true, message: '请选择虚实类型', trigger: 'change' }], rxrq: [{ required: true, message: '请选择入学日期', trigger: 'change' }], byrq: [{ required: true, message: '请选择毕业日期', trigger: 'change' }], - xydlx: [{ required: true, message: '请输入学员队类型', trigger: 'blur' }], - jclb: [{ required: true, message: '请输入节次类别', trigger: 'blur' }], - xtms: [{ required: true, message: '请输入系统模式', trigger: 'blur' }], + xydlx: [{ required: true, message: '请选择学员队类型', trigger: 'change' }], + jclb: [{ required: true, message: '请选择节次类别', trigger: 'change' }], + xtms: [{ required: true, message: '请选择系统模式', trigger: 'change' }], ztpxrw: [{ required: true, message: '请选择主体培训任务', trigger: 'change' }] }, @@ -364,9 +434,53 @@ export default { } }, mounted() { + this.loadTeamDictionaries() + this.loadMajorOptions() this.fetchList() }, 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 || [] + }, + + /** 加载专业下拉选项,标签同时包含名称、代码和代号,便于直接模糊搜索。 */ + async loadMajorOptions() { + this.majorOptionsLoading = true + try { + const response = await listMajor({ + pageNum: 1, + pageSize: MAJOR_OPTION_PAGE_SIZE, + ty: false + }) + const data = response.data || {} + this.majorOptions = Array.isArray(data.records) ? data.records : [] + } catch (error) { + this.majorOptions = [] + } finally { + this.majorOptionsLoading = false + } + }, + + formatMajorLabel(item) { + const identifiers = [item.zydm, item.zydh].filter(Boolean).join(' / ') + if (!item.zymc) { + return identifiers + } + + return identifiers ? `${item.zymc}(${identifiers})` : item.zymc + }, + createEmptyForm() { return { xydbh: '', @@ -376,8 +490,7 @@ export default { zydh: '', zyjsbh: '', bz: '', - zxzt: 1, - xh: undefined, + zxzt: undefined, rwlb: '', xslx: 1, rxrq: '', @@ -402,6 +515,17 @@ export default { 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() { const params = {} @@ -464,6 +588,7 @@ export default { this.isAdd = true this.dialogTitle = '新增学员队' this.form = this.createEmptyForm() + this.loadTrainingTaskOptions(this.form.ztpxrw) this.formDialogVisible = true this.$nextTick(() => { this.$refs.formRef && this.$refs.formRef.clearValidate() @@ -488,8 +613,7 @@ export default { zydh: d.zydh || '', zyjsbh: d.zyjsbh || '', bz: d.bz || '', - zxzt: d.zxzt !== null && d.zxzt !== undefined ? Number(d.zxzt) : 1, - xh: d.xh !== null && d.xh !== undefined ? d.xh : undefined, + zxzt: this.normalizeSchoolStatus(d.zxzt), rwlb: d.rwlb || '', xslx: d.xslx !== null && d.xslx !== undefined ? Number(d.xslx) : 1, rxrq: this.formatDate(d.rxrq), @@ -503,9 +627,36 @@ export default { ssdw: d.ssdw || '', ztpxrw: d.ztpxrw !== null && d.ztpxrw !== undefined ? Number(d.ztpxrw) : 1 } + this.loadTrainingTaskOptions(this.form.ztpxrw) }).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() { const f = this.form const payload = { @@ -516,16 +667,16 @@ export default { xydlx: f.xydlx, jclb: f.jclb, xtms: f.xtms, - zxzt: Number(f.zxzt), xslx: Number(f.xslx), ztpxrw: Number(f.ztpxrw) } // 数值字段 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.rxrq) payload.rxrq = f.rxrq - if (f.byrq) payload.byrq = f.byrq + // 字符串字段 + if (f.zxzt !== '' && f.zxzt !== null && f.zxzt !== undefined) payload.zxzt = String(f.zxzt) + // 后端字段为 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 => { if (f[key] !== '' && f[key] !== null && f[key] !== undefined) { @@ -635,14 +786,14 @@ export default { } .shift-team-page { + .w-full { + width: 100%; + } + .search-card { margin-bottom: 16px; .search-form { - .w-full { - width: 100%; - } - .search-actions-row { margin-top: 2px; border-top: 1px dashed #ebeef5; diff --git a/frontend/src/views/student/statusChange/index.vue b/frontend/src/views/student/statusChange/index.vue index 3bfbb722..52d89ca2 100644 --- a/frontend/src/views/student/statusChange/index.vue +++ b/frontend/src/views/student/statusChange/index.vue @@ -106,9 +106,6 @@ @update:visible="val => formDialogVisible = val" > - - - - - - - -
取消 @@ -270,11 +262,13 @@ export default { verifiedStudentNo: '', form: this.createEmptyForm(), formRules: { - bh: [{ required: true, message: '请输入编号', trigger: 'blur' }], - xh: [{ required: true, message: '请输入学号', trigger: 'blur' }], + xh: [ + { 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' }], - sy: [{ required: true, message: '请输入事由', trigger: 'blur' }], - zt: [{ required: true, message: '请选择状态', trigger: 'change' }] + sy: [{ required: true, message: '请输入事由', trigger: 'blur' }] }, // ==================== 详情 ==================== @@ -543,11 +537,16 @@ export default { buildPayload() { const f = this.form const payload = { - bh: f.bh, xybh: f.xybh, sqlx: f.sqlx, - sy: f.sy, - zt: Number(f.zt) + sy: f.sy + } + // 新增编号和状态由后端生成;编辑时仅回传记录定位编号和原状态。 + 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) { diff --git a/frontend/src/views/student/studentInfo/index.vue b/frontend/src/views/student/studentInfo/index.vue index 244eaeba..e4467777 100644 --- a/frontend/src/views/student/studentInfo/index.vue +++ b/frontend/src/views/student/studentInfo/index.vue @@ -77,8 +77,15 @@ - - + + + + @@ -150,7 +157,7 @@ @update:visible="val => dialogVisible = val" > - + @@ -160,15 +167,59 @@ - + + + + + + + - + + + + + + + - - + + + + + + + + + + + + + + @@ -180,12 +231,12 @@ - + - - + + @@ -217,10 +268,21 @@
学员:{{ gradesStudent || '-' }} 学号:{{ gradesStudentNo || '-' }} +
+ 年度: + + + +
- + @@ -235,11 +297,10 @@ - - + @@ -251,7 +312,6 @@ - @@ -277,26 +337,82 @@ import { exportStudentProcessGrades } from "@/api/studentRecords/studentRecords" import { getDicts } from '@/api/system/dict/data' +import { optionselect } from '@/api/system/dict/type' const POLITICAL_STATUS_DICT_CODE = 'sys_political_status' const NATION_DICT_CODE = 'nation_type' const DEGREE_DICT_CODE = 'sys_degree_type' 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 { name: 'StudentInfoIndex', 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 { // ==================== 查询条件 ==================== // 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件 searchForm: { xh: '', xm: '', xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '', - ybzb: '', sfzh: '', whcd: '', bkbyyx: '', bq: '', lxdh: '', txdz: '' + ybzb: '', sfzh: '', whcd: '', bkbyyx: '', xylb: '', lxdh: '', txdz: '' }, politicalStatusOptions: [], nationOptions: [], degreeOptions: [], educationLevelOptions: [], + studentCategoryOptions: [], // ==================== 数据表格 ==================== loading: false, @@ -309,27 +425,29 @@ export default { 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' }], + zjhm: [ + { required: true, message: '请输入证件号码', trigger: 'blur' }, + { validator: validateCertificateNumber, trigger: 'blur' } + ], + zzmm: [{ required: true, message: '请选择政治面貌', trigger: 'change' }], xb: [{ required: true, message: '请选择性别', trigger: 'change' }], - csrq: [{ required: true, message: '请选择出生日期', trigger: 'change' }], - mz: [{ required: true, message: '请输入民族', trigger: 'blur' }], + csrq: [ + { required: true, message: '请选择出生日期', trigger: 'change' }, + { validator: validateBirthDate, trigger: 'change' } + ], + mz: [{ required: true, message: '请选择民族', trigger: 'change' }], jg: [{ required: true, message: '请输入籍贯', trigger: 'blur' }], - whcd: [{ required: true, message: '请输入文化程度', trigger: 'blur' }], - xylb: [{ required: true, message: '请输入学员类别', trigger: 'blur' }], + whcd: [{ required: true, message: '请选择文化程度', trigger: 'change' }], + xylb: [{ required: true, message: '请选择学员类别', trigger: 'change' }], 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' }] + jrzjlx: [{ required: true, message: '请输入军人证件类型', trigger: 'blur' }], + lxdh: [{ validator: validatePhoneNumber, trigger: 'blur' }] }, // ==================== 成绩弹窗 ==================== @@ -337,6 +455,7 @@ export default { gradesTab: 'grades', gradesData: [], processGradesData: [], + gradesYear: '', gradesStudent: '', gradesStudentNo: '', currentBh: '', @@ -344,6 +463,22 @@ export default { 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() { this.loadStudentDictionaries() }, @@ -354,27 +489,45 @@ export default { /** 加载学员基础信息字典,业务字段按字典标签查询和提交。 */ async loadStudentDictionaries() { const emptyResponse = { data: [] } - const [politicalStatusResponse, nationResponse, degreeResponse, educationLevelResponse] = + const [politicalStatusResponse, nationResponse, degreeResponse, educationLevelResponse, dictTypeResponse] = await Promise.all([ getDicts(POLITICAL_STATUS_DICT_CODE).catch(() => emptyResponse), getDicts(NATION_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.nationOptions = nationResponse.data || [] this.degreeOptions = degreeResponse.data || [] this.educationLevelOptions = educationLevelResponse.data || [] + this.studentCategoryOptions = await this.loadNamedDictionary(dictTypeResponse.data || [], '学员类别') 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() { this.politicalStatusOptions = this.mergeFieldOptions(this.politicalStatusOptions, 'zzmm') this.nationOptions = this.mergeFieldOptions(this.nationOptions, 'mz') this.degreeOptions = this.mergeFieldOptions(this.degreeOptions, 'xw') this.educationLevelOptions = this.mergeFieldOptions(this.educationLevelOptions, 'whcd') + this.studentCategoryOptions = this.mergeFieldOptions(this.studentCategoryOptions, 'xylb') }, mergeFieldOptions(dictionaryOptions, fieldName) { @@ -427,7 +580,9 @@ export default { /** 组装查询参数:仅传后端 XYXX 实体支持的字符串字段,空值忽略 */ 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 => { const v = this.searchForm[key] if (v !== '' && v !== null && v !== undefined) params[key] = v.trim() @@ -488,6 +643,13 @@ export default { this.submitting = true const isAdd = this.dialogTitle === '新增学员' 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) request.then(() => { this.$message.success(isAdd ? '新增成功' : '编辑成功') @@ -516,11 +678,20 @@ export default { // ==================== 成绩弹窗 ==================== async handleGrades(row) { + if (this.isGradesViewDisabled(row.yxckcj)) { + this.$alert('不允许查看该学员成绩', '提示', { + confirmButtonText: '确定', + type: 'warning' + }).catch(() => {}) + return + } + this.gradesStudent = row.xm || '' this.gradesStudentNo = row.xh || '' this.currentBh = row.bh || '' this.gradesData = [] this.processGradesData = [] + this.gradesYear = '' this.gradesTab = 'grades' this.gradesVisible = true this.gradesLoading = true @@ -549,6 +720,18 @@ export default { 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) { const link = document.createElement('a') link.href = URL.createObjectURL(blob) @@ -661,10 +844,27 @@ export default { .student-summary { display: flex; + flex-wrap: wrap; + align-items: center; gap: 32px; margin-bottom: 8px; color: #303133; 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; + } + } } } diff --git a/frontend/src/views/student/warningCondition/index.vue b/frontend/src/views/student/warningCondition/index.vue index a31c3073..29992204 100644 --- a/frontend/src/views/student/warningCondition/index.vue +++ b/frontend/src/views/student/warningCondition/index.vue @@ -11,12 +11,26 @@ - + + + - + + + @@ -101,12 +115,26 @@ - + + + - + + + @@ -116,12 +144,10 @@ - - - - - - + + + +
@@ -243,6 +269,10 @@ import { addWarningCondition, updateWarningCondition } 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 { name: "WarningCondition", @@ -255,6 +285,8 @@ export default { pxcc: '', ty: 0 }, + trainingTypeOptions: [], + trainingLevelOptions: [], // ==================== 列表数据 ==================== loading: false, @@ -272,8 +304,7 @@ export default { formRules: { mc: [{ required: true, message: "名称不能为空", trigger: "blur" }], ty: [{ required: true, message: "停用不能为空", trigger: "change" }], - bb: [{ required: true, message: "版本不能为空", trigger: "blur" }], - xgsj: [{ required: true, message: "修改时间不能为空", trigger: "change" }] + bb: [{ required: true, message: "版本不能为空", trigger: "blur" }] }, // ==================== 详情 ==================== @@ -283,9 +314,21 @@ export default { } }, created() { + this.loadTrainingDictionaries() this.fetchList() }, 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() { return { @@ -305,8 +348,7 @@ export default { qbbjgmssx: undefined, qbbjgmsxx: undefined, ty: 0, - bb: '', - xgsj: '' + bb: '' } }, @@ -398,7 +440,7 @@ export default { 'qbksbjgmssx', 'qbksbjgmsxx', 'qbkcbjgmssx', 'qbkcbjgmsxx', 'qbbjgmssx', 'qbbjgmsxx', - 'bb', 'xgsj' + 'bb' ] const result = this.createEmptyForm() fieldKeys.forEach(key => { diff --git a/frontend/src/views/subjectMajor/discipline/index.vue b/frontend/src/views/subjectMajor/discipline/index.vue index 4a8b328a..d1b8e208 100644 --- a/frontend/src/views/subjectMajor/discipline/index.vue +++ b/frontend/src/views/subjectMajor/discipline/index.vue @@ -191,13 +191,6 @@
- - - - - - - @@ -233,7 +226,6 @@ {{ detailForm.tysj || '-' }} - {{ detailForm.jsonzd || '-' }} {{ detailForm.bz || '-' }}
diff --git a/frontend/src/views/subjectMajor/major/index.vue b/frontend/src/views/subjectMajor/major/index.vue index 598e346b..1ffb312c 100644 --- a/frontend/src/views/subjectMajor/major/index.vue +++ b/frontend/src/views/subjectMajor/major/index.vue @@ -253,11 +253,6 @@ - - - - - @@ -330,7 +325,6 @@ {{ viewForm.ty === 1 || viewForm.ty === true ? '是' : '否' }} - {{ viewForm.jsonzd || '-' }} {{ viewForm.pymb || '-' }} {{ viewForm.zybz || '-' }} {{ viewForm.zygf || '-' }} diff --git a/frontend/src/views/system/dict/data.vue b/frontend/src/views/system/dict/data.vue index 0acb25fe..f6ab1015 100644 --- a/frontend/src/views/system/dict/data.vue +++ b/frontend/src/views/system/dict/data.vue @@ -2,7 +2,7 @@
- + - + - + diff --git a/frontend/src/views/teachBusiness/teachingTask/index.vue b/frontend/src/views/teachBusiness/teachingTask/index.vue index 03e9075f..f0a02935 100644 --- a/frontend/src/views/teachBusiness/teachingTask/index.vue +++ b/frontend/src/views/teachBusiness/teachingTask/index.vue @@ -23,6 +23,7 @@ v-model="searchForm.nd" placeholder="请选择年度" clearable + filterable style="width: 100%" > diff --git a/frontend/src/views/teachBusiness/timetableAdjust/index.vue b/frontend/src/views/teachBusiness/timetableAdjust/index.vue index 90e5c06d..ba0f86e7 100644 --- a/frontend/src/views/teachBusiness/timetableAdjust/index.vue +++ b/frontend/src/views/teachBusiness/timetableAdjust/index.vue @@ -23,7 +23,13 @@
- + @@ -99,7 +105,13 @@ - + diff --git a/frontend/src/views/teachBusiness/timetableConflict/index.vue b/frontend/src/views/teachBusiness/timetableConflict/index.vue index dc69101a..2649f953 100644 --- a/frontend/src/views/teachBusiness/timetableConflict/index.vue +++ b/frontend/src/views/teachBusiness/timetableConflict/index.vue @@ -10,7 +10,13 @@
- + diff --git a/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue b/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue index 0320bd1f..8feae81b 100644 --- a/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue +++ b/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue @@ -24,7 +24,7 @@ - + diff --git a/frontend/src/views/teachOffice/shiftSemester/index.vue b/frontend/src/views/teachOffice/shiftSemester/index.vue index 220480e5..88c82a03 100644 --- a/frontend/src/views/teachOffice/shiftSemester/index.vue +++ b/frontend/src/views/teachOffice/shiftSemester/index.vue @@ -16,7 +16,14 @@ /> - + @@ -131,7 +138,7 @@ > - + diff --git a/frontend/src/views/teachOffice/taskPlan/index.vue b/frontend/src/views/teachOffice/taskPlan/index.vue index 42940f69..b65f48f8 100644 --- a/frontend/src/views/teachOffice/taskPlan/index.vue +++ b/frontend/src/views/teachOffice/taskPlan/index.vue @@ -16,7 +16,7 @@ /> - + @@ -109,7 +109,7 @@ - + diff --git a/frontend/src/views/textbook/index.vue b/frontend/src/views/textbook/index.vue index d409d92f..adf9ce76 100644 --- a/frontend/src/views/textbook/index.vue +++ b/frontend/src/views/textbook/index.vue @@ -624,11 +624,6 @@ - - - - -
@@ -657,7 +652,6 @@ {{ stockDetailData.sprbh || '-' }} {{ stockDetailData.zt || '-' }} {{ stockDetailData.bz || '-' }} - {{ stockDetailData.jsonzd || '-' }} {{ fmtDateTime(stockDetailData.cjsj) || '-' }} {{ fmtDateTime(stockDetailData.xgsj) || '-' }} {{ fmtDateTime(stockDetailData.tjsj) || '-' }} @@ -720,11 +714,6 @@ - - - - -
@@ -752,7 +741,6 @@ {{ fmtDateTime(detailViewData.hwbwsj) || '-' }} {{ detailViewData.bz || '-' }} - {{ detailViewData.jsonzd || '-' }} {{ fmtVal(detailViewData.kzswHkcsl) }} {{ fmtVal(detailViewData.kzswHjcsl) }} {{ fmtVal(detailViewData.kzswQkcsl) }}