1、选修课选择教室、教员等用下拉选择,

2、绑定教材落库
This commit is contained in:
2026-09-22 16:09:20 +08:00
parent cda0854ab1
commit 97ae86f9c7
4 changed files with 165 additions and 16 deletions
@@ -35,6 +35,9 @@ public class ElectiveCourseSaveDTO {
/** 教室编号 */
private String jsbh;
/** 教材名称(按名称匹配教材信息,写入课程教材关联) */
private String jcmc;
/** 计划人数 */
private Integer rs;
@@ -0,0 +1,12 @@
package com.roomroot.jwgl.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.roomroot.jwgl.entity.KCJC;
import org.apache.ibatis.annotations.Mapper;
/**
* 课程教材 Mapper
*/
@Mapper
public interface KCJCMapper extends BaseMapper<KCJC> {
}
@@ -10,9 +10,11 @@ import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.jwgl.dto.jys.ElectiveCourseImportDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery;
import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO;
import com.roomroot.jwgl.entity.JCXX;
import com.roomroot.jwgl.entity.JSB;
import com.roomroot.jwgl.entity.JYB;
import com.roomroot.jwgl.entity.KB;
import com.roomroot.jwgl.entity.KCJC;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
import com.roomroot.jwgl.entity.XYDQB;
@@ -23,7 +25,9 @@ import com.roomroot.jwgl.mapper.ClassSemesterMapper;
import com.roomroot.jwgl.mapper.ElectiveCourseMapper;
import com.roomroot.jwgl.mapper.JYBMapper;
import com.roomroot.jwgl.mapper.KBMapper;
import com.roomroot.jwgl.mapper.KCJCMapper;
import com.roomroot.jwgl.mapper.StudentTeamTaskMapper;
import com.roomroot.jwgl.mapper.TeachingMaterialMapper;
import com.roomroot.jwgl.mapper.XYDBMapper;
import com.roomroot.jwgl.mapper.XYDQBMapper;
import com.roomroot.jwgl.mapper.ZYBMapper;
@@ -93,6 +97,10 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
private ZYBMapper zybMapper;
@Resource
private ClassSemesterMapper classSemesterMapper;
@Resource
private KCJCMapper kcjcMapper;
@Resource
private TeachingMaterialMapper teachingMaterialMapper;
@Resource
private TeamCodeUtil teamCodeUtil;
@@ -115,6 +123,8 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
throw new ServiceException("选修课信息不能为空", BAD_REQUEST);
}
KB course = requireCourse(dto.getKbh());
// 先校验教材存在性,避免先建班/学期后失败回滚留下副作用
linkCourseTextbook(course.getKbh(), dto.getJcmc());
String xydbh = resolveTeamId(dto.getXydbh(), dto.getXxbmc(), dto.getNj(), true, dto.getRs());
XYDRWB task = new XYDRWB();
task.setBh(UuidUtil.getOriginalUUID());
@@ -259,6 +269,11 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
}
jsbh = room.getJsbh();
}
try {
linkCourseTextbook(course.getKbh(), row.getJcmc());
} catch (ServiceException e) {
throw new ServiceException("第" + line + "行" + e.getMessage(), BAD_REQUEST);
}
String xydbh = resolveTeamId(null, row.getXxbmc().trim(), row.getKxbcnj(), true, row.getJhrs());
XYDRWB task = new XYDRWB();
task.setBh(UuidUtil.getOriginalUUID());
@@ -656,6 +671,34 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
return course;
}
/**
* 按教材名称把教材挂到课程(课程教材表)。教材按「名称」精确匹配,
* 同一课程同一教材的关联已存在则跳过,不覆盖课程已有教材。
*/
private void linkCourseTextbook(String kbh, String jcmc) {
if (StringUtils.isEmpty(jcmc) || StringUtils.isEmpty(kbh)) {
return;
}
JCXX material = teachingMaterialMapper.selectOne(new LambdaQueryWrapper<JCXX>()
.eq(JCXX::getMc, jcmc.trim())
.last("LIMIT 1"));
if (material == null) {
throw new ServiceException("教材不存在:" + jcmc, NOT_FOUND);
}
Long exists = kcjcMapper.selectCount(new LambdaQueryWrapper<KCJC>()
.eq(KCJC::getKbh, kbh)
.eq(KCJC::getJcbh, material.getBh()));
if (exists != null && exists > 0) {
return;
}
KCJC link = new KCJC();
link.setBh(UuidUtil.getOriginalUUID());
link.setKbh(kbh);
link.setJcbh(material.getBh());
link.setTy(0);
kcjcMapper.insert(link);
}
private void updateTeamDates(String xydbh, LocalDateTime start, LocalDateTime end) {
if (start == null && end == null) {
return;
+107 -16
View File
@@ -149,13 +149,57 @@
<el-input v-model="form.kcmc" placeholder="请输入课程名称,提交时按名称查找课编号" clearable />
</el-form-item>
<el-form-item label="实施教员" prop="js">
<el-input v-model="form.js" placeholder="请输入实施教员,提交时按名称查找教员编号" clearable />
<el-select
v-model="form.js"
placeholder="请选择实施教员"
clearable
filterable
:loading="teacherLoading"
class="w-full"
>
<el-option
v-for="t in teacherOptions"
:key="t.jybh"
:label="(t.jyxm || '-') + '(' + t.jybh + ')'"
:value="t.jybh"
/>
</el-select>
</el-form-item>
<el-form-item label="教材">
<el-input v-model="form.jc" placeholder="请输入教材" clearable />
<el-select
v-model="form.jc"
placeholder="请选择教材"
clearable
filterable
allow-create
default-first-option
:loading="materialLoading"
class="w-full"
>
<el-option
v-for="m in materialOptions"
:key="m.bh || m.id"
:label="m.mc"
:value="m.mc"
/>
</el-select>
</el-form-item>
<el-form-item label="教学场地">
<el-input v-model="form.jxcd" placeholder="请输入教学场地,提交时按名称查找教室编号" clearable />
<el-select
v-model="form.jxcd"
placeholder="请选择教学场地"
clearable
filterable
:loading="classroomLoading"
class="w-full"
>
<el-option
v-for="r in classroomOptions"
:key="r.jsbh"
:label="r.jsmc ? r.jsbh + ' · ' + r.jsmc : r.jsbh"
:value="r.jsbh"
/>
</el-select>
</el-form-item>
<el-form-item label="计划学时">
<el-input-number v-model="form.jhsxs" :min="0" :precision="0" class="w-full" />
@@ -191,7 +235,8 @@ import {
} from '@/api/teachOffice/elective'
import { listKb } from '@/api/teachOffice/kb'
import { listTeacher } from '@/api/teachOffice/teacher'
import { listClassroom } from '@/api/teachBusiness/classroom'
import { listAllClassroom } from '@/api/teachBusiness/classroom'
import { listTeachingMaterial } from '@/api/textbook/teachingMaterial'
import { saveAs } from 'file-saver'
export default {
@@ -235,10 +280,18 @@ export default {
xf: 0,
jh: 0
},
// ==================== 新建弹窗下拉选项 ====================
teacherOptions: [],
teacherLoading: false,
classroomOptions: [],
classroomLoading: false,
materialOptions: [],
materialLoading: false,
rules: {
xxbmc: [{ required: true, message: '请输入选修班名称', trigger: 'blur' }],
kcmc: [{ required: true, message: '请输入课程名称', trigger: 'blur' }],
js: [{ required: true, message: '请输入实施教员', trigger: 'blur' }]
js: [{ required: true, message: '请选择实施教员', trigger: 'change' }]
},
// ==================== 分页 ====================
@@ -401,10 +454,50 @@ export default {
jh: 0
}
this.dialogVisible = true
this.loadTeacherOptions()
this.loadClassroomOptions()
this.loadMaterialOptions()
this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate()
})
},
loadTeacherOptions() {
if (this.teacherOptions.length || this.teacherLoading) return
this.teacherLoading = true
listTeacher({ pageNum: 1, pageSize: 500 }).then(res => {
const records = (res && res.data && res.data.records) || []
this.teacherOptions = records.filter(t => t.jybh && !t.lzzt)
}).catch(() => {
this.teacherOptions = []
}).finally(() => {
this.teacherLoading = false
})
},
loadClassroomOptions() {
if (this.classroomOptions.length || this.classroomLoading) return
this.classroomLoading = true
listAllClassroom().then(res => {
this.classroomOptions = (res && res.data ? res.data : [])
.filter(r => r.jsbh && !(r.ty === true || r.ty === 1 || r.ty === '1' || r.ty === 'true'))
.sort((a, b) => String(a.jsbh).localeCompare(String(b.jsbh), 'zh-CN'))
}).catch(() => {
this.classroomOptions = []
}).finally(() => {
this.classroomLoading = false
})
},
loadMaterialOptions() {
if (this.materialOptions.length || this.materialLoading) return
this.materialLoading = true
listTeachingMaterial({ pageNum: 1, pageSize: 500 }).then(res => {
const records = (res && res.data && res.data.records) || []
this.materialOptions = records.filter(m => m.mc && !(m.ty === true || m.ty === 1 || m.ty === '1' || m.ty === 'true'))
}).catch(() => {
this.materialOptions = []
}).finally(() => {
this.materialLoading = false
})
},
handleNewConfirm() {
if (!this.$refs.formRef) return
this.$refs.formRef.validate((valid) => {
@@ -413,16 +506,9 @@ export default {
})
},
submitNewElective() {
const emptyPage = { data: { records: [] } }
Promise.all([
listKb({ pageNum: 1, pageSize: 1, kmc: this.form.kcmc }),
listTeacher({ pageNum: 1, pageSize: 1, jyxm: this.form.js }),
this.form.jxcd ? listClassroom({ pageNum: 1, pageSize: 1, jsmc: this.form.jxcd }) : Promise.resolve(emptyPage)
])
.then(([kbRes, teacherRes, roomRes]) => {
listKb({ pageNum: 1, pageSize: 1, kmc: this.form.kcmc })
.then(kbRes => {
const kbh = kbRes?.data?.records?.[0]?.kbh
const jybh = teacherRes?.data?.records?.[0]?.jybh
const jsbh = roomRes?.data?.records?.[0]?.jsbh
if (!kbh) {
this.$message.warning(`未找到课程科目:${this.form.kcmc}`)
return
@@ -431,8 +517,9 @@ export default {
kbh: kbh,
xxbmc: this.form.xxbmc,
nj: this.form.nj || undefined,
jybh: jybh || undefined,
jsbh: jsbh || undefined,
jybh: this.form.js || undefined,
jsbh: this.form.jxcd || undefined,
jcmc: this.form.jc || undefined,
rs: this.form.jh || undefined,
xs: this.form.jhsxs || undefined,
xf: this.form.xf || undefined
@@ -486,6 +573,10 @@ export default {
}
}
.w-full {
width: 100%;
}
// ==================== 6. 数据表格区域 ====================
.table-card {
.list-header {