forked from liweijie/education
1、正课与学期关系关联;
2、天假删除保护; 3、教学任务计划增加了「结束发布」。已发布或库里的「已发布」都可以结束;结束后写入结束时间,任务书和班次课程任务只读 4、班次学期操作内容调整修改;
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package com.roomroot.web.controller.jwgl;
|
||||||
|
|
||||||
|
import com.roomroot.jwgl.dto.calendar.ClassCalendarApplyDTO;
|
||||||
|
import com.roomroot.jwgl.dto.calendar.ClassCalendarEventDTO;
|
||||||
|
import com.roomroot.jwgl.service.ClassEventCalendarService;
|
||||||
|
import com.roomroot.jwgl.unit.Result;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班历(假期表)。与课程任务接口 /classCalendar 分开。
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/class-calendar")
|
||||||
|
public class ClassEventCalendarController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ClassEventCalendarService classEventCalendarService;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result<List<ClassCalendarEventDTO>> list(@RequestParam("xydxqbh") String xydxqbh) {
|
||||||
|
return Result.success(classEventCalendarService.listOrInherit(xydxqbh));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update")
|
||||||
|
public Result<Void> update(@RequestBody ClassCalendarEventDTO event) {
|
||||||
|
classEventCalendarService.update(event);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/apply")
|
||||||
|
public Result<Integer> apply(@RequestBody ClassCalendarApplyDTO body) {
|
||||||
|
return Result.success(classEventCalendarService.apply(
|
||||||
|
body.getSourceXydxqbh(), body.getTargetBhList(), body.getEventBhList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -344,8 +344,9 @@ public class ElectiveController {
|
|||||||
public Result<SemesterInitVO> semesterInit(
|
public Result<SemesterInitVO> semesterInit(
|
||||||
@RequestParam("xydbh") String xydbh,
|
@RequestParam("xydbh") String xydbh,
|
||||||
@RequestParam(required = false) String presetKxrq,
|
@RequestParam(required = false) String presetKxrq,
|
||||||
@RequestParam(required = false) String presetJsrq) {
|
@RequestParam(required = false) String presetJsrq,
|
||||||
return Result.success(electiveService.getSemesterInit(xydbh, presetKxrq, presetJsrq));
|
@RequestParam(required = false) Integer xqdc) {
|
||||||
|
return Result.success(electiveService.getSemesterInit(xydbh, presetKxrq, presetJsrq, xqdc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
@@ -545,6 +545,15 @@ public class JYSController {
|
|||||||
return Result.success("已发布,同步教研室任务书 " + count + " 份", count);
|
return Result.success("已发布,同步教研室任务书 " + count + " 份", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束发布。结束后任务书和课程任务只读。
|
||||||
|
*/
|
||||||
|
@PostMapping("/task/endPublish")
|
||||||
|
public Result<Void> endPublishTask(@RequestParam("bh") String bh) {
|
||||||
|
teachingTaskManageService.endPublish(bh);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 教研室任务书列表。
|
* 教研室任务书列表。
|
||||||
*/
|
*/
|
||||||
|
|||||||
+78
@@ -401,6 +401,84 @@ public class StudentRecordsController {
|
|||||||
return Result.success(count);
|
return Result.success(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未毕业、且该年度学期尚未建立班次学期信息的班次。
|
||||||
|
*/
|
||||||
|
@GetMapping("/semester/creatableClasses")
|
||||||
|
public Result<List<XYDB>> creatableClasses(@RequestParam("nd") Integer nd,
|
||||||
|
@RequestParam("xqdc") Integer xqdc) {
|
||||||
|
return Result.success(classSemesterService.listCreatableClasses(nd, xqdc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校学期带出开学/结束日期。
|
||||||
|
*/
|
||||||
|
@GetMapping("/semester/presetDates")
|
||||||
|
public Result<Map<String, String>> presetDates(@RequestParam("nd") Integer nd,
|
||||||
|
@RequestParam("xqdc") Integer xqdc) {
|
||||||
|
return Result.success(classSemesterService.presetDates(nd, xqdc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为符合条件的全部班次创建班次学期,返回实际创建数。
|
||||||
|
*/
|
||||||
|
@PostMapping("/semester/batchCreate")
|
||||||
|
public Result<Integer> batchCreate(@RequestBody Map<String, Object> params) {
|
||||||
|
Integer nd = asInt(params.get("nd"));
|
||||||
|
Integer xqdc = asInt(params.get("xqdc"));
|
||||||
|
String kxrq = asText(params.get("kxrq"));
|
||||||
|
String jsrq = asText(params.get("jsrq"));
|
||||||
|
int count = classSemesterService.batchCreateEligible(
|
||||||
|
nd,
|
||||||
|
xqdc,
|
||||||
|
kxrq == null ? null : java.time.LocalDate.parse(kxrq),
|
||||||
|
jsrq == null ? null : java.time.LocalDate.parse(jsrq));
|
||||||
|
return Result.success(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学期级预设合班,只改预设编班号。
|
||||||
|
*/
|
||||||
|
@PostMapping("/semester/batchWaveMerge")
|
||||||
|
public Result<Integer> batchWaveMerge(@RequestBody Map<String, Object> params) {
|
||||||
|
return Result.success(classSemesterService.batchWaveMerge(asBhList(params)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学期级预设拆班,所选班次各自独立成波。
|
||||||
|
*/
|
||||||
|
@PostMapping("/semester/batchWaveSplit")
|
||||||
|
public Result<Integer> batchWaveSplit(@RequestBody Map<String, Object> params) {
|
||||||
|
return Result.success(classSemesterService.batchWaveSplit(asBhList(params)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer asInt(Object value) {
|
||||||
|
if (value == null || "".equals(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof Number) {
|
||||||
|
return ((Number) value).intValue();
|
||||||
|
}
|
||||||
|
return Integer.valueOf(String.valueOf(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String asText(Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
return text.isEmpty() ? null : text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<String> asBhList(Map<String, Object> params) {
|
||||||
|
Object raw = params.get("bhList");
|
||||||
|
if (!(raw instanceof List)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return (List<String>) raw;
|
||||||
|
}
|
||||||
|
|
||||||
// ======================== 课程成绩查询 ========================
|
// ======================== 课程成绩查询 ========================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+43
@@ -159,4 +159,47 @@ public class StudentTeamTaskController {
|
|||||||
List<String> newBhList = studentTeamTaskService.copy(bhList, newXydbh);
|
List<String> newBhList = studentTeamTaskService.copy(bhList, newXydbh);
|
||||||
return Result.success(newBhList);
|
return Result.success(newBhList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/batchAutoGenerate")
|
||||||
|
public Result<Integer> batchAutoGenerate(@RequestBody List<String> xydxqbhList) {
|
||||||
|
return Result.success(studentTeamTaskService.batchAutoGenerate(xydxqbhList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/planCourses")
|
||||||
|
public Result<List<com.roomroot.jwgl.vo.PlanCourseVO>> planCourses(
|
||||||
|
@RequestParam("xydxqbh") String xydxqbh,
|
||||||
|
@RequestParam(value = "otherOnly", defaultValue = "true") boolean otherOnly) {
|
||||||
|
return Result.success(studentTeamTaskService.listPlanCourses(xydxqbh, otherOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addFromLibrary")
|
||||||
|
public Result<Void> addFromLibrary(@RequestParam("xydxqbh") String xydxqbh,
|
||||||
|
@RequestParam("kbh") String kbh) {
|
||||||
|
studentTeamTaskService.addFromLibrary(xydxqbh, kbh);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addFromPlan")
|
||||||
|
public Result<Void> addFromPlan(@RequestParam("xydxqbh") String xydxqbh,
|
||||||
|
@RequestParam("planBh") String planBh) {
|
||||||
|
studentTeamTaskService.addFromPlan(xydxqbh, planBh);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/syncFromPlan")
|
||||||
|
public Result<Integer> syncFromPlan(@RequestBody List<String> bhList) {
|
||||||
|
return Result.success(studentTeamTaskService.syncFromPlan(bhList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/batchDelete")
|
||||||
|
public Result<Integer> batchDelete(@RequestBody List<String> bhList) {
|
||||||
|
return Result.success(studentTeamTaskService.batchDeleteGuarded(bhList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/paste")
|
||||||
|
public Result<Integer> paste(@RequestBody Map<String, Object> params) {
|
||||||
|
List<String> bhList = (List<String>) params.get("bhList");
|
||||||
|
String targetXydxqbh = (String) params.get("targetXydxqbh");
|
||||||
|
return Result.success(studentTeamTaskService.pasteToSemester(bhList, targetXydxqbh));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+9
@@ -92,4 +92,13 @@ public class TeachingTaskController {
|
|||||||
int count = teachingTaskService.batchPublish(bh);
|
int count = teachingTaskService.batchPublish(bh);
|
||||||
return Result.success(count);
|
return Result.success(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束发布。结束后教研室不能再改任务书和课程任务。
|
||||||
|
*/
|
||||||
|
@PostMapping("/endPublish")
|
||||||
|
public Result<Void> endPublish(@RequestParam("bh") String bh) {
|
||||||
|
teachingTaskService.endPublish(bh);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.roomroot.jwgl.dto.calendar;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把班历事件应用到其它班次。eventBhList 为空时复制整个班历。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ClassCalendarApplyDTO {
|
||||||
|
|
||||||
|
private String sourceXydxqbh;
|
||||||
|
private List<String> targetBhList;
|
||||||
|
private List<String> eventBhList;
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package com.roomroot.jwgl.dto.calendar;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班历时间格。日期用 yyyy-MM-dd,便于复用校历编辑器。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ClassCalendarEventDTO {
|
||||||
|
|
||||||
|
private String bh;
|
||||||
|
private Integer nd;
|
||||||
|
private String xydbh;
|
||||||
|
private String xydxqbh;
|
||||||
|
private String jqsj;
|
||||||
|
private String jqmc;
|
||||||
|
private Boolean jc;
|
||||||
|
private String bz;
|
||||||
|
private Boolean kpk;
|
||||||
|
private Boolean bzxs;
|
||||||
|
private Boolean zdpk;
|
||||||
|
private Boolean zk;
|
||||||
|
private String courseClass;
|
||||||
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
package com.roomroot.jwgl.entity;
|
package com.roomroot.jwgl.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.roomroot.jwgl.unit.BaseEntity;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 假期表
|
* 假期表。班历时间格,不继承基类,避免写入表中不存在的审计列。
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@TableName("假期表")
|
@TableName("假期表")
|
||||||
public class JQB extends BaseEntity {
|
public class JQB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编号
|
* 编号
|
||||||
@@ -21,54 +19,49 @@ public class JQB extends BaseEntity {
|
|||||||
@TableId(value = "编号", type = IdType.INPUT)
|
@TableId(value = "编号", type = IdType.INPUT)
|
||||||
private String bh;
|
private String bh;
|
||||||
|
|
||||||
/**
|
@TableField("年度")
|
||||||
* 年度
|
|
||||||
*/
|
|
||||||
private Integer nd;
|
private Integer nd;
|
||||||
|
|
||||||
/**
|
@TableField("学员队编号")
|
||||||
* 学员队编号
|
|
||||||
*/
|
|
||||||
private String xydbh;
|
private String xydbh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 假期时间
|
* 假期时间,库中为整型日期 yyyyMMdd。
|
||||||
*/
|
*/
|
||||||
|
@TableField("假期时间")
|
||||||
private Integer jqsj;
|
private Integer jqsj;
|
||||||
|
|
||||||
/**
|
@TableField("假期名称")
|
||||||
* 假期名称
|
|
||||||
*/
|
|
||||||
private String jqmc;
|
private String jqmc;
|
||||||
|
|
||||||
/**
|
@TableField("加粗")
|
||||||
* 加粗
|
|
||||||
*/
|
|
||||||
private Integer jc;
|
private Integer jc;
|
||||||
|
|
||||||
/**
|
@TableField("备注")
|
||||||
* 备注
|
|
||||||
*/
|
|
||||||
private String bz;
|
private String bz;
|
||||||
|
|
||||||
/**
|
@TableField("可排课")
|
||||||
* 可排课
|
|
||||||
*/
|
|
||||||
private Integer kpk;
|
private Integer kpk;
|
||||||
|
|
||||||
/**
|
@TableField("学员队学期编号")
|
||||||
* 学员队学期编号
|
|
||||||
*/
|
|
||||||
private String xydxqbh;
|
private String xydxqbh;
|
||||||
|
|
||||||
/**
|
@TableField("备注显示")
|
||||||
* 备注显示
|
|
||||||
*/
|
|
||||||
private Integer bzxs;
|
private Integer bzxs;
|
||||||
|
|
||||||
/**
|
@TableField("自动排课")
|
||||||
* 自动排课
|
|
||||||
*/
|
|
||||||
private Integer zdpk;
|
private Integer zdpk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正课。与自动排课分离。
|
||||||
|
*/
|
||||||
|
@TableField("正课")
|
||||||
|
private Integer zk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节次,与校历一致,如 1-2、3-4。
|
||||||
|
*/
|
||||||
|
@TableField("节次")
|
||||||
|
private String courseClass;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ public class XQXLB extends BaseEntity {
|
|||||||
@TableField("自动排课")
|
@TableField("自动排课")
|
||||||
private Boolean zdpk;
|
private Boolean zdpk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正课。与自动排课分离:默认星期一至星期五 1-6 节,周末补课也可标为正课。
|
||||||
|
*/
|
||||||
|
@TableField("正课")
|
||||||
|
private Boolean zk;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 节次
|
* 节次
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -144,4 +144,28 @@ public class XYDNDXQJBXXB extends BaseEntity {
|
|||||||
@TableField("分析报告文档3编号")
|
@TableField("分析报告文档3编号")
|
||||||
private String fxbgwd3bh;
|
private String fxbgwd3bh;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总课程数。列表聚合学员队任务表,不落库。
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Integer zkcs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班次名称。列表联查学员队表,不落库。
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String xydmc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专用教室名称。列表联查教室表,不落库。
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String zyjsmc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表按预设编班号排序。仅查询参数,不落库。
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Integer sortWave;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-9
@@ -24,6 +24,9 @@
|
|||||||
<result column="分析报告文档2编号" property="fxbgwd2bh" />
|
<result column="分析报告文档2编号" property="fxbgwd2bh" />
|
||||||
<result column="分析报告文档3编号" property="fxbgwd3bh" />
|
<result column="分析报告文档3编号" property="fxbgwd3bh" />
|
||||||
<result column="DEL_FLAG" property="delFlag" />
|
<result column="DEL_FLAG" property="delFlag" />
|
||||||
|
<result column="zkcs" property="zkcs" />
|
||||||
|
<result column="xydmc" property="xydmc" />
|
||||||
|
<result column="zyjsmc" property="zyjsmc" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
@@ -32,25 +35,50 @@
|
|||||||
分析报告生成时间, 分析报告文档1编号, 分析报告文档2编号, 分析报告文档3编号, DEL_FLAG
|
分析报告生成时间, 分析报告文档1编号, 分析报告文档2编号, 分析报告文档3编号, DEL_FLAG
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<sql id="List_Select">
|
||||||
|
SELECT a.编号, a.年度, a.学员队编号, a.开学日期, a.结束日期, a.学期第次, a.专用教室编号, a.教学任务编号,
|
||||||
|
a.变动时间, a.备注, a.序号标识, a.预设编班号, a.节次类别, a.系统模式, a.开放教员排课, a.JSONZD,
|
||||||
|
a.分析报告生成时间, a.分析报告文档1编号, a.分析报告文档2编号, a.分析报告文档3编号, a.DEL_FLAG,
|
||||||
|
(SELECT COUNT(*) FROM 学员队任务表 t
|
||||||
|
WHERE t.学员队学期编号 = a.编号 AND NVL(t.DEL_FLAG, 0) = 0) AS zkcs,
|
||||||
|
b.学员队名称 AS xydmc,
|
||||||
|
NVL(r1.教室名称, r2.教室名称) AS zyjsmc
|
||||||
|
FROM 学员队年度学期基本信息表 a
|
||||||
|
LEFT JOIN 学员队表 b ON a.学员队编号 = b.学员队编号
|
||||||
|
LEFT JOIN 教室表 r1 ON a.专用教室编号 = r1.ID
|
||||||
|
LEFT JOIN 教室表 r2 ON a.专用教室编号 = r2.教室编号 AND r1.ID IS NULL
|
||||||
|
</sql>
|
||||||
|
|
||||||
<select id="selectPageList" resultMap="BaseResultMap">
|
<select id="selectPageList" resultMap="BaseResultMap">
|
||||||
SELECT <include refid="Base_Column_List" />
|
<include refid="List_Select" />
|
||||||
FROM 学员队年度学期基本信息表
|
|
||||||
<where>
|
<where>
|
||||||
<if test="xydndxqjbxxb.delFlag != null">
|
<if test="xydndxqjbxxb.delFlag != null">
|
||||||
AND DEL_FLAG = #{xydndxqjbxxb.delFlag}
|
AND a.DEL_FLAG = #{xydndxqjbxxb.delFlag}
|
||||||
</if>
|
</if>
|
||||||
<if test="xydndxqjbxxb.xydbh != null and xydndxqjbxxb.xydbh != ''">
|
<if test="xydndxqjbxxb.xydbh != null and xydndxqjbxxb.xydbh != ''">
|
||||||
AND 学员队编号 LIKE CONCAT('%', #{xydndxqjbxxb.xydbh}, '%')
|
AND a.学员队编号 LIKE CONCAT('%', #{xydndxqjbxxb.xydbh}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="xydndxqjbxxb.nd != null">
|
||||||
|
AND a.年度 = #{xydndxqjbxxb.nd}
|
||||||
|
</if>
|
||||||
|
<if test="xydndxqjbxxb.xqdc != null">
|
||||||
|
AND a.学期第次 = #{xydndxqjbxxb.xqdc}
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
ORDER BY 编号
|
<choose>
|
||||||
|
<when test="xydndxqjbxxb.sortWave != null and xydndxqjbxxb.sortWave == 1">
|
||||||
|
ORDER BY NVL(a.预设编班号, 0), a.学员队编号
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
ORDER BY a.年度 DESC, a.学期第次, a.学员队编号
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectAllValid" resultMap="BaseResultMap">
|
<select id="selectAllValid" resultMap="BaseResultMap">
|
||||||
SELECT <include refid="Base_Column_List" />
|
<include refid="List_Select" />
|
||||||
FROM 学员队年度学期基本信息表
|
WHERE a.DEL_FLAG = '0'
|
||||||
WHERE DEL_FLAG = '0'
|
ORDER BY NVL(a.预设编班号, 0), a.学员队编号
|
||||||
ORDER BY 编号
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectByBcAndNdAndXqdc" resultMap="BaseResultMap">
|
<select id="selectByBcAndNdAndXqdc" resultMap="BaseResultMap">
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.roomroot.jwgl.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.roomroot.jwgl.entity.JQB;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 假期表(班历时间格)
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface JQBMapper extends BaseMapper<JQB> {
|
||||||
|
}
|
||||||
@@ -25,4 +25,9 @@ public interface XYDBMapper extends BaseMapper<XYDB> {
|
|||||||
* @return 学员队列表
|
* @return 学员队列表
|
||||||
*/
|
*/
|
||||||
java.util.List<XYDB> selectByDateRange(@Param("startTime") String startTime, @Param("endTime") String endTime);
|
java.util.List<XYDB> selectByDateRange(@Param("startTime") String startTime, @Param("endTime") String endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未毕业、且指定年度学期尚未建立班次学期信息的班次。
|
||||||
|
*/
|
||||||
|
java.util.List<XYDB> selectCreatableClasses(@Param("nd") Integer nd, @Param("xqdc") Integer xqdc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,4 +161,19 @@
|
|||||||
ORDER BY "序号"
|
ORDER BY "序号"
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 未毕业,且该年度学期尚未建立班次学期 -->
|
||||||
|
<select id="selectCreatableClasses" resultMap="BaseResultMap">
|
||||||
|
SELECT <include refid="Base_Column_List" />
|
||||||
|
FROM "学员队表" t
|
||||||
|
WHERE (t."毕业日期" IS NULL OR t."毕业日期" > SYSDATE)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM "学员队年度学期基本信息表" s
|
||||||
|
WHERE s."学员队编号" = t."学员队编号"
|
||||||
|
AND s."年度" = #{nd}
|
||||||
|
AND s."学期第次" = #{xqdc}
|
||||||
|
AND NVL(s.DEL_FLAG, 0) = 0
|
||||||
|
)
|
||||||
|
ORDER BY t."序号", t."学员队编号"
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.roomroot.jwgl.service;
|
||||||
|
|
||||||
|
import com.roomroot.jwgl.dto.calendar.ClassCalendarEventDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班历(假期表)服务。
|
||||||
|
*/
|
||||||
|
public interface ClassEventCalendarService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学员队学期编号查询班历。没有记录时按校历复制一份。
|
||||||
|
*/
|
||||||
|
List<ClassCalendarEventDTO> listOrInherit(String xydxqbh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新一个时间格。班次日期范围外的格子拒绝保存。
|
||||||
|
*/
|
||||||
|
void update(ClassCalendarEventDTO event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把选定或整个班历覆盖到其它班次的对应时间格。不改课程任务。
|
||||||
|
*/
|
||||||
|
int apply(String sourceXydxqbh, List<String> targetBhList, List<String> eventBhList);
|
||||||
|
}
|
||||||
+28
@@ -1,10 +1,13 @@
|
|||||||
package com.roomroot.jwgl.service;
|
package com.roomroot.jwgl.service;
|
||||||
|
|
||||||
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
|
import com.roomroot.jwgl.entity.XYDB;
|
||||||
import com.roomroot.jwgl.unit.PageQuery;
|
import com.roomroot.jwgl.unit.PageQuery;
|
||||||
import com.roomroot.jwgl.unit.PageResult;
|
import com.roomroot.jwgl.unit.PageResult;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 班次学期服务接口
|
* 班次学期服务接口
|
||||||
@@ -113,4 +116,29 @@ public interface ClassSemesterService {
|
|||||||
* @return 更新数量
|
* @return 更新数量
|
||||||
*/
|
*/
|
||||||
int batchUpdateDateRange(List<String> bhList, String xqkssj, String xqjssj);
|
int batchUpdateDateRange(List<String> bhList, String xqkssj, String xqjssj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未毕业且指定年度学期尚未建班次学期的班次。
|
||||||
|
*/
|
||||||
|
List<XYDB> listCreatableClasses(Integer nd, Integer xqdc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校学期表带出开学/结束日期。
|
||||||
|
*/
|
||||||
|
Map<String, String> presetDates(Integer nd, Integer xqdc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为符合条件的全部班次创建班次学期,返回实际创建数。
|
||||||
|
*/
|
||||||
|
int batchCreateEligible(Integer nd, Integer xqdc, LocalDate kxrq, LocalDate jsrq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学期级预设合班:所选班次写入同一预设编班号。
|
||||||
|
*/
|
||||||
|
int batchWaveMerge(List<String> bhList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学期级预设拆班:所选班次各自独立成波。
|
||||||
|
*/
|
||||||
|
int batchWaveSplit(List<String> bhList);
|
||||||
}
|
}
|
||||||
@@ -111,6 +111,11 @@ public interface ElectiveService {
|
|||||||
*/
|
*/
|
||||||
SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq);
|
SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同 {@link #getSemesterInit(String, String, String)}。指定学期第次时按该次取上学期专用教室,学制半年以内仍强制第1学期。
|
||||||
|
*/
|
||||||
|
SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq, Integer xqdc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建班次学期信息(教学班次学期信息设置窗口 - 确定按钮)
|
* 创建班次学期信息(教学班次学期信息设置窗口 - 确定按钮)
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
+36
@@ -2,6 +2,7 @@ package com.roomroot.jwgl.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.roomroot.jwgl.entity.XYDRWB;
|
import com.roomroot.jwgl.entity.XYDRWB;
|
||||||
|
import com.roomroot.jwgl.vo.PlanCourseVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -114,4 +115,39 @@ public interface StudentTeamTaskService {
|
|||||||
* @return 新生成的编号集合
|
* @return 新生成的编号集合
|
||||||
*/
|
*/
|
||||||
List<String> copy(List<String> bhList, String newXydbh);
|
List<String> copy(List<String> bhList, String newXydbh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按班次学期批量生成必修,已有课程不重复。
|
||||||
|
*/
|
||||||
|
int batchAutoGenerate(List<String> xydxqbhList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本班人培课程。otherOnly 为 true 时只列其它学期,并标是否已加入当前学期。
|
||||||
|
*/
|
||||||
|
List<PlanCourseVO> listPlanCourses(String xydxqbh, boolean otherOnly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从课程库加入当前学期任务,带出课程库默认学时和类型。
|
||||||
|
*/
|
||||||
|
void addFromLibrary(String xydxqbh, String kbh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把人培中的一门课加入当前学期任务。
|
||||||
|
*/
|
||||||
|
void addFromPlan(String xydxqbh, String planBh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按人培覆盖所选任务的学时、类型等字段。
|
||||||
|
*/
|
||||||
|
int syncFromPlan(List<String> bhList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除。已发布教学任务或已排课的行拒绝删除。
|
||||||
|
*/
|
||||||
|
int batchDeleteGuarded(List<String> bhList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制任务到另一个班次学期,两条任务独立。
|
||||||
|
*/
|
||||||
|
int pasteToSemester(List<String> bhList, String targetXydxqbh);
|
||||||
}
|
}
|
||||||
+5
@@ -29,6 +29,11 @@ public interface TeachingTaskManageService {
|
|||||||
|
|
||||||
int publish(String bh);
|
int publish(String bh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束发布。结束后任务书和课程任务只读。
|
||||||
|
*/
|
||||||
|
void endPublish(String bh);
|
||||||
|
|
||||||
List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh);
|
List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh);
|
||||||
|
|
||||||
List<TeachingOfficeBookCourseVO> listOfficeBookCourses(String jxrwbh, String jysdh);
|
List<TeachingOfficeBookCourseVO> listOfficeBookCourses(String jxrwbh, String jysdh);
|
||||||
|
|||||||
@@ -71,4 +71,11 @@ public interface TeachingTaskService {
|
|||||||
* @return 更新数量
|
* @return 更新数量
|
||||||
*/
|
*/
|
||||||
int batchPublish(String bh);
|
int batchPublish(String bh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束发布。结束后教研室不能再改任务书和课程任务。
|
||||||
|
*
|
||||||
|
* @param bh 教学任务编号
|
||||||
|
*/
|
||||||
|
void endPublish(String bh);
|
||||||
}
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.roomroot.jwgl.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 教学任务结束后,禁止再改任务书和班次课程任务。
|
||||||
|
*/
|
||||||
|
public interface TeachingTaskWriteGuard {
|
||||||
|
|
||||||
|
void assertTaskWritable(String jxrwbh);
|
||||||
|
|
||||||
|
void assertCourseTaskWritable(String xydxqbh);
|
||||||
|
}
|
||||||
+303
@@ -0,0 +1,303 @@
|
|||||||
|
package com.roomroot.jwgl.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
|
import com.roomroot.jwgl.dto.calendar.ClassCalendarEventDTO;
|
||||||
|
import com.roomroot.jwgl.entity.JQB;
|
||||||
|
import com.roomroot.jwgl.entity.XQXLB;
|
||||||
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.JQBMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.SemesterCalendarMapper;
|
||||||
|
import com.roomroot.jwgl.service.ClassEventCalendarService;
|
||||||
|
import com.roomroot.jwgl.service.TeachingTaskWriteGuard;
|
||||||
|
import com.roomroot.jwgl.utils.UuidUtil;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班历读写假期表。没有记录时从学期校历复制,不写课程任务。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ClassEventCalendarServiceImpl implements ClassEventCalendarService {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DAY = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
private static final DateTimeFormatter COMPACT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
|
private static final List<String> PERIODS = Arrays.asList("1-2", "3-4", "5-6", "7-8", "9-10", "11-12");
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JQBMapper jqbMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ClassSemesterMapper classSemesterMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SemesterCalendarMapper semesterCalendarMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeachingTaskWriteGuard teachingTaskWriteGuard;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public List<ClassCalendarEventDTO> listOrInherit(String xydxqbh) {
|
||||||
|
XYDNDXQJBXXB semester = requireSemester(xydxqbh);
|
||||||
|
List<JQB> rows = listRows(xydxqbh);
|
||||||
|
if (rows.isEmpty()) {
|
||||||
|
inherit(semester);
|
||||||
|
rows = listRows(xydxqbh);
|
||||||
|
}
|
||||||
|
List<ClassCalendarEventDTO> result = new ArrayList<>();
|
||||||
|
for (JQB row : rows) {
|
||||||
|
result.add(toDto(row));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(ClassCalendarEventDTO event) {
|
||||||
|
if (event == null || event.getBh() == null || event.getBh().isEmpty()) {
|
||||||
|
throw new ServiceException("班历编号不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
JQB existing = jqbMapper.selectById(event.getBh());
|
||||||
|
if (existing == null) {
|
||||||
|
throw new ServiceException("班历时间格不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(existing.getXydxqbh());
|
||||||
|
XYDNDXQJBXXB semester = requireSemester(existing.getXydxqbh());
|
||||||
|
LocalDate day = parseDay(event.getJqsj() == null ? formatDay(existing.getJqsj()) : event.getJqsj());
|
||||||
|
assertInRange(semester, day);
|
||||||
|
existing.setJqmc(event.getJqmc() == null ? "" : event.getJqmc());
|
||||||
|
existing.setBz(event.getBz());
|
||||||
|
existing.setJc(flag(event.getJc()));
|
||||||
|
existing.setKpk(flag(event.getKpk()));
|
||||||
|
existing.setBzxs(flag(event.getBzxs()));
|
||||||
|
existing.setZdpk(flag(event.getZdpk()));
|
||||||
|
existing.setZk(flag(event.getZk()));
|
||||||
|
if (event.getCourseClass() != null && !event.getCourseClass().isEmpty()) {
|
||||||
|
existing.setCourseClass(event.getCourseClass());
|
||||||
|
}
|
||||||
|
existing.setJqsj(Integer.valueOf(day.format(COMPACT)));
|
||||||
|
jqbMapper.updateById(existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int apply(String sourceXydxqbh, List<String> targetBhList, List<String> eventBhList) {
|
||||||
|
if (sourceXydxqbh == null || sourceXydxqbh.isEmpty() || CollectionUtils.isEmpty(targetBhList)) {
|
||||||
|
throw new ServiceException("请选择源班次和目标班次", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(sourceXydxqbh);
|
||||||
|
List<JQB> sourceRows = listRows(sourceXydxqbh);
|
||||||
|
if (sourceRows.isEmpty()) {
|
||||||
|
inherit(requireSemester(sourceXydxqbh));
|
||||||
|
sourceRows = listRows(sourceXydxqbh);
|
||||||
|
}
|
||||||
|
Set<String> selected = eventBhList == null ? new HashSet<>() : new HashSet<>(eventBhList);
|
||||||
|
List<JQB> toCopy = new ArrayList<>();
|
||||||
|
for (JQB row : sourceRows) {
|
||||||
|
if (selected.isEmpty() || selected.contains(row.getBh())) {
|
||||||
|
toCopy.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (String targetBh : targetBhList) {
|
||||||
|
if (sourceXydxqbh.equals(targetBh)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(targetBh);
|
||||||
|
XYDNDXQJBXXB target = requireSemester(targetBh);
|
||||||
|
if (listRows(targetBh).isEmpty()) {
|
||||||
|
inherit(target);
|
||||||
|
}
|
||||||
|
for (JQB source : toCopy) {
|
||||||
|
if (overlay(target, source)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void inherit(XYDNDXQJBXXB semester) {
|
||||||
|
LocalDate start = semester.getKxrq();
|
||||||
|
LocalDate end = semester.getJsrq();
|
||||||
|
if (start == null || end == null) {
|
||||||
|
throw new ServiceException("班次学期缺少开学或结束日期,不能生成班历", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
List<XQXLB> schoolRows = loadSchoolRows(semester, start, end);
|
||||||
|
if (schoolRows.isEmpty()) {
|
||||||
|
generateEmptyGrid(semester, start, end);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (XQXLB school : schoolRows) {
|
||||||
|
LocalDate day = parseDay(school.getJqsj());
|
||||||
|
if (day.isBefore(start) || day.isAfter(end)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
insertCell(semester, day, school.getCourseClass(), school.getJqmc(),
|
||||||
|
flag(school.getJc()), flag(school.getKpk()), flag(school.getBzxs()),
|
||||||
|
flag(school.getZdpk()), flag(school.getZk()), school.getBz());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<XQXLB> loadSchoolRows(XYDNDXQJBXXB semester, LocalDate start, LocalDate end) {
|
||||||
|
Integer schoolNd = semester.getNd() == null || semester.getXqdc() == null
|
||||||
|
? null : semester.getNd() * 100 + semester.getXqdc();
|
||||||
|
List<XQXLB> rows = querySchool(schoolNd, start, end);
|
||||||
|
if (!rows.isEmpty() || semester.getNd() == null) {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
return querySchool(semester.getNd(), start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<XQXLB> querySchool(Integer nd, LocalDate start, LocalDate end) {
|
||||||
|
if (nd == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return semesterCalendarMapper.selectList(new LambdaQueryWrapper<XQXLB>()
|
||||||
|
.eq(XQXLB::getNd, nd)
|
||||||
|
.ge(XQXLB::getJqsj, start.format(DAY))
|
||||||
|
.le(XQXLB::getJqsj, end.format(DAY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateEmptyGrid(XYDNDXQJBXXB semester, LocalDate start, LocalDate end) {
|
||||||
|
for (LocalDate day = start; !day.isAfter(end); day = day.plusDays(1)) {
|
||||||
|
boolean weekdayMain = day.getDayOfWeek().getValue() <= 5;
|
||||||
|
for (String period : PERIODS) {
|
||||||
|
boolean mainSlot = weekdayMain && ("1-2".equals(period) || "3-4".equals(period) || "5-6".equals(period));
|
||||||
|
insertCell(semester, day, period, "", 0, mainSlot ? 1 : 0, 0, mainSlot ? 1 : 0, mainSlot ? 1 : 0, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean overlay(XYDNDXQJBXXB target, JQB source) {
|
||||||
|
LocalDate day = parseDay(formatDay(source.getJqsj()));
|
||||||
|
if (target.getKxrq() != null && day.isBefore(target.getKxrq())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (target.getJsrq() != null && day.isAfter(target.getJsrq())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<JQB> matched = jqbMapper.selectList(new LambdaQueryWrapper<JQB>()
|
||||||
|
.eq(JQB::getXydxqbh, target.getBh())
|
||||||
|
.eq(JQB::getJqsj, source.getJqsj())
|
||||||
|
.eq(JQB::getCourseClass, source.getCourseClass()));
|
||||||
|
if (matched.isEmpty()) {
|
||||||
|
insertCell(target, day, source.getCourseClass(), source.getJqmc(),
|
||||||
|
source.getJc(), 0, source.getBzxs(), source.getZdpk(), source.getZk(), source.getBz());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (JQB row : matched) {
|
||||||
|
row.setJqmc(source.getJqmc());
|
||||||
|
row.setJc(source.getJc());
|
||||||
|
row.setBz(source.getBz());
|
||||||
|
row.setBzxs(source.getBzxs());
|
||||||
|
row.setZdpk(source.getZdpk());
|
||||||
|
row.setZk(source.getZk());
|
||||||
|
row.setKpk(source.getKpk());
|
||||||
|
jqbMapper.updateById(row);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertCell(XYDNDXQJBXXB semester, LocalDate day, String courseClass, String name,
|
||||||
|
Integer jc, Integer kpk, Integer bzxs, Integer zdpk, Integer zk, String bz) {
|
||||||
|
if (courseClass == null || courseClass.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean outside = (semester.getKxrq() != null && day.isBefore(semester.getKxrq()))
|
||||||
|
|| (semester.getJsrq() != null && day.isAfter(semester.getJsrq()));
|
||||||
|
JQB row = new JQB();
|
||||||
|
row.setBh(UuidUtil.getUUID());
|
||||||
|
row.setNd(semester.getNd());
|
||||||
|
row.setXydbh(semester.getXydbh());
|
||||||
|
row.setXydxqbh(semester.getBh());
|
||||||
|
row.setJqsj(Integer.valueOf(day.format(COMPACT)));
|
||||||
|
row.setJqmc(name == null ? "" : name);
|
||||||
|
row.setJc(jc == null ? 0 : jc);
|
||||||
|
row.setBz(bz);
|
||||||
|
row.setKpk(outside ? 0 : (kpk == null ? 0 : kpk));
|
||||||
|
row.setBzxs(bzxs == null ? 0 : bzxs);
|
||||||
|
row.setZdpk(zdpk == null ? 0 : zdpk);
|
||||||
|
row.setZk(zk == null ? 0 : zk);
|
||||||
|
row.setCourseClass(courseClass);
|
||||||
|
jqbMapper.insert(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JQB> listRows(String xydxqbh) {
|
||||||
|
return jqbMapper.selectList(new LambdaQueryWrapper<JQB>()
|
||||||
|
.eq(JQB::getXydxqbh, xydxqbh)
|
||||||
|
.orderByAsc(JQB::getJqsj)
|
||||||
|
.orderByAsc(JQB::getCourseClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
private XYDNDXQJBXXB requireSemester(String xydxqbh) {
|
||||||
|
XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh);
|
||||||
|
if (semester == null || Integer.valueOf(1).equals(semester.getDelFlag())) {
|
||||||
|
throw new ServiceException("班次学期不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
return semester;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertInRange(XYDNDXQJBXXB semester, LocalDate day) {
|
||||||
|
if (semester.getKxrq() != null && day.isBefore(semester.getKxrq())) {
|
||||||
|
throw new ServiceException("班次日期范围外的格子不可排", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (semester.getJsrq() != null && day.isAfter(semester.getJsrq())) {
|
||||||
|
throw new ServiceException("班次日期范围外的格子不可排", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassCalendarEventDTO toDto(JQB row) {
|
||||||
|
ClassCalendarEventDTO dto = new ClassCalendarEventDTO();
|
||||||
|
dto.setBh(row.getBh());
|
||||||
|
dto.setNd(row.getNd());
|
||||||
|
dto.setXydbh(row.getXydbh());
|
||||||
|
dto.setXydxqbh(row.getXydxqbh());
|
||||||
|
dto.setJqsj(formatDay(row.getJqsj()));
|
||||||
|
dto.setJqmc(row.getJqmc());
|
||||||
|
dto.setJc(Integer.valueOf(1).equals(row.getJc()));
|
||||||
|
dto.setBz(row.getBz());
|
||||||
|
dto.setKpk(Integer.valueOf(1).equals(row.getKpk()));
|
||||||
|
dto.setBzxs(Integer.valueOf(1).equals(row.getBzxs()));
|
||||||
|
dto.setZdpk(Integer.valueOf(1).equals(row.getZdpk()));
|
||||||
|
dto.setZk(Integer.valueOf(1).equals(row.getZk()));
|
||||||
|
dto.setCourseClass(row.getCourseClass());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDay(Integer value) {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value);
|
||||||
|
if (text.length() != 8) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text.substring(0, 4) + "-" + text.substring(4, 6) + "-" + text.substring(6, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDate parseDay(String value) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
throw new ServiceException("班历日期不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
String text = value.length() >= 10 ? value.substring(0, 10) : value;
|
||||||
|
return LocalDate.parse(text, DAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer flag(Boolean value) {
|
||||||
|
return Boolean.TRUE.equals(value) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -6,6 +6,7 @@ import com.roomroot.jwgl.entity.XYDRWB;
|
|||||||
import com.roomroot.jwgl.mapper.ClassSemesterCalendarMapper;
|
import com.roomroot.jwgl.mapper.ClassSemesterCalendarMapper;
|
||||||
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
import com.roomroot.jwgl.service.ClassSemesterCalendarService;
|
import com.roomroot.jwgl.service.ClassSemesterCalendarService;
|
||||||
|
import com.roomroot.jwgl.service.TeachingTaskWriteGuard;
|
||||||
import com.roomroot.jwgl.utils.UuidUtil;
|
import com.roomroot.jwgl.utils.UuidUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -26,8 +27,19 @@ public class ClassSemesterCalendarServiceImpl implements ClassSemesterCalendarSe
|
|||||||
@Resource
|
@Resource
|
||||||
private ClassSemesterMapper classSemesterMapper;
|
private ClassSemesterMapper classSemesterMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeachingTaskWriteGuard teachingTaskWriteGuard;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(XYDRWB xydrwb) {
|
public void update(XYDRWB xydrwb) {
|
||||||
|
if (xydrwb != null) {
|
||||||
|
String semesterBh = xydrwb.getXydxqbh();
|
||||||
|
if (semesterBh == null && xydrwb.getBh() != null) {
|
||||||
|
XYDRWB existing = classSemesterCalendarMapper.selectById(xydrwb.getBh());
|
||||||
|
semesterBh = existing == null ? null : existing.getXydxqbh();
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(semesterBh);
|
||||||
|
}
|
||||||
classSemesterCalendarMapper.updateById(xydrwb);
|
classSemesterCalendarMapper.updateById(xydrwb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +62,7 @@ public class ClassSemesterCalendarServiceImpl implements ClassSemesterCalendarSe
|
|||||||
failedTargetBhs.add(targetBh);
|
failedTargetBhs.add(targetBh);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(targetBh);
|
||||||
String newXydbh = targetSemester.getXydbh();
|
String newXydbh = targetSemester.getXydbh();
|
||||||
|
|
||||||
for (String sourceBh : sourceBhList) {
|
for (String sourceBh : sourceBhList) {
|
||||||
@@ -142,6 +155,7 @@ public class ClassSemesterCalendarServiceImpl implements ClassSemesterCalendarSe
|
|||||||
failedTargetBhs.add(targetBh);
|
failedTargetBhs.add(targetBh);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(targetBh);
|
||||||
String newXydbh = targetSemester.getXydbh();
|
String newXydbh = targetSemester.getXydbh();
|
||||||
|
|
||||||
for (XYDRWB source : sourceList) {
|
for (XYDRWB source : sourceList) {
|
||||||
|
|||||||
+271
-40
@@ -1,11 +1,17 @@
|
|||||||
package com.roomroot.jwgl.service.impl;
|
package com.roomroot.jwgl.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
|
import com.roomroot.jwgl.entity.XQ;
|
||||||
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
import com.roomroot.jwgl.entity.XYDB;
|
import com.roomroot.jwgl.entity.XYDB;
|
||||||
|
import com.roomroot.jwgl.entity.XYDRWB;
|
||||||
import com.roomroot.jwgl.mapper.ClassSemesterCalendarMapper;
|
import com.roomroot.jwgl.mapper.ClassSemesterCalendarMapper;
|
||||||
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
import com.roomroot.jwgl.mapper.SemesterCalendarMapper;
|
import com.roomroot.jwgl.mapper.SemesterCalendarMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.SemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.XYDBMapper;
|
||||||
import com.roomroot.jwgl.service.ClassSemesterService;
|
import com.roomroot.jwgl.service.ClassSemesterService;
|
||||||
import com.roomroot.jwgl.service.ElectiveService;
|
import com.roomroot.jwgl.service.ElectiveService;
|
||||||
import com.roomroot.jwgl.unit.PageQuery;
|
import com.roomroot.jwgl.unit.PageQuery;
|
||||||
@@ -17,8 +23,16 @@ import org.springframework.util.CollectionUtils;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 班次学期服务实现类
|
* 班次学期服务实现类
|
||||||
@@ -38,37 +52,88 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
|||||||
@Resource
|
@Resource
|
||||||
private ElectiveService electiveService;
|
private ElectiveService electiveService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private XYDBMapper xydbMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SemesterMapper semesterMapper;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void add(XYDNDXQJBXXB xydndxqjbxxb) {
|
public void add(XYDNDXQJBXXB xydndxqjbxxb) {
|
||||||
String uuid = UuidUtil.getUUID();
|
if (xydndxqjbxxb == null || xydndxqjbxxb.getXydbh() == null || xydndxqjbxxb.getXydbh().isEmpty()) {
|
||||||
xydndxqjbxxb.setBh(uuid);
|
throw new ServiceException("班次编号不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
assertXqdc(xydndxqjbxxb.getXqdc());
|
||||||
|
com.roomroot.jwgl.vo.elective.SemesterInitVO init = electiveService.getSemesterInit(
|
||||||
|
xydndxqjbxxb.getXydbh(), null, null, xydndxqjbxxb.getXqdc());
|
||||||
|
if (Boolean.TRUE.equals(init.getHalfYear()) && !Integer.valueOf(1).equals(xydndxqjbxxb.getXqdc())) {
|
||||||
|
throw new ServiceException("学制半年以内的班次,学期第次只能是第1学期", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (xydndxqjbxxb.getZyjsbh() == null || xydndxqjbxxb.getZyjsbh().isEmpty()) {
|
||||||
|
xydndxqjbxxb.setZyjsbh(init.getZyjsbh());
|
||||||
|
}
|
||||||
|
XYDNDXQJBXXB existing = classSemesterMapper.selectByBcAndNdAndXqdc(
|
||||||
|
xydndxqjbxxb.getXydbh(),
|
||||||
|
String.valueOf(xydndxqjbxxb.getNd()),
|
||||||
|
String.valueOf(xydndxqjbxxb.getXqdc()));
|
||||||
|
if (existing != null) {
|
||||||
|
throw new ServiceException("该班次本年度学期已存在,不能重复新建", CONFLICT);
|
||||||
|
}
|
||||||
|
if (xydndxqjbxxb.getYsbbh() == null) {
|
||||||
|
xydndxqjbxxb.setYsbbh(0);
|
||||||
|
}
|
||||||
|
if (xydndxqjbxxb.getKfjypk() == null) {
|
||||||
|
xydndxqjbxxb.setKfjypk(0);
|
||||||
|
}
|
||||||
|
if (xydndxqjbxxb.getXhbs() == null) {
|
||||||
|
xydndxqjbxxb.setXhbs(0);
|
||||||
|
}
|
||||||
|
xydndxqjbxxb.setBh(UuidUtil.getUUID());
|
||||||
xydndxqjbxxb.setDelFlag(0);
|
xydndxqjbxxb.setDelFlag(0);
|
||||||
int insert = classSemesterMapper.insert(xydndxqjbxxb);
|
classSemesterMapper.insert(xydndxqjbxxb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void delete(String bh) {
|
public void delete(String bh) {
|
||||||
|
assertNoCourseTasks(bh);
|
||||||
XYDNDXQJBXXB xydndxqjbxxb = getByBh(bh);
|
XYDNDXQJBXXB xydndxqjbxxb = getByBh(bh);
|
||||||
|
if (xydndxqjbxxb == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
xydndxqjbxxb.setDelFlag(1);
|
xydndxqjbxxb.setDelFlag(1);
|
||||||
classSemesterMapper.updateById(xydndxqjbxxb);
|
classSemesterMapper.updateById(xydndxqjbxxb);
|
||||||
classSemesterCalendarMapper.deleteByBcxqBh(bh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void batchDelete(List<String> bhList) {
|
public void batchDelete(List<String> bhList) {
|
||||||
|
if (bhList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (String bh : bhList) {
|
for (String bh : bhList) {
|
||||||
XYDNDXQJBXXB xydndxqjbxxb = getByBh(bh);
|
delete(bh);
|
||||||
if (xydndxqjbxxb != null) {
|
}
|
||||||
xydndxqjbxxb.setDelFlag(1);
|
}
|
||||||
classSemesterMapper.updateById(xydndxqjbxxb);
|
|
||||||
}
|
private void assertNoCourseTasks(String bh) {
|
||||||
|
Long count = classSemesterCalendarMapper.selectCount(new LambdaQueryWrapper<XYDRWB>()
|
||||||
|
.eq(XYDRWB::getXydxqbh, bh)
|
||||||
|
.eq(XYDRWB::getDelFlag, 0));
|
||||||
|
if (count != null && count > 0) {
|
||||||
|
throw new ServiceException("该班次学期已有 " + count + " 条课程教学计划,请先删除课程任务后再删除", CONFLICT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(XYDNDXQJBXXB xydndxqjbxxb) {
|
public void update(XYDNDXQJBXXB xydndxqjbxxb) {
|
||||||
|
if (xydndxqjbxxb != null && xydndxqjbxxb.getXydbh() != null && xydndxqjbxxb.getXqdc() != null) {
|
||||||
|
com.roomroot.jwgl.vo.elective.SemesterInitVO init = electiveService.getSemesterInit(
|
||||||
|
xydndxqjbxxb.getXydbh(), null, null, xydndxqjbxxb.getXqdc());
|
||||||
|
if (Boolean.TRUE.equals(init.getHalfYear()) && !Integer.valueOf(1).equals(xydndxqjbxxb.getXqdc())) {
|
||||||
|
throw new ServiceException("学制半年以内的班次,学期第次只能是第1学期", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
classSemesterMapper.updateById(xydndxqjbxxb);
|
classSemesterMapper.updateById(xydndxqjbxxb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,40 +167,13 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xqdcNum = parseXqdc(xqdc);
|
||||||
|
int year = Integer.parseInt(nd);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (XYDB xydb : xydbList) {
|
for (XYDB xydb : xydbList) {
|
||||||
// 校验是否已存在:根据班次编号、年度、学期第次查询
|
if (insertClassSemester(xydb, year, xqdcNum, LocalDate.parse(xqkssj), LocalDate.parse(xqjssj))) {
|
||||||
XYDNDXQJBXXB existing = classSemesterMapper.selectByBcAndNdAndXqdc(xydb.getXydbh(), nd, xqdc);
|
count++;
|
||||||
if (existing != null) {
|
|
||||||
// 已存在,跳过
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建学员队年度学期基本信息
|
|
||||||
XYDNDXQJBXXB xydndxqjbxxb = new XYDNDXQJBXXB();
|
|
||||||
String uuid = UuidUtil.getUUID();
|
|
||||||
xydndxqjbxxb.setBh(uuid);
|
|
||||||
xydndxqjbxxb.setXydbh(xydb.getXydbh());
|
|
||||||
xydndxqjbxxb.setNd(Integer.valueOf(nd));
|
|
||||||
if("春季学期".equals(xqdc)){
|
|
||||||
xqdc = "1";
|
|
||||||
} else if("夏季学期".equals(xqdc)){
|
|
||||||
xqdc = "2";
|
|
||||||
} else if("秋季学期".equals(xqdc)){
|
|
||||||
xqdc = "3";
|
|
||||||
}
|
|
||||||
xydndxqjbxxb.setXhbs(0);
|
|
||||||
xydndxqjbxxb.setXqdc(Integer.valueOf(xqdc));
|
|
||||||
xydndxqjbxxb.setKxrq(LocalDate.parse(xqkssj));
|
|
||||||
xydndxqjbxxb.setJsrq(LocalDate.parse(xqjssj));
|
|
||||||
xydndxqjbxxb.setYsbbh(0);
|
|
||||||
xydndxqjbxxb.setJclb("双节次");
|
|
||||||
xydndxqjbxxb.setXtms("");
|
|
||||||
xydndxqjbxxb.setKfjypk(0);
|
|
||||||
xydndxqjbxxb.setDelFlag(0);
|
|
||||||
|
|
||||||
int insert = classSemesterMapper.insert(xydndxqjbxxb);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -159,6 +197,7 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int batchUpdateXqdc(List<String> bhList, Integer xqdc) {
|
public int batchUpdateXqdc(List<String> bhList, Integer xqdc) {
|
||||||
|
assertXqdc(xqdc);
|
||||||
if (CollectionUtils.isEmpty(bhList)) {
|
if (CollectionUtils.isEmpty(bhList)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -210,6 +249,7 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
|||||||
xydndxqjbxxb.setKxrq(LocalDate.parse(xqkssj));
|
xydndxqjbxxb.setKxrq(LocalDate.parse(xqkssj));
|
||||||
xydndxqjbxxb.setJsrq(LocalDate.parse(xqjssj));
|
xydndxqjbxxb.setJsrq(LocalDate.parse(xqjssj));
|
||||||
classSemesterMapper.updateById(xydndxqjbxxb);
|
classSemesterMapper.updateById(xydndxqjbxxb);
|
||||||
|
count++;
|
||||||
|
|
||||||
// // 删除日期范围之外的日历记录
|
// // 删除日期范围之外的日历记录
|
||||||
// classSemesterCalendarMapper.deleteOutsideDateRange(bh, xqkssj, xqjssj);
|
// classSemesterCalendarMapper.deleteOutsideDateRange(bh, xqkssj, xqjssj);
|
||||||
@@ -250,4 +290,195 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<XYDB> listCreatableClasses(Integer nd, Integer xqdc) {
|
||||||
|
assertYearAndXqdc(nd, xqdc);
|
||||||
|
return xydbMapper.selectCreatableClasses(nd, xqdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> presetDates(Integer nd, Integer xqdc) {
|
||||||
|
assertYearAndXqdc(nd, xqdc);
|
||||||
|
XQ school = findSchoolSemester(nd, xqdc);
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
if (school == null || school.getKxrq() == null || school.getJsrq() == null) {
|
||||||
|
result.put("kxrq", "");
|
||||||
|
result.put("jsrq", "");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
result.put("kxrq", school.getKxrq().toLocalDate().format(fmt));
|
||||||
|
result.put("jsrq", school.getJsrq().toLocalDate().format(fmt));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int batchCreateEligible(Integer nd, Integer xqdc, LocalDate kxrq, LocalDate jsrq) {
|
||||||
|
assertYearAndXqdc(nd, xqdc);
|
||||||
|
if (kxrq == null || jsrq == null) {
|
||||||
|
Map<String, String> preset = presetDates(nd, xqdc);
|
||||||
|
if (kxrq == null && preset.get("kxrq") != null && !preset.get("kxrq").isEmpty()) {
|
||||||
|
kxrq = LocalDate.parse(preset.get("kxrq"));
|
||||||
|
}
|
||||||
|
if (jsrq == null && preset.get("jsrq") != null && !preset.get("jsrq").isEmpty()) {
|
||||||
|
jsrq = LocalDate.parse(preset.get("jsrq"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kxrq == null || jsrq == null) {
|
||||||
|
throw new ServiceException("请先维护学校学期的开学/结束日期,或手工填写", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (!jsrq.isAfter(kxrq)) {
|
||||||
|
throw new ServiceException("结束日期必须晚于开学日期", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
List<XYDB> classes = xydbMapper.selectCreatableClasses(nd, xqdc);
|
||||||
|
int count = 0;
|
||||||
|
for (XYDB clazz : classes) {
|
||||||
|
if (insertClassSemester(clazz, nd, xqdc, kxrq, jsrq)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int batchWaveMerge(List<String> bhList) {
|
||||||
|
List<XYDNDXQJBXXB> rows = loadRows(bhList);
|
||||||
|
if (rows.size() < 2) {
|
||||||
|
throw new ServiceException("请至少选择两个班次进行预设合班", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
Set<Integer> waves = new HashSet<>();
|
||||||
|
for (XYDNDXQJBXXB row : rows) {
|
||||||
|
if (row.getYsbbh() != null && row.getYsbbh() > 0) {
|
||||||
|
waves.add(row.getYsbbh());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int wave = waves.size() == 1 ? waves.iterator().next() : nextWaveNo();
|
||||||
|
int count = 0;
|
||||||
|
for (XYDNDXQJBXXB row : rows) {
|
||||||
|
row.setYsbbh(wave);
|
||||||
|
classSemesterMapper.updateById(row);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int batchWaveSplit(List<String> bhList) {
|
||||||
|
List<XYDNDXQJBXXB> rows = loadRows(bhList);
|
||||||
|
if (rows.isEmpty()) {
|
||||||
|
throw new ServiceException("请先选择要拆班的班次", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
int next = nextWaveNo();
|
||||||
|
int count = 0;
|
||||||
|
for (XYDNDXQJBXXB row : rows) {
|
||||||
|
row.setYsbbh(next++);
|
||||||
|
classSemesterMapper.updateById(row);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean insertClassSemester(XYDB clazz, int nd, int xqdc, LocalDate kxrq, LocalDate jsrq) {
|
||||||
|
XYDNDXQJBXXB existing = classSemesterMapper.selectByBcAndNdAndXqdc(
|
||||||
|
clazz.getXydbh(), String.valueOf(nd), String.valueOf(xqdc));
|
||||||
|
if (existing != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
XYDNDXQJBXXB row = new XYDNDXQJBXXB();
|
||||||
|
row.setBh(UuidUtil.getUUID());
|
||||||
|
row.setXydbh(clazz.getXydbh());
|
||||||
|
row.setNd(nd);
|
||||||
|
row.setXqdc(xqdc);
|
||||||
|
row.setKxrq(kxrq);
|
||||||
|
row.setJsrq(jsrq);
|
||||||
|
row.setZyjsbh(resolveRoom(clazz, xqdc));
|
||||||
|
row.setXhbs(0);
|
||||||
|
row.setYsbbh(0);
|
||||||
|
row.setJclb(clazz.getJclb() != null && !clazz.getJclb().isEmpty() ? clazz.getJclb() : "双节次");
|
||||||
|
row.setXtms(clazz.getXtms() == null ? "" : clazz.getXtms());
|
||||||
|
row.setKfjypk(0);
|
||||||
|
row.setDelFlag(0);
|
||||||
|
classSemesterMapper.insert(row);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveRoom(XYDB clazz, int xqdc) {
|
||||||
|
if (clazz.getZyjsbh() != null && !clazz.getZyjsbh().isEmpty()) {
|
||||||
|
return clazz.getZyjsbh();
|
||||||
|
}
|
||||||
|
if (xqdc <= 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<XYDNDXQJBXXB> prev = classSemesterMapper.selectList(new LambdaQueryWrapper<XYDNDXQJBXXB>()
|
||||||
|
.eq(XYDNDXQJBXXB::getXydbh, clazz.getXydbh())
|
||||||
|
.eq(XYDNDXQJBXXB::getXqdc, xqdc - 1)
|
||||||
|
.eq(XYDNDXQJBXXB::getDelFlag, 0)
|
||||||
|
.orderByDesc(XYDNDXQJBXXB::getNd));
|
||||||
|
if (prev.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return prev.get(0).getZyjsbh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private XQ findSchoolSemester(Integer nd, Integer xqdc) {
|
||||||
|
String key = String.valueOf(nd * 100 + xqdc);
|
||||||
|
XQ school = semesterMapper.selectById(key);
|
||||||
|
if (school != null) {
|
||||||
|
return school;
|
||||||
|
}
|
||||||
|
return semesterMapper.selectById(String.valueOf(nd));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<XYDNDXQJBXXB> loadRows(List<String> bhList) {
|
||||||
|
if (CollectionUtils.isEmpty(bhList)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return bhList.stream()
|
||||||
|
.map(classSemesterMapper::selectById)
|
||||||
|
.filter(row -> row != null && !Integer.valueOf(1).equals(row.getDelFlag()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nextWaveNo() {
|
||||||
|
int max = 0;
|
||||||
|
for (XYDNDXQJBXXB row : classSemesterMapper.selectAllValid()) {
|
||||||
|
if (row.getYsbbh() != null && row.getYsbbh() > max) {
|
||||||
|
max = row.getYsbbh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertYearAndXqdc(Integer nd, Integer xqdc) {
|
||||||
|
if (nd == null || nd < 2000) {
|
||||||
|
throw new ServiceException("请选择有效年度", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
assertXqdc(xqdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertXqdc(Integer xqdc) {
|
||||||
|
if (xqdc == null || xqdc < 1 || xqdc > 3) {
|
||||||
|
throw new ServiceException("学期第次只能是 1、2、3", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int parseXqdc(String xqdc) {
|
||||||
|
if (xqdc == null || xqdc.isEmpty()) {
|
||||||
|
throw new ServiceException("请选择学期第次", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if ("春季学期".equals(xqdc)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ("夏季学期".equals(xqdc)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if ("秋季学期".equals(xqdc)) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return Integer.parseInt(xqdc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+30
-10
@@ -211,7 +211,10 @@ public class ElectiveServiceImpl implements ElectiveService {
|
|||||||
wrapper.eq(JSB::getJxldh, jxldh);
|
wrapper.eq(JSB::getJxldh, jxldh);
|
||||||
}
|
}
|
||||||
if (py != null && !py.isEmpty()) {
|
if (py != null && !py.isEmpty()) {
|
||||||
wrapper.like(JSB::getPy, py);
|
wrapper.and(w -> w.like(JSB::getPy, py)
|
||||||
|
.or().like(JSB::getJsmc, py)
|
||||||
|
.or().like(JSB::getJsbh, py)
|
||||||
|
.or().like(JSB::getId, py));
|
||||||
}
|
}
|
||||||
wrapper.orderByAsc(JSB::getXh);
|
wrapper.orderByAsc(JSB::getXh);
|
||||||
return classRoomMapper.selectList(wrapper);
|
return classRoomMapper.selectList(wrapper);
|
||||||
@@ -219,6 +222,11 @@ public class ElectiveServiceImpl implements ElectiveService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq) {
|
public SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq) {
|
||||||
|
return getSemesterInit(xydbh, presetKxrq, presetJsrq, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SemesterInitVO getSemesterInit(String xydbh, String presetKxrq, String presetJsrq, Integer xqdc) {
|
||||||
XYDB clazz = xydbMapper.selectById(xydbh);
|
XYDB clazz = xydbMapper.selectById(xydbh);
|
||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
throw new BusinessException("教学班次不存在:" + xydbh);
|
throw new BusinessException("教学班次不存在:" + xydbh);
|
||||||
@@ -230,8 +238,12 @@ public class ElectiveServiceImpl implements ElectiveService {
|
|||||||
// 判断学制是否半年以内
|
// 判断学制是否半年以内
|
||||||
boolean halfYear = isHalfYear(rx, by);
|
boolean halfYear = isHalfYear(rx, by);
|
||||||
|
|
||||||
// 学期第次:半年以内固定第一学期;半年以上按入学日期智能推断
|
// 学期第次:半年以内固定第一学期;半年以上优先用窗口已选学期第次,否则按入学日期推断
|
||||||
Integer xqdc = halfYear ? 1 : inferXqdc(rx, by, LocalDate.now());
|
if (halfYear) {
|
||||||
|
xqdc = 1;
|
||||||
|
} else if (xqdc == null || xqdc < 1 || xqdc > 3) {
|
||||||
|
xqdc = inferXqdc(rx, by, LocalDate.now());
|
||||||
|
}
|
||||||
// 人才培养方案总学期数(半年一学期,向上取整)
|
// 人才培养方案总学期数(半年一学期,向上取整)
|
||||||
Integer totalXqdc = calcTotalXqdc(rx, by);
|
Integer totalXqdc = calcTotalXqdc(rx, by);
|
||||||
|
|
||||||
@@ -246,15 +258,12 @@ public class ElectiveServiceImpl implements ElectiveService {
|
|||||||
jsrq = parseDate(presetJsrq);
|
jsrq = parseDate(presetJsrq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二以上学期:默认预设上学期的专用教室
|
// 第二以上学期优先上学期专用教室;没有则用班次专业教室
|
||||||
String zyjsbh = getPrevRoom(xydbh, xqdc);
|
String zyjsbh = getPrevRoom(xydbh, xqdc);
|
||||||
String zyjsmc = null;
|
if (zyjsbh == null || zyjsbh.isEmpty()) {
|
||||||
if (zyjsbh != null && !zyjsbh.isEmpty()) {
|
zyjsbh = clazz.getZyjsbh();
|
||||||
JSB room = classRoomMapper.selectById(zyjsbh);
|
|
||||||
if (room != null) {
|
|
||||||
zyjsmc = room.getJsmc();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
String zyjsmc = roomName(zyjsbh);
|
||||||
|
|
||||||
SemesterInitVO vo = new SemesterInitVO();
|
SemesterInitVO vo = new SemesterInitVO();
|
||||||
vo.setXydbh(xydbh);
|
vo.setXydbh(xydbh);
|
||||||
@@ -405,6 +414,17 @@ public class ElectiveServiceImpl implements ElectiveService {
|
|||||||
* @param xqdc 当前学期第次(<=1 时返回 null)
|
* @param xqdc 当前学期第次(<=1 时返回 null)
|
||||||
* @return 上学期专用教室编号,不存在返回 null
|
* @return 上学期专用教室编号,不存在返回 null
|
||||||
*/
|
*/
|
||||||
|
private String roomName(String zyjsbh) {
|
||||||
|
if (zyjsbh == null || zyjsbh.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSB room = classRoomMapper.selectById(zyjsbh);
|
||||||
|
if (room == null) {
|
||||||
|
room = classRoomMapper.selectOne(new LambdaQueryWrapper<JSB>().eq(JSB::getJsbh, zyjsbh));
|
||||||
|
}
|
||||||
|
return room == null ? null : room.getJsmc();
|
||||||
|
}
|
||||||
|
|
||||||
private String getPrevRoom(String xydbh, Integer xqdc) {
|
private String getPrevRoom(String xydbh, Integer xqdc) {
|
||||||
if (xqdc == null || xqdc <= 1) {
|
if (xqdc == null || xqdc <= 1) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+16
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||||||
import com.roomroot.jwgl.entity.JYSRWS;
|
import com.roomroot.jwgl.entity.JYSRWS;
|
||||||
import com.roomroot.jwgl.mapper.OfficeTaskBookMapper;
|
import com.roomroot.jwgl.mapper.OfficeTaskBookMapper;
|
||||||
import com.roomroot.jwgl.service.OfficeTaskBookService;
|
import com.roomroot.jwgl.service.OfficeTaskBookService;
|
||||||
|
import com.roomroot.jwgl.service.TeachingTaskWriteGuard;
|
||||||
import com.roomroot.jwgl.unit.PageQuery;
|
import com.roomroot.jwgl.unit.PageQuery;
|
||||||
import com.roomroot.jwgl.unit.PageResult;
|
import com.roomroot.jwgl.unit.PageResult;
|
||||||
import com.roomroot.jwgl.utils.UuidUtil;
|
import com.roomroot.jwgl.utils.UuidUtil;
|
||||||
@@ -22,8 +23,14 @@ public class OfficeTaskBookServiceImpl implements OfficeTaskBookService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OfficeTaskBookMapper officeTaskBookMapper;
|
private OfficeTaskBookMapper officeTaskBookMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeachingTaskWriteGuard teachingTaskWriteGuard;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(JYSRWS jysrws) {
|
public void add(JYSRWS jysrws) {
|
||||||
|
if (jysrws != null) {
|
||||||
|
teachingTaskWriteGuard.assertTaskWritable(jysrws.getJxrwbh());
|
||||||
|
}
|
||||||
String uuid = UuidUtil.getUUID();
|
String uuid = UuidUtil.getUUID();
|
||||||
jysrws.setBh(uuid);
|
jysrws.setBh(uuid);
|
||||||
jysrws.setDelFlag(0);
|
jysrws.setDelFlag(0);
|
||||||
@@ -37,6 +44,7 @@ public class OfficeTaskBookServiceImpl implements OfficeTaskBookService {
|
|||||||
public void delete(String bh) {
|
public void delete(String bh) {
|
||||||
JYSRWS jysrws = getByBh(bh);
|
JYSRWS jysrws = getByBh(bh);
|
||||||
if (jysrws != null) {
|
if (jysrws != null) {
|
||||||
|
teachingTaskWriteGuard.assertTaskWritable(jysrws.getJxrwbh());
|
||||||
jysrws.setDelFlag(1);
|
jysrws.setDelFlag(1);
|
||||||
officeTaskBookMapper.updateById(jysrws);
|
officeTaskBookMapper.updateById(jysrws);
|
||||||
}
|
}
|
||||||
@@ -51,6 +59,14 @@ public class OfficeTaskBookServiceImpl implements OfficeTaskBookService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(JYSRWS jysrws) {
|
public void update(JYSRWS jysrws) {
|
||||||
|
if (jysrws != null) {
|
||||||
|
String taskBh = jysrws.getJxrwbh();
|
||||||
|
if (taskBh == null && jysrws.getBh() != null) {
|
||||||
|
JYSRWS existing = getByBh(jysrws.getBh());
|
||||||
|
taskBh = existing == null ? null : existing.getJxrwbh();
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertTaskWritable(taskBh);
|
||||||
|
}
|
||||||
officeTaskBookMapper.updateById(jysrws);
|
officeTaskBookMapper.updateById(jysrws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+85
@@ -3,8 +3,15 @@ package com.roomroot.jwgl.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
|
import com.roomroot.jwgl.entity.JXRW;
|
||||||
import com.roomroot.jwgl.entity.XQ;
|
import com.roomroot.jwgl.entity.XQ;
|
||||||
|
import com.roomroot.jwgl.entity.XQXLB;
|
||||||
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.SemesterCalendarMapper;
|
||||||
import com.roomroot.jwgl.mapper.SemesterMapper;
|
import com.roomroot.jwgl.mapper.SemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
|
||||||
import com.roomroot.jwgl.service.SemesterCalendarService;
|
import com.roomroot.jwgl.service.SemesterCalendarService;
|
||||||
import com.roomroot.jwgl.service.SemesterService;
|
import com.roomroot.jwgl.service.SemesterService;
|
||||||
import com.roomroot.jwgl.unit.PageQuery;
|
import com.roomroot.jwgl.unit.PageQuery;
|
||||||
@@ -14,8 +21,12 @@ import org.springframework.stereotype.Service;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 学期服务实现类
|
* 学期服务实现类
|
||||||
*/
|
*/
|
||||||
@@ -31,8 +42,19 @@ public class SemesterServiceImpl extends ServiceImpl<SemesterMapper, XQ> impleme
|
|||||||
@Resource
|
@Resource
|
||||||
SemesterCalendarService semesterCalendarService;
|
SemesterCalendarService semesterCalendarService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ClassSemesterMapper classSemesterMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeachingTaskMapper teachingTaskMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SemesterCalendarMapper semesterCalendarMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(XQ xq) {
|
public void add(XQ xq) {
|
||||||
|
normalizeSemester(xq);
|
||||||
|
assertNoOverlap(xq);
|
||||||
xq.setDelFlag(0);
|
xq.setDelFlag(0);
|
||||||
xq.setTkbsp(true);
|
xq.setTkbsp(true);
|
||||||
int insert = semesterMapper.insert(xq);
|
int insert = semesterMapper.insert(xq);
|
||||||
@@ -59,14 +81,77 @@ public class SemesterServiceImpl extends ServiceImpl<SemesterMapper, XQ> impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(Integer nd) {
|
public void delete(Integer nd) {
|
||||||
|
if (nd == null) {
|
||||||
|
throw new ServiceException("学期不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
List<String> blocked = new ArrayList<>();
|
||||||
|
Long classSemesterCount = classSemesterMapper.selectCount(new LambdaQueryWrapper<XYDNDXQJBXXB>()
|
||||||
|
.eq(XYDNDXQJBXXB::getNd, nd)
|
||||||
|
.and(w -> w.isNull(XYDNDXQJBXXB::getDelFlag).or().ne(XYDNDXQJBXXB::getDelFlag, 1)));
|
||||||
|
if (classSemesterCount != null && classSemesterCount > 0) {
|
||||||
|
blocked.add("班次学期 " + classSemesterCount + " 条");
|
||||||
|
}
|
||||||
|
Long taskCount = teachingTaskMapper.selectCount(new LambdaQueryWrapper<JXRW>()
|
||||||
|
.eq(JXRW::getNd, nd)
|
||||||
|
.and(w -> w.isNull(JXRW::getDelFlag).or().ne(JXRW::getDelFlag, 1)));
|
||||||
|
if (taskCount != null && taskCount > 0) {
|
||||||
|
blocked.add("教学任务 " + taskCount + " 条");
|
||||||
|
}
|
||||||
|
Long eventCount = semesterCalendarMapper.selectCount(new LambdaQueryWrapper<XQXLB>()
|
||||||
|
.eq(XQXLB::getNd, nd)
|
||||||
|
.isNotNull(XQXLB::getJqmc)
|
||||||
|
.ne(XQXLB::getJqmc, ""));
|
||||||
|
if (eventCount != null && eventCount > 0) {
|
||||||
|
blocked.add("校历事件 " + eventCount + " 条");
|
||||||
|
}
|
||||||
|
if (!blocked.isEmpty()) {
|
||||||
|
throw new ServiceException("该学期已有关联数据,不能删除:" + String.join("、", blocked), CONFLICT);
|
||||||
|
}
|
||||||
semesterMapper.deleteById(nd);
|
semesterMapper.deleteById(nd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(XQ xq) {
|
public void update(XQ xq) {
|
||||||
|
normalizeSemester(xq);
|
||||||
|
assertNoOverlap(xq);
|
||||||
semesterMapper.updateById(xq);
|
semesterMapper.updateById(xq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 年度末两位是学期次,只允许 01/02/03,序号与末位保持一致。
|
||||||
|
*/
|
||||||
|
private void normalizeSemester(XQ xq) {
|
||||||
|
if (xq == null || xq.getNd() == null || xq.getNd().isBlank()) {
|
||||||
|
throw new ServiceException("学期年度不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
String nd = xq.getNd().trim();
|
||||||
|
if (!nd.matches("\\d{6}")) {
|
||||||
|
throw new ServiceException("学期年度必须是6位,如202601", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
String suffix = nd.substring(4);
|
||||||
|
if (!suffix.equals("01") && !suffix.equals("02") && !suffix.equals("03")) {
|
||||||
|
throw new ServiceException("一年最多三个学期,学期次只能是01、02、03", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
xq.setNd(nd);
|
||||||
|
xq.setXh(Integer.parseInt(suffix));
|
||||||
|
if (xq.getKxrq() == null || xq.getJsrq() == null) {
|
||||||
|
throw new ServiceException("开学时间和结束时间不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (!xq.getJsrq().isAfter(xq.getKxrq())) {
|
||||||
|
throw new ServiceException("学期结束时间必须晚于开学时间", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNoOverlap(XQ xq) {
|
||||||
|
Long overlap = semesterMapper.selectCount(new LambdaQueryWrapper<XQ>()
|
||||||
|
.ne(XQ::getNd, xq.getNd())
|
||||||
|
.lt(XQ::getKxrq, xq.getJsrq())
|
||||||
|
.gt(XQ::getJsrq, xq.getKxrq()));
|
||||||
|
if (overlap != null && overlap > 0) {
|
||||||
|
throw new ServiceException("学期时间范围与已有学期重叠", CONFLICT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XQ getByNd(Integer nd) {
|
public XQ getByNd(Integer nd) {
|
||||||
return semesterMapper.selectById(nd);
|
return semesterMapper.selectById(nd);
|
||||||
|
|||||||
+316
@@ -3,25 +3,44 @@ package com.roomroot.jwgl.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
|
import com.roomroot.jwgl.entity.JXRW;
|
||||||
|
import com.roomroot.jwgl.entity.KB;
|
||||||
|
import com.roomroot.jwgl.entity.SSKC;
|
||||||
|
import com.roomroot.jwgl.entity.SSKCXYD;
|
||||||
import com.roomroot.jwgl.entity.XYDB;
|
import com.roomroot.jwgl.entity.XYDB;
|
||||||
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
import com.roomroot.jwgl.entity.XYDRWB;
|
import com.roomroot.jwgl.entity.XYDRWB;
|
||||||
import com.roomroot.jwgl.entity.ZYJXJHB;
|
import com.roomroot.jwgl.entity.ZYJXJHB;
|
||||||
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.KBMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.SSKCMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.SSKCXYDMapper;
|
||||||
import com.roomroot.jwgl.mapper.StudentTeamTaskMapper;
|
import com.roomroot.jwgl.mapper.StudentTeamTaskMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
|
||||||
import com.roomroot.jwgl.mapper.XYDBMapper;
|
import com.roomroot.jwgl.mapper.XYDBMapper;
|
||||||
import com.roomroot.jwgl.mapper.ZYJXJHBMapper;
|
import com.roomroot.jwgl.mapper.ZYJXJHBMapper;
|
||||||
import com.roomroot.jwgl.service.StudentTeamTaskService;
|
import com.roomroot.jwgl.service.StudentTeamTaskService;
|
||||||
|
import com.roomroot.jwgl.service.TeachingTaskWriteGuard;
|
||||||
|
import com.roomroot.jwgl.utils.TeachingTaskStatus;
|
||||||
import com.roomroot.jwgl.utils.UuidUtil;
|
import com.roomroot.jwgl.utils.UuidUtil;
|
||||||
|
import com.roomroot.jwgl.vo.PlanCourseVO;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 学员队任务表 Service实现
|
* 学员队任务表 Service实现
|
||||||
*/
|
*/
|
||||||
@@ -40,8 +59,26 @@ public class StudentTeamTaskServiceImpl implements StudentTeamTaskService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ZYJXJHBMapper zyjxjhbMapper;
|
private ZYJXJHBMapper zyjxjhbMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TeachingTaskWriteGuard teachingTaskWriteGuard;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private KBMapper kbMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TeachingTaskMapper teachingTaskMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SSKCMapper sskcMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SSKCXYDMapper sskcxydMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(XYDRWB xydrwb) {
|
public void add(XYDRWB xydrwb) {
|
||||||
|
if (xydrwb != null) {
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(xydrwb.getXydxqbh());
|
||||||
|
}
|
||||||
xydrwb.setBh(UuidUtil.getUUID());
|
xydrwb.setBh(UuidUtil.getUUID());
|
||||||
xydrwb.setDelFlag(0);
|
xydrwb.setDelFlag(0);
|
||||||
xydrwbMapper.insert(xydrwb);
|
xydrwbMapper.insert(xydrwb);
|
||||||
@@ -49,11 +86,23 @@ public class StudentTeamTaskServiceImpl implements StudentTeamTaskService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String bh) {
|
public void delete(String bh) {
|
||||||
|
XYDRWB existing = xydrwbMapper.selectById(bh);
|
||||||
|
if (existing != null) {
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(existing.getXydxqbh());
|
||||||
|
}
|
||||||
xydrwbMapper.deleteById(bh);
|
xydrwbMapper.deleteById(bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(XYDRWB xydrwb) {
|
public void update(XYDRWB xydrwb) {
|
||||||
|
if (xydrwb != null) {
|
||||||
|
String semesterBh = xydrwb.getXydxqbh();
|
||||||
|
if (semesterBh == null && xydrwb.getBh() != null) {
|
||||||
|
XYDRWB existing = xydrwbMapper.selectById(xydrwb.getBh());
|
||||||
|
semesterBh = existing == null ? null : existing.getXydxqbh();
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(semesterBh);
|
||||||
|
}
|
||||||
xydrwbMapper.updateById(xydrwb);
|
xydrwbMapper.updateById(xydrwb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +217,7 @@ public class StudentTeamTaskServiceImpl implements StudentTeamTaskService {
|
|||||||
}
|
}
|
||||||
Integer nd = semester.getNd();
|
Integer nd = semester.getNd();
|
||||||
String xydxqbh = semester.getBh();
|
String xydxqbh = semester.getBh();
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(xydxqbh);
|
||||||
|
|
||||||
// 4. 查询当前班次已存在的课程编号集合
|
// 4. 查询当前班次已存在的课程编号集合
|
||||||
LambdaQueryWrapper<XYDRWB> existWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<XYDRWB> existWrapper = new LambdaQueryWrapper<>();
|
||||||
@@ -231,9 +281,275 @@ public class StudentTeamTaskServiceImpl implements StudentTeamTaskService {
|
|||||||
source.setBh(newBh);
|
source.setBh(newBh);
|
||||||
source.setXydbh(newXydbh);
|
source.setXydbh(newXydbh);
|
||||||
source.setDelFlag(0);
|
source.setDelFlag(0);
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(source.getXydxqbh());
|
||||||
xydrwbMapper.insert(source);
|
xydrwbMapper.insert(source);
|
||||||
newBhList.add(newBh);
|
newBhList.add(newBh);
|
||||||
}
|
}
|
||||||
return newBhList;
|
return newBhList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int batchAutoGenerate(List<String> xydxqbhList) {
|
||||||
|
if (CollectionUtils.isEmpty(xydxqbhList)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (String xydxqbh : xydxqbhList) {
|
||||||
|
XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh);
|
||||||
|
if (semester == null || semester.getXydbh() == null || semester.getXqdc() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count += autoGenerateRequiredCourses(semester.getXydbh(), semester.getXqdc());
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PlanCourseVO> listPlanCourses(String xydxqbh, boolean otherOnly) {
|
||||||
|
XYDNDXQJBXXB semester = requireSemester(xydxqbh);
|
||||||
|
XYDB clazz = xydbMapper.selectById(semester.getXydbh());
|
||||||
|
if (clazz == null || clazz.getZydh() == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<ZYJXJHB> wrapper = new LambdaQueryWrapper<ZYJXJHB>()
|
||||||
|
.eq(ZYJXJHB::getZydh, clazz.getZydh())
|
||||||
|
.eq(ZYJXJHB::getTy, 0);
|
||||||
|
if (otherOnly && semester.getXqdc() != null) {
|
||||||
|
wrapper.ne(ZYJXJHB::getXqdc, semester.getXqdc());
|
||||||
|
}
|
||||||
|
List<ZYJXJHB> plans = zyjxjhbMapper.selectList(wrapper);
|
||||||
|
Set<String> done = currentCourseCodes(xydxqbh);
|
||||||
|
List<PlanCourseVO> result = new ArrayList<>();
|
||||||
|
for (ZYJXJHB plan : plans) {
|
||||||
|
PlanCourseVO vo = new PlanCourseVO();
|
||||||
|
vo.setBh(plan.getBh());
|
||||||
|
vo.setKbh(plan.getKbh());
|
||||||
|
vo.setJc(plan.getJc());
|
||||||
|
vo.setXqdc(plan.getXqdc());
|
||||||
|
vo.setXs(plan.getXs());
|
||||||
|
vo.setKlx(plan.getKlx());
|
||||||
|
vo.setXf(plan.getXf());
|
||||||
|
vo.setZks(plan.getZks());
|
||||||
|
vo.setCompleted(done.contains(plan.getKbh()));
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void addFromLibrary(String xydxqbh, String kbh) {
|
||||||
|
XYDNDXQJBXXB semester = requireWritableSemester(xydxqbh);
|
||||||
|
KB course = kbMapper.selectById(kbh);
|
||||||
|
if (course == null) {
|
||||||
|
throw new ServiceException("课程不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (currentCourseCodes(xydxqbh).contains(kbh)) {
|
||||||
|
throw new ServiceException("当前学期已有该课程", CONFLICT);
|
||||||
|
}
|
||||||
|
XYDRWB row = new XYDRWB();
|
||||||
|
row.setBh(UuidUtil.getUUID());
|
||||||
|
row.setNd(semester.getNd());
|
||||||
|
row.setXydbh(semester.getXydbh());
|
||||||
|
row.setXydxqbh(xydxqbh);
|
||||||
|
row.setXqdc(semester.getXqdc());
|
||||||
|
row.setKbh(course.getKbh());
|
||||||
|
row.setJc(course.getJc());
|
||||||
|
row.setXs(course.getXs());
|
||||||
|
row.setKlx(course.getKlx() == null ? course.getKclx() : course.getKlx());
|
||||||
|
row.setXf(course.getXf());
|
||||||
|
row.setZks(course.getZks());
|
||||||
|
row.setLlxs(course.getLlxs());
|
||||||
|
row.setSjxs(course.getSjxs());
|
||||||
|
row.setCjfz(course.getCjfz());
|
||||||
|
row.setKsks(course.getKsks());
|
||||||
|
row.setJysdh(course.getJysdh());
|
||||||
|
row.setDelFlag(0);
|
||||||
|
xydrwbMapper.insert(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void addFromPlan(String xydxqbh, String planBh) {
|
||||||
|
XYDNDXQJBXXB semester = requireWritableSemester(xydxqbh);
|
||||||
|
ZYJXJHB plan = zyjxjhbMapper.selectById(planBh);
|
||||||
|
if (plan == null) {
|
||||||
|
throw new ServiceException("人培课程不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (currentCourseCodes(xydxqbh).contains(plan.getKbh())) {
|
||||||
|
throw new ServiceException("当前学期已有该课程", CONFLICT);
|
||||||
|
}
|
||||||
|
xydrwbMapper.insert(fromPlan(semester, plan));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int syncFromPlan(List<String> bhList) {
|
||||||
|
if (CollectionUtils.isEmpty(bhList)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (String bh : bhList) {
|
||||||
|
XYDRWB row = xydrwbMapper.selectById(bh);
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(row.getXydxqbh());
|
||||||
|
ZYJXJHB plan = findPlan(row);
|
||||||
|
if (plan == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row.setXs(plan.getXs());
|
||||||
|
row.setKlx(plan.getKlx());
|
||||||
|
row.setXf(plan.getXf());
|
||||||
|
row.setJc(plan.getJc());
|
||||||
|
row.setZks(plan.getZks());
|
||||||
|
row.setLlxs(plan.getLlxs());
|
||||||
|
row.setSjxs(plan.getSjxs());
|
||||||
|
row.setJysdh(plan.getJysdh());
|
||||||
|
row.setCjfz(plan.getCjfz());
|
||||||
|
xydrwbMapper.updateById(row);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int batchDeleteGuarded(List<String> bhList) {
|
||||||
|
if (CollectionUtils.isEmpty(bhList)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (String bh : bhList) {
|
||||||
|
XYDRWB row = xydrwbMapper.selectById(bh);
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(row.getXydxqbh());
|
||||||
|
assertDeletable(row);
|
||||||
|
xydrwbMapper.deleteById(bh);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public int pasteToSemester(List<String> bhList, String targetXydxqbh) {
|
||||||
|
XYDNDXQJBXXB semester = requireWritableSemester(targetXydxqbh);
|
||||||
|
if (CollectionUtils.isEmpty(bhList)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (String bh : bhList) {
|
||||||
|
XYDRWB source = xydrwbMapper.selectById(bh);
|
||||||
|
if (source == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
source.setBh(UuidUtil.getUUID());
|
||||||
|
source.setXydbh(semester.getXydbh());
|
||||||
|
source.setXydxqbh(semester.getBh());
|
||||||
|
source.setNd(semester.getNd());
|
||||||
|
source.setXqdc(semester.getXqdc());
|
||||||
|
source.setDelFlag(0);
|
||||||
|
xydrwbMapper.insert(source);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XYDRWB fromPlan(XYDNDXQJBXXB semester, ZYJXJHB plan) {
|
||||||
|
XYDRWB row = new XYDRWB();
|
||||||
|
row.setBh(UuidUtil.getUUID());
|
||||||
|
row.setNd(semester.getNd());
|
||||||
|
row.setXydbh(semester.getXydbh());
|
||||||
|
row.setXydxqbh(semester.getBh());
|
||||||
|
row.setXqdc(semester.getXqdc());
|
||||||
|
row.setKbh(plan.getKbh());
|
||||||
|
row.setKlx(plan.getKlx());
|
||||||
|
row.setXs(plan.getXs());
|
||||||
|
row.setJc(plan.getJc());
|
||||||
|
row.setZks(plan.getZks());
|
||||||
|
row.setXf(plan.getXf());
|
||||||
|
row.setKsks(plan.getKsks());
|
||||||
|
row.setCjfz(plan.getCjfz());
|
||||||
|
row.setBjrxypjf(plan.getBjrxypjf());
|
||||||
|
row.setLlxs(plan.getLlxs());
|
||||||
|
row.setSjxs(plan.getSjxs());
|
||||||
|
row.setKsksbxs(plan.getKsksbxs());
|
||||||
|
row.setJysdh(plan.getJysdh());
|
||||||
|
row.setDelFlag(0);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZYJXJHB findPlan(XYDRWB row) {
|
||||||
|
XYDB clazz = xydbMapper.selectById(row.getXydbh());
|
||||||
|
if (clazz == null || clazz.getZydh() == null || row.getKbh() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<ZYJXJHB> plans = zyjxjhbMapper.selectList(new LambdaQueryWrapper<ZYJXJHB>()
|
||||||
|
.eq(ZYJXJHB::getZydh, clazz.getZydh())
|
||||||
|
.eq(ZYJXJHB::getKbh, row.getKbh())
|
||||||
|
.eq(ZYJXJHB::getTy, 0));
|
||||||
|
for (ZYJXJHB plan : plans) {
|
||||||
|
if (Objects.equals(plan.getXqdc(), row.getXqdc())) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plans.isEmpty() ? null : plans.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertDeletable(XYDRWB row) {
|
||||||
|
XYDNDXQJBXXB semester = classSemesterMapper.selectById(row.getXydxqbh());
|
||||||
|
if (semester != null && semester.getJxrwbh() != null) {
|
||||||
|
JXRW task = teachingTaskMapper.selectById(semester.getJxrwbh());
|
||||||
|
if (task != null && (TeachingTaskStatus.isPublished(task.getZt()) || TeachingTaskStatus.isEnded(task.getZt()))) {
|
||||||
|
throw new ServiceException("课程已发布到教学任务,不能删除", CONFLICT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isScheduled(row)) {
|
||||||
|
throw new ServiceException("课程已排课,不能删除", CONFLICT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isScheduled(XYDRWB row) {
|
||||||
|
if (row.getKbh() == null || row.getXydbh() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<SSKC> courses = sskcMapper.selectList(new LambdaQueryWrapper<SSKC>().eq(SSKC::getKmbh, row.getKbh()));
|
||||||
|
for (SSKC course : courses) {
|
||||||
|
Long linked = sskcxydMapper.selectCount(new LambdaQueryWrapper<SSKCXYD>()
|
||||||
|
.eq(SSKCXYD::getSskcbh, course.getBh())
|
||||||
|
.eq(SSKCXYD::getXydbh, row.getXydbh()));
|
||||||
|
if (linked != null && linked > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> currentCourseCodes(String xydxqbh) {
|
||||||
|
return xydrwbMapper.selectList(new LambdaQueryWrapper<XYDRWB>()
|
||||||
|
.eq(XYDRWB::getXydxqbh, xydxqbh)
|
||||||
|
.eq(XYDRWB::getDelFlag, 0))
|
||||||
|
.stream()
|
||||||
|
.map(XYDRWB::getKbh)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toCollection(HashSet::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private XYDNDXQJBXXB requireSemester(String xydxqbh) {
|
||||||
|
XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh);
|
||||||
|
if (semester == null) {
|
||||||
|
throw new ServiceException("班次学期不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
return semester;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XYDNDXQJBXXB requireWritableSemester(String xydxqbh) {
|
||||||
|
teachingTaskWriteGuard.assertCourseTaskWritable(xydxqbh);
|
||||||
|
return requireSemester(xydxqbh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+37
-1
@@ -24,6 +24,7 @@ import com.roomroot.jwgl.mapper.XYDBMapper;
|
|||||||
import com.roomroot.jwgl.mapper.ZYJXJHBMapper;
|
import com.roomroot.jwgl.mapper.ZYJXJHBMapper;
|
||||||
import com.roomroot.jwgl.service.StudentTeamTaskService;
|
import com.roomroot.jwgl.service.StudentTeamTaskService;
|
||||||
import com.roomroot.jwgl.service.TeachingTaskManageService;
|
import com.roomroot.jwgl.service.TeachingTaskManageService;
|
||||||
|
import com.roomroot.jwgl.utils.TeachingTaskStatus;
|
||||||
import com.roomroot.jwgl.unit.PageQuery;
|
import com.roomroot.jwgl.unit.PageQuery;
|
||||||
import com.roomroot.jwgl.unit.PageResult;
|
import com.roomroot.jwgl.unit.PageResult;
|
||||||
import com.roomroot.jwgl.utils.UuidUtil;
|
import com.roomroot.jwgl.utils.UuidUtil;
|
||||||
@@ -150,6 +151,9 @@ public class TeachingTaskManageServiceImpl implements TeachingTaskManageService
|
|||||||
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
|
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
|
||||||
throw new ServiceException("教学任务不存在", NOT_FOUND);
|
throw new ServiceException("教学任务不存在", NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
if (TeachingTaskStatus.isEnded(entity.getZt())) {
|
||||||
|
throw new ServiceException("教学任务已结束,不能再修改", CONFLICT);
|
||||||
|
}
|
||||||
fillSemester(dto);
|
fillSemester(dto);
|
||||||
entity.setRwmc(dto.getRwmc().trim());
|
entity.setRwmc(dto.getRwmc().trim());
|
||||||
if (dto.getJssj() != null) {
|
if (dto.getJssj() != null) {
|
||||||
@@ -195,7 +199,10 @@ public class TeachingTaskManageServiceImpl implements TeachingTaskManageService
|
|||||||
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
|
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
|
||||||
throw new ServiceException("教学任务不存在", NOT_FOUND);
|
throw new ServiceException("教学任务不存在", NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (STATUS_PUBLISHED.equals(entity.getZt())) {
|
if (TeachingTaskStatus.isEnded(entity.getZt())) {
|
||||||
|
throw new ServiceException("该教学任务已结束", CONFLICT);
|
||||||
|
}
|
||||||
|
if (TeachingTaskStatus.isPublished(entity.getZt())) {
|
||||||
throw new ServiceException("该教学任务已发布", CONFLICT);
|
throw new ServiceException("该教学任务已发布", CONFLICT);
|
||||||
}
|
}
|
||||||
generateCourseTasksAndOfficeBooks(bh);
|
generateCourseTasksAndOfficeBooks(bh);
|
||||||
@@ -213,6 +220,35 @@ public class TeachingTaskManageServiceImpl implements TeachingTaskManageService
|
|||||||
return books.size();
|
return books.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void endPublish(String bh) {
|
||||||
|
if (StringUtils.isEmpty(bh)) {
|
||||||
|
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
JXRW entity = teachingTaskMapper.selectById(bh);
|
||||||
|
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
|
||||||
|
throw new ServiceException("教学任务不存在", NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (TeachingTaskStatus.isEnded(entity.getZt())) {
|
||||||
|
throw new ServiceException("该教学任务已结束", CONFLICT);
|
||||||
|
}
|
||||||
|
if (!TeachingTaskStatus.isPublished(entity.getZt())) {
|
||||||
|
throw new ServiceException("只有已发布的教学任务才能结束", CONFLICT);
|
||||||
|
}
|
||||||
|
entity.setZt(TeachingTaskStatus.ENDED);
|
||||||
|
entity.setJssj(LocalDateTime.now());
|
||||||
|
teachingTaskMapper.updateById(entity);
|
||||||
|
|
||||||
|
List<JYSRWS> books = officeTaskBookMapper.selectList(new LambdaQueryWrapper<JYSRWS>()
|
||||||
|
.eq(JYSRWS::getJxrwbh, bh)
|
||||||
|
.eq(JYSRWS::getDelFlag, 0));
|
||||||
|
for (JYSRWS book : books) {
|
||||||
|
book.setZt(TeachingTaskStatus.ENDED);
|
||||||
|
officeTaskBookMapper.updateById(book);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh) {
|
public List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh) {
|
||||||
if (StringUtils.isEmpty(jxrwbh)) {
|
if (StringUtils.isEmpty(jxrwbh)) {
|
||||||
|
|||||||
+42
@@ -2,8 +2,10 @@ package com.roomroot.jwgl.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
import com.roomroot.jwgl.entity.JXRW;
|
import com.roomroot.jwgl.entity.JXRW;
|
||||||
import com.roomroot.jwgl.entity.JYSRWS;
|
import com.roomroot.jwgl.entity.JYSRWS;
|
||||||
|
import com.roomroot.jwgl.utils.TeachingTaskStatus;
|
||||||
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
|
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
|
||||||
import com.roomroot.jwgl.mapper.OfficeTaskBookMapper;
|
import com.roomroot.jwgl.mapper.OfficeTaskBookMapper;
|
||||||
import com.roomroot.jwgl.service.TeachingTaskService;
|
import com.roomroot.jwgl.service.TeachingTaskService;
|
||||||
@@ -14,8 +16,12 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 教学任务服务实现类
|
* 教学任务服务实现类
|
||||||
*/
|
*/
|
||||||
@@ -69,6 +75,10 @@ public class TeachingTaskServiceImpl implements TeachingTaskService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(JXRW jxrw) {
|
public void update(JXRW jxrw) {
|
||||||
|
JXRW existing = jxrw == null ? null : getByBh(jxrw.getBh());
|
||||||
|
if (existing != null && TeachingTaskStatus.isEnded(existing.getZt())) {
|
||||||
|
throw new ServiceException("教学任务已结束,不能再修改", CONFLICT);
|
||||||
|
}
|
||||||
teachingTaskMapper.updateById(jxrw);
|
teachingTaskMapper.updateById(jxrw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +115,9 @@ public class TeachingTaskServiceImpl implements TeachingTaskService {
|
|||||||
if (jxrw == null || jxrw.getDelFlag() != 0) {
|
if (jxrw == null || jxrw.getDelFlag() != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (TeachingTaskStatus.isEnded(jxrw.getZt())) {
|
||||||
|
throw new ServiceException("教学任务已结束,不能再次发布", CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
// 更新教学任务状态为"发布"
|
// 更新教学任务状态为"发布"
|
||||||
jxrw.setZt("发布");
|
jxrw.setZt("发布");
|
||||||
@@ -125,4 +138,33 @@ public class TeachingTaskServiceImpl implements TeachingTaskService {
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void endPublish(String bh) {
|
||||||
|
if (bh == null || bh.isEmpty()) {
|
||||||
|
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
JXRW jxrw = teachingTaskMapper.selectById(bh);
|
||||||
|
if (jxrw == null || Integer.valueOf(1).equals(jxrw.getDelFlag())) {
|
||||||
|
throw new ServiceException("教学任务不存在", BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (TeachingTaskStatus.isEnded(jxrw.getZt())) {
|
||||||
|
throw new ServiceException("该教学任务已结束", CONFLICT);
|
||||||
|
}
|
||||||
|
if (!TeachingTaskStatus.isPublished(jxrw.getZt())) {
|
||||||
|
throw new ServiceException("只有已发布的教学任务才能结束", CONFLICT);
|
||||||
|
}
|
||||||
|
jxrw.setZt(TeachingTaskStatus.ENDED);
|
||||||
|
jxrw.setJssj(LocalDateTime.now());
|
||||||
|
teachingTaskMapper.updateById(jxrw);
|
||||||
|
|
||||||
|
List<JYSRWS> books = officeTaskBookMapper.selectList(new LambdaQueryWrapper<JYSRWS>()
|
||||||
|
.eq(JYSRWS::getJxrwbh, bh)
|
||||||
|
.eq(JYSRWS::getDelFlag, 0));
|
||||||
|
for (JYSRWS book : books) {
|
||||||
|
book.setZt(TeachingTaskStatus.ENDED);
|
||||||
|
officeTaskBookMapper.updateById(book);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.roomroot.jwgl.service.impl;
|
||||||
|
|
||||||
|
import com.roomroot.common.exception.ServiceException;
|
||||||
|
import com.roomroot.common.utils.StringUtils;
|
||||||
|
import com.roomroot.jwgl.entity.JXRW;
|
||||||
|
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
|
||||||
|
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
|
||||||
|
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
|
||||||
|
import com.roomroot.jwgl.service.TeachingTaskWriteGuard;
|
||||||
|
import com.roomroot.jwgl.utils.TeachingTaskStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按教学任务状态拦截已结束任务的改写。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class TeachingTaskWriteGuardImpl implements TeachingTaskWriteGuard {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeachingTaskMapper teachingTaskMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ClassSemesterMapper classSemesterMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assertTaskWritable(String jxrwbh) {
|
||||||
|
if (StringUtils.isEmpty(jxrwbh)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JXRW task = teachingTaskMapper.selectById(jxrwbh);
|
||||||
|
if (task == null || Integer.valueOf(1).equals(task.getDelFlag())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (TeachingTaskStatus.isEnded(task.getZt())) {
|
||||||
|
throw new ServiceException("教学任务已结束,不能再修改任务书或课程任务", CONFLICT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assertCourseTaskWritable(String xydxqbh) {
|
||||||
|
if (StringUtils.isEmpty(xydxqbh)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh);
|
||||||
|
if (semester == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertTaskWritable(semester.getJxrwbh());
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -160,10 +160,10 @@ public final class SystemInitializationUtil {
|
|||||||
// 第三步:校验同一年度内的学期序号。
|
// 第三步:校验同一年度内的学期序号。
|
||||||
if (dto.getSequenceNumber() == null
|
if (dto.getSequenceNumber() == null
|
||||||
|| dto.getSequenceNumber().intValue() < 1
|
|| dto.getSequenceNumber().intValue() < 1
|
||||||
|| dto.getSequenceNumber().intValue() > 10) {
|
|| dto.getSequenceNumber().intValue() > 3) {
|
||||||
throw new BusinessException(
|
throw new BusinessException(
|
||||||
BAD_REQUEST,
|
BAD_REQUEST,
|
||||||
"学期序号必须在1至10之间");
|
"一年最多三个学期,学期序号必须在1至3之间");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第四步:开学和结束时间均为学期初始化必填参数。
|
// 第四步:开学和结束时间均为学期初始化必填参数。
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.roomroot.jwgl.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 教学任务状态。库中同时存在「发布」和历史值「已发布」。
|
||||||
|
*/
|
||||||
|
public final class TeachingTaskStatus {
|
||||||
|
|
||||||
|
public static final String DRAFT = "上报";
|
||||||
|
public static final String PUBLISHED = "发布";
|
||||||
|
public static final String PUBLISHED_LEGACY = "已发布";
|
||||||
|
public static final String ENDED = "已结束";
|
||||||
|
|
||||||
|
private TeachingTaskStatus() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPublished(String status) {
|
||||||
|
return PUBLISHED.equals(status) || PUBLISHED_LEGACY.equals(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnded(String status) {
|
||||||
|
return ENDED.equals(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.roomroot.jwgl.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人培课程及在当前班次学期的完成情况。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PlanCourseVO {
|
||||||
|
|
||||||
|
private String bh;
|
||||||
|
private String kbh;
|
||||||
|
private String jc;
|
||||||
|
private Integer xqdc;
|
||||||
|
private Integer xs;
|
||||||
|
private String klx;
|
||||||
|
private Float xf;
|
||||||
|
private Integer zks;
|
||||||
|
private Boolean completed;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-- 阶段0:正课列、学期序号校正
|
||||||
|
-- 正课与自动排课分离。回填只覆盖星期一至星期五的 1-6 节且可排课的格子。
|
||||||
|
-- 假期时间在学期校历表中是 VARCHAR(10),直接 TO_CHAR 即可。列已存在时不要重复执行 ALTER。
|
||||||
|
|
||||||
|
ALTER TABLE "学期校历表" ADD "正课" TINYINT DEFAULT 0 NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE "假期表" ADD "正课" TINYINT DEFAULT 0 NOT NULL;
|
||||||
|
|
||||||
|
UPDATE "学期校历表"
|
||||||
|
SET "正课" = 1
|
||||||
|
WHERE "可排课" = 1
|
||||||
|
AND "节次" IN ('1-2', '3-4', '5-6')
|
||||||
|
AND TO_CHAR("假期时间", 'D') IN ('2', '3', '4', '5', '6');
|
||||||
|
|
||||||
|
-- 年度末位即学期次(202602 -> 2)。校正现有序号与末位不一致的记录。
|
||||||
|
UPDATE "学期"
|
||||||
|
SET "序号" = MOD("年度", 10)
|
||||||
|
WHERE "年度" >= 200001
|
||||||
|
AND "年度" <= 210003
|
||||||
|
AND MOD("年度", 100) BETWEEN 1 AND 3
|
||||||
|
AND "序号" <> MOD("年度", 10);
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- 阶段2:班历时间格需要节次。假期表原先没有该列,不新建表。
|
||||||
|
-- 列已存在时不要重复执行。
|
||||||
|
|
||||||
|
ALTER TABLE "假期表" ADD "节次" VARCHAR(10) DEFAULT '' NOT NULL;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// ======================== 班历管理(实体 XYDRWB 学员队任务表) ========================
|
// ======================== 班次教学任务(实体 XYDRWB 学员队任务表,不是班历) ========================
|
||||||
// 接口依据:api2.txt「班次学期日历(班历)」分组 + StudentTeamTaskController
|
// 接口依据:api2.txt「班次学期日历(班历)」分组 + StudentTeamTaskController
|
||||||
// 每个班次学期(xydxqbh)下挂若干条课程任务记录:
|
// 每个班次学期(xydxqbh)下挂若干条课程任务记录:
|
||||||
// bh 编号、nd 年度、xydbh 学员队编号、kbh 课编号、xqdc 学期第次、jybh 教员编号、kcxh 课次序号、
|
// bh 编号、nd 年度、xydbh 学员队编号、kbh 课编号、xqdc 学期第次、jybh 教员编号、kcxh 课次序号、
|
||||||
@@ -103,3 +103,59 @@ export function autoGenerateRequiredCourses(xydbh, xqdc) {
|
|||||||
params: { xydbh: xydbh, xqdc: xqdc }
|
params: { xydbh: xydbh, xqdc: xqdc }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function batchAutoGenerateTasks(xydxqbhList) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/batchAutoGenerate',
|
||||||
|
method: 'post',
|
||||||
|
data: xydxqbhList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listPlanCourses(xydxqbh, otherOnly) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/planCourses',
|
||||||
|
method: 'get',
|
||||||
|
params: { xydxqbh, otherOnly }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addTaskFromLibrary(xydxqbh, kbh) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/addFromLibrary',
|
||||||
|
method: 'post',
|
||||||
|
params: { xydxqbh, kbh }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addTaskFromPlan(xydxqbh, planBh) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/addFromPlan',
|
||||||
|
method: 'post',
|
||||||
|
params: { xydxqbh, planBh }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function syncTaskFromPlan(bhList) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/syncFromPlan',
|
||||||
|
method: 'post',
|
||||||
|
data: bhList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function batchDeleteTasks(bhList) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/batchDelete',
|
||||||
|
method: 'post',
|
||||||
|
data: bhList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pasteTasks(bhList, targetXydxqbh) {
|
||||||
|
return request({
|
||||||
|
url: '/studentTeamTask/paste',
|
||||||
|
method: 'post',
|
||||||
|
data: { bhList, targetXydxqbh }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function updateSemester(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除班次学期(逻辑删除并级联删除其班历记录)
|
// 删除班次学期(逻辑删除;已有课程任务时后端拒绝)
|
||||||
export function delSemester(bh) {
|
export function delSemester(bh) {
|
||||||
return request({
|
return request({
|
||||||
url: '/student-records/semester/delete',
|
url: '/student-records/semester/delete',
|
||||||
@@ -115,3 +115,72 @@ export function batchAddFromElective(params) {
|
|||||||
params: params
|
params: params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 未毕业、且该年度学期尚未建立班次学期的班次
|
||||||
|
export function listCreatableClasses(params) {
|
||||||
|
return request({
|
||||||
|
url: '/student-records/semester/creatableClasses',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按学校学期带出开学/结束日期
|
||||||
|
export function presetSemesterDates(params) {
|
||||||
|
return request({
|
||||||
|
url: '/student-records/semester/presetDates',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为符合条件的全部班次创建班次学期,返回实际创建数
|
||||||
|
export function batchCreateSemester(data) {
|
||||||
|
return request({
|
||||||
|
url: '/student-records/semester/batchCreate',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 学期级预设合班,只改预设编班号
|
||||||
|
export function batchWaveMerge(data) {
|
||||||
|
return request({
|
||||||
|
url: '/student-records/semester/batchWaveMerge',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按学制带出学期第次、日期、专用教室。xqdc 为窗口已选学期第次
|
||||||
|
export function initClassSemester(params) {
|
||||||
|
return request({
|
||||||
|
url: '/elective/semester/init',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listSemesterBuildings() {
|
||||||
|
return request({
|
||||||
|
url: '/elective/semester/buildings',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listSemesterRooms(params) {
|
||||||
|
return request({
|
||||||
|
url: '/elective/semester/rooms',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 学期级预设拆班,所选班次各自独立成波
|
||||||
|
export function batchWaveSplit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/student-records/semester/batchWaveSplit',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,3 +88,15 @@ export function publishTeachingTask(bh) {
|
|||||||
params: { bh }
|
params: { bh }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束发布。仅已发布任务可结束,结束后任务书与班次课程任务只读。
|
||||||
|
* POST /teachingTask/endPublish?bh=
|
||||||
|
*/
|
||||||
|
export function endPublishTeachingTask(bh) {
|
||||||
|
return request({
|
||||||
|
url: '/teachingTask/endPublish',
|
||||||
|
method: 'post',
|
||||||
|
params: { bh }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function listClassCalendarEvent(xydxqbh) {
|
||||||
|
return request({
|
||||||
|
url: '/class-calendar/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { xydxqbh }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateClassCalendarEvent(data) {
|
||||||
|
return request({
|
||||||
|
url: '/class-calendar/update',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyClassCalendarEvent(data) {
|
||||||
|
return request({
|
||||||
|
url: '/class-calendar/apply',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="sce-panel">
|
<div class="sce-panel">
|
||||||
<div class="sce-panel-row">
|
<div class="sce-panel-row">
|
||||||
<span class="sce-label">事件名称:</span>
|
<span class="sce-label">事件名称:</span>
|
||||||
<el-input v-model="toolbar.eventName" size="small" class="sce-event-input" placeholder="请输入校历事件名称" />
|
<el-input v-model="toolbar.eventName" size="small" class="sce-event-input" :placeholder="mode === 'class' ? '请输入班历事件名称' : '请输入校历事件名称'" />
|
||||||
<el-checkbox v-model="toolbar.bold" class="sce-cb">加粗显示</el-checkbox>
|
<el-checkbox v-model="toolbar.bold" class="sce-cb">加粗显示</el-checkbox>
|
||||||
<el-checkbox v-model="toolbar.schedulable" class="sce-cb">可排课</el-checkbox>
|
<el-checkbox v-model="toolbar.schedulable" class="sce-cb">可排课</el-checkbox>
|
||||||
<el-checkbox v-model="toolbar.mainCourse" class="sce-cb">正课</el-checkbox>
|
<el-checkbox v-model="toolbar.mainCourse" class="sce-cb">正课</el-checkbox>
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { getSemester } from '@/api/teachBusiness/semester'
|
import { getSemester } from '@/api/teachBusiness/semester'
|
||||||
import { listXqxlb, addXqxlb, updateXqxlb } from '@/api/teachBusiness/xqxlb'
|
import { listXqxlb, addXqxlb, updateXqxlb } from '@/api/teachBusiness/xqxlb'
|
||||||
|
import { listClassCalendarEvent, updateClassCalendarEvent } from '@/api/teachOffice/classCalendarEvent'
|
||||||
|
|
||||||
// 节次定义:12/34/56 常显,78/晚上/夜间由开关控制可见
|
// 节次定义:12/34/56 常显,78/晚上/夜间由开关控制可见
|
||||||
const SLOT_DEFS = [
|
const SLOT_DEFS = [
|
||||||
@@ -137,7 +138,12 @@ export default {
|
|||||||
name: 'SchoolCalendarEditor',
|
name: 'SchoolCalendarEditor',
|
||||||
props: {
|
props: {
|
||||||
nd: { type: [String, Number], default: '' },
|
nd: { type: [String, Number], default: '' },
|
||||||
semesterName: { type: String, default: '' }
|
semesterName: { type: String, default: '' },
|
||||||
|
mode: { type: String, default: 'school' },
|
||||||
|
xydxqbh: { type: String, default: '' },
|
||||||
|
xydbh: { type: String, default: '' },
|
||||||
|
rangeStart: { type: String, default: '' },
|
||||||
|
rangeEnd: { type: String, default: '' }
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -202,7 +208,13 @@ export default {
|
|||||||
nd: {
|
nd: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
if (val) this.loadSemester()
|
if (this.mode !== 'class' && val) this.loadSemester()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xydxqbh: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (this.mode === 'class' && val) this.loadClassCalendar()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
visibleColumns(newCols, oldCols) {
|
visibleColumns(newCols, oldCols) {
|
||||||
@@ -251,6 +263,28 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* ---------- 数据加载 ---------- */
|
/* ---------- 数据加载 ---------- */
|
||||||
|
loadClassCalendar() {
|
||||||
|
const start = (this.rangeStart || '').slice(0, 10)
|
||||||
|
const end = (this.rangeEnd || '').slice(0, 10)
|
||||||
|
if (!start || !end) {
|
||||||
|
this.$message.warning('班次学期缺少开学或结束日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.startDate = new Date(start.replace(/-/g, '/'))
|
||||||
|
this.endDate = new Date(end.replace(/-/g, '/'))
|
||||||
|
this.calendarStart = null
|
||||||
|
this.buildWeeks()
|
||||||
|
this.loadClassEvents()
|
||||||
|
},
|
||||||
|
loadClassEvents() {
|
||||||
|
listClassCalendarEvent(this.xydxqbh).then(res => {
|
||||||
|
const data = res.data
|
||||||
|
const list = Array.isArray(data) ? data : (data && data.records) || []
|
||||||
|
this.renderEventList(list)
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.warning('班历加载失败')
|
||||||
|
})
|
||||||
|
},
|
||||||
loadSemester() {
|
loadSemester() {
|
||||||
if (!this.nd) return
|
if (!this.nd) return
|
||||||
getSemester(this.nd)
|
getSemester(this.nd)
|
||||||
@@ -281,57 +315,53 @@ export default {
|
|||||||
const data = res.data
|
const data = res.data
|
||||||
return Array.isArray(data) ? data : (data && data.records) || []
|
return Array.isArray(data) ? data : (data && data.records) || []
|
||||||
})
|
})
|
||||||
const render = (list) => {
|
|
||||||
// 后端 add() 的按「月日」去重对已存的全量日期不生效,同一年度多次打开/刷新会
|
|
||||||
// 积累同一格的重复占位记录(各带不同 bh)。updateById 只改其中一行,其余空记录
|
|
||||||
// 会在重新拉取时把刚保存的事件名覆盖掉。故这里按「周-星期-节次」先去重:
|
|
||||||
// 同一格保留有事件名(jqmc非空)的一条;都没有则保留最后一条兜底(保证有 bh)。
|
|
||||||
const unique = {}
|
|
||||||
list.forEach(item => {
|
|
||||||
const pos = this.locateXqxlb(item)
|
|
||||||
if (!pos) return
|
|
||||||
const stable = this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)
|
|
||||||
const prev = unique[stable]
|
|
||||||
if (!prev || (item.jqmc && !prev.item.jqmc)) {
|
|
||||||
unique[stable] = { item: item, pos: pos }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const loaded = {}
|
|
||||||
Object.keys(unique).forEach(stable => {
|
|
||||||
const { item, pos } = unique[stable]
|
|
||||||
const ev = {
|
|
||||||
bh: item.bh,
|
|
||||||
name: item.jqmc || '',
|
|
||||||
bold: !!item.jc,
|
|
||||||
schedulable: !!item.kpk,
|
|
||||||
mainCourse: !!item.zdpk,
|
|
||||||
remarkShow: !!item.bzxs,
|
|
||||||
remark: item.bz || ''
|
|
||||||
}
|
|
||||||
const colIndex = this.colIndexOf(pos.dayIndex, pos.slotKey)
|
|
||||||
if (colIndex >= 0) {
|
|
||||||
loaded[this.cellKey(pos.wIdx, colIndex)] = ev
|
|
||||||
} else {
|
|
||||||
// 该节次列当前隐藏:暂存(含 bh),待列显示时由 visibleColumns 监听恢复
|
|
||||||
this.hiddenEvents[this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)] = ev
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 合并到现有格子(后端数据覆盖已有状态)
|
|
||||||
this.events = Object.assign({}, this.events, loaded)
|
|
||||||
}
|
|
||||||
fetchList().then(list => {
|
fetchList().then(list => {
|
||||||
const hasCoverage = list.some(item => this.isInRange(item.jqsj))
|
const hasCoverage = list.some(item => this.isInRange(item.jqsj))
|
||||||
if (!hasCoverage && this.startDate && this.endDate) {
|
if (!hasCoverage && this.startDate && this.endDate) {
|
||||||
// 本学期区间尚无占位记录:仅用本期 kxrq/jsrq 预生成整张网格
|
|
||||||
const startStr = fmtDate(this.startDate)
|
const startStr = fmtDate(this.startDate)
|
||||||
const endStr = fmtDate(this.endDate)
|
const endStr = fmtDate(this.endDate)
|
||||||
return addXqxlb(startStr, endStr).then(() => fetchList())
|
return addXqxlb(startStr, endStr).then(() => fetchList())
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}).then(render).catch(() => {
|
}).then(list => {
|
||||||
|
this.renderEventList(list)
|
||||||
|
}).catch(() => {
|
||||||
this.$message.warning('校历事件加载失败')
|
this.$message.warning('校历事件加载失败')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
renderEventList(list) {
|
||||||
|
const unique = {}
|
||||||
|
list.forEach(item => {
|
||||||
|
const pos = this.locateXqxlb(item)
|
||||||
|
if (!pos) return
|
||||||
|
const stable = this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)
|
||||||
|
const prev = unique[stable]
|
||||||
|
if (!prev || (item.jqmc && !prev.item.jqmc)) {
|
||||||
|
unique[stable] = { item: item, pos: pos }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const loaded = {}
|
||||||
|
Object.keys(unique).forEach(stable => {
|
||||||
|
const { item, pos } = unique[stable]
|
||||||
|
const ev = {
|
||||||
|
bh: item.bh,
|
||||||
|
name: item.jqmc || '',
|
||||||
|
bold: !!item.jc,
|
||||||
|
schedulable: !!item.kpk,
|
||||||
|
autoSchedule: !!item.zdpk,
|
||||||
|
mainCourse: !!item.zk,
|
||||||
|
remarkShow: !!item.bzxs,
|
||||||
|
remark: item.bz || ''
|
||||||
|
}
|
||||||
|
const colIndex = this.colIndexOf(pos.dayIndex, pos.slotKey)
|
||||||
|
if (colIndex >= 0) {
|
||||||
|
loaded[this.cellKey(pos.wIdx, colIndex)] = ev
|
||||||
|
} else {
|
||||||
|
this.hiddenEvents[this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)] = ev
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.events = loaded
|
||||||
|
},
|
||||||
// 判断某条记录(jqsj 日期)是否落在本学期 [startDate, endDate] 区间内
|
// 判断某条记录(jqsj 日期)是否落在本学期 [startDate, endDate] 区间内
|
||||||
isInRange(jqsj) {
|
isInRange(jqsj) {
|
||||||
if (!this.startDate || !this.endDate || !jqsj) return false
|
if (!this.startDate || !this.endDate || !jqsj) return false
|
||||||
@@ -537,6 +567,7 @@ export default {
|
|||||||
name: name,
|
name: name,
|
||||||
bold: this.toolbar.bold,
|
bold: this.toolbar.bold,
|
||||||
schedulable: this.toolbar.schedulable,
|
schedulable: this.toolbar.schedulable,
|
||||||
|
autoSchedule: !!(prev && prev.autoSchedule),
|
||||||
mainCourse: this.toolbar.mainCourse,
|
mainCourse: this.toolbar.mainCourse,
|
||||||
remarkShow: this.toolbar.remarkShow,
|
remarkShow: this.toolbar.remarkShow,
|
||||||
remark: this.toolbar.remark
|
remark: this.toolbar.remark
|
||||||
@@ -601,9 +632,19 @@ export default {
|
|||||||
this.absorbPreview = ''
|
this.absorbPreview = ''
|
||||||
this.events = {}
|
this.events = {}
|
||||||
this.hiddenEvents = {}
|
this.hiddenEvents = {}
|
||||||
this.loadXqxlbEvents()
|
if (this.mode === 'class') this.loadClassEvents()
|
||||||
|
else this.loadXqxlbEvents()
|
||||||
this.$message.info('已刷新')
|
this.$message.info('已刷新')
|
||||||
},
|
},
|
||||||
|
reloadEvents() {
|
||||||
|
this.events = {}
|
||||||
|
this.hiddenEvents = {}
|
||||||
|
if (this.mode === 'class') this.loadClassEvents()
|
||||||
|
else this.loadXqxlbEvents()
|
||||||
|
},
|
||||||
|
savePayload(payload) {
|
||||||
|
return this.mode === 'class' ? updateClassCalendarEvent(payload) : updateXqxlb(payload)
|
||||||
|
},
|
||||||
/* ---------- 后端持久化(xqxlb 接口) ---------- */
|
/* ---------- 后端持久化(xqxlb 接口) ---------- */
|
||||||
// 批量保存选中格事件,返回各格子保存成功/失败的个数
|
// 批量保存选中格事件,返回各格子保存成功/失败的个数
|
||||||
persistEvents(keys) {
|
persistEvents(keys) {
|
||||||
@@ -612,11 +653,8 @@ export default {
|
|||||||
.map(key => {
|
.map(key => {
|
||||||
const payload = this.buildXqxlbPayload(key, this.events[key])
|
const payload = this.buildXqxlbPayload(key, this.events[key])
|
||||||
if (!payload) return Promise.resolve(false)
|
if (!payload) return Promise.resolve(false)
|
||||||
return updateXqxlb(payload)
|
return this.savePayload(payload)
|
||||||
.then(() => {
|
.then(() => true)
|
||||||
console.warn('[设定] key=', key, 'bh来源=', this.events[key] && this.events[key].bh ? '已有' : '生成', 'bh=', payload.bh, 'nd=', payload.nd, 'name=', payload.jqmc)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.warn('[设定] key=', key, '保存失败', err && (err.message || err))
|
console.warn('[设定] key=', key, '保存失败', err && (err.message || err))
|
||||||
return false
|
return false
|
||||||
@@ -630,8 +668,7 @@ export default {
|
|||||||
} else if (ok > 0) {
|
} else if (ok > 0) {
|
||||||
this.$message.success('已设定 ' + ok + ' 个时间格')
|
this.$message.success('已设定 ' + ok + ' 个时间格')
|
||||||
}
|
}
|
||||||
// 保存成功后重新拉取,回写各记录主键,避免重复新增
|
this.reloadEvents()
|
||||||
this.loadXqxlbEvents()
|
|
||||||
return { ok: ok, fail: fail }
|
return { ok: ok, fail: fail }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -643,7 +680,7 @@ export default {
|
|||||||
const payload = this.buildXqxlbPayload(key, this.events[key])
|
const payload = this.buildXqxlbPayload(key, this.events[key])
|
||||||
if (!payload) return Promise.resolve(false)
|
if (!payload) return Promise.resolve(false)
|
||||||
payload.jqmc = ''
|
payload.jqmc = ''
|
||||||
return updateXqxlb(payload)
|
return this.savePayload(payload)
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch(() => false)
|
.catch(() => false)
|
||||||
})
|
})
|
||||||
@@ -655,8 +692,7 @@ export default {
|
|||||||
} else if (ok > 0) {
|
} else if (ok > 0) {
|
||||||
this.$message.success('已删除 ' + ok + ' 个时间格事件')
|
this.$message.success('已删除 ' + ok + ' 个时间格事件')
|
||||||
}
|
}
|
||||||
// 删除成功后重新拉取,同步后端状态
|
this.reloadEvents()
|
||||||
this.loadXqxlbEvents()
|
|
||||||
return { ok: ok, fail: fail }
|
return { ok: ok, fail: fail }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -678,10 +714,18 @@ export default {
|
|||||||
bz: ev.remark || null,
|
bz: ev.remark || null,
|
||||||
kpk: !!ev.schedulable,
|
kpk: !!ev.schedulable,
|
||||||
bzxs: !!ev.remarkShow,
|
bzxs: !!ev.remarkShow,
|
||||||
zdpk: !!ev.mainCourse,
|
zdpk: !!ev.autoSchedule,
|
||||||
courseClass: SLOT_COURSE_MAP[pos.slotKey] || null
|
zk: !!ev.mainCourse,
|
||||||
|
courseClass: SLOT_COURSE_MAP[pos.slotKey] || null,
|
||||||
|
xydxqbh: this.mode === 'class' ? this.xydxqbh : undefined,
|
||||||
|
xydbh: this.mode === 'class' ? this.xydbh : undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectedEventBhs() {
|
||||||
|
return this.selectedKeys
|
||||||
|
.map(key => this.events[key] && this.events[key].bh)
|
||||||
|
.filter(Boolean)
|
||||||
|
},
|
||||||
// 时间格 key -> { wIdx, dayIndex, slotKey }
|
// 时间格 key -> { wIdx, dayIndex, slotKey }
|
||||||
parseCellKey(key) {
|
parseCellKey(key) {
|
||||||
const m = key.match(/^w(\d+)-c(\d+)$/)
|
const m = key.match(/^w(\d+)-c(\d+)$/)
|
||||||
@@ -694,7 +738,9 @@ export default {
|
|||||||
/* ---------- 返回学期管理 ---------- */
|
/* ---------- 返回学期管理 ---------- */
|
||||||
handleClose() {
|
handleClose() {
|
||||||
this.$emit('close')
|
this.$emit('close')
|
||||||
this.$router.replace({ path: '/teachBusiness/semester' })
|
if (this.mode !== 'class') {
|
||||||
|
this.$router.replace({ path: '/teachBusiness/semester' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ export default {
|
|||||||
bh: item.bh,
|
bh: item.bh,
|
||||||
name: item.jqmc || '',
|
name: item.jqmc || '',
|
||||||
schedulable: !!item.kpk,
|
schedulable: !!item.kpk,
|
||||||
mainCourse: !!item.zdpk,
|
mainCourse: !!item.zk,
|
||||||
remarkShow: !!item.bzxs,
|
remarkShow: !!item.bzxs,
|
||||||
remark: item.bz || ''
|
remark: item.bz || ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ export default {
|
|||||||
ksxsfabh: form.ksxsfabh || null,
|
ksxsfabh: form.ksxsfabh || null,
|
||||||
sdzs: form.sdzs,
|
sdzs: form.sdzs,
|
||||||
sdjldw: lockValue === '' ? '' : lockValue + form.lockUnit,
|
sdjldw: lockValue === '' ? '' : lockValue + form.lockUnit,
|
||||||
xh: form.xh,
|
xh: Number(String(form.xq || '').slice(-1)) || 0,
|
||||||
jsonzd: "{'1':1}",
|
jsonzd: "{'1':1}",
|
||||||
kstjsj: null
|
kstjsj: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible="dialogVisible"
|
:visible="dialogVisible"
|
||||||
:title="`班历管理——${semesterTitle}`"
|
:title="`班次教学任务——${semesterTitle}`"
|
||||||
width="1200px"
|
width="1200px"
|
||||||
top="6vh"
|
top="6vh"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@@ -17,19 +17,23 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="date-range-row">
|
<div class="date-range-row">
|
||||||
<div class="range-item">学期日期:{{ fmtDate(safeSemester.kxrq) }} 至 {{ fmtDate(safeSemester.jsrq) }},共 {{ semesterWeeks }} 周</div>
|
<div class="range-item">学期日期:{{ fmtDate(safeSemester.kxrq) }} 至 {{ fmtDate(safeSemester.jsrq) }},共 {{ semesterWeeks }} 周</div>
|
||||||
<div class="range-item">班历记录:{{ records.length }} 条,总学时 {{ summary.totalXs }},总学分 {{ summary.totalXf }}</div>
|
<div class="range-item">课程任务:{{ records.length }} 条,总学时 {{ summary.totalXs }},总学分 {{ summary.totalXf }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ==================== 2. 操作按钮区域 ==================== -->
|
<!-- ==================== 2. 操作按钮区域 ==================== -->
|
||||||
<div class="settings-panel">
|
<div class="settings-panel">
|
||||||
<div class="action-buttons-row">
|
<div class="action-buttons-row">
|
||||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增记录</el-button>
|
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增课程任务</el-button>
|
||||||
|
<el-button size="small" @click="openLibraryPicker">计划外新添</el-button>
|
||||||
|
<el-button size="small" @click="openPlanPicker">计划内必修添加</el-button>
|
||||||
<el-button size="small" @click="handleAutoGenerate">自动生成必修课程</el-button>
|
<el-button size="small" @click="handleAutoGenerate">自动生成必修课程</el-button>
|
||||||
<el-button size="small" @click="handlePresetMerge">预设合班</el-button>
|
<el-button size="small" :disabled="!selection.length" @click="handleCopySelected">复制所选</el-button>
|
||||||
<el-button size="small" @click="handlePresetSplit">预设拆班</el-button>
|
<el-button size="small" :disabled="!clipboardCount" @click="handlePaste">粘贴到其它班次</el-button>
|
||||||
|
<el-button size="small" :disabled="!selection.length" @click="handleSyncPlan">同步人培</el-button>
|
||||||
|
<el-button size="small" type="danger" plain :disabled="!selection.length" @click="handleBatchDelete">批量删除</el-button>
|
||||||
<el-button size="small" @click="handleApplyRegion">选定区域应用于其它班次</el-button>
|
<el-button size="small" @click="handleApplyRegion">选定区域应用于其它班次</el-button>
|
||||||
<el-button size="small" @click="handleApplyWhole">整个班历应用于其它班次</el-button>
|
<el-button size="small" @click="handleApplyWhole">整个班次教学任务应用于其它班次</el-button>
|
||||||
<el-button size="small" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
|
<el-button size="small" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,6 +48,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
max-height="480"
|
max-height="480"
|
||||||
class="calendar-table"
|
class="calendar-table"
|
||||||
|
:row-class-name="rowClassName"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
@@ -63,6 +68,11 @@
|
|||||||
<el-table-column prop="rs" label="人数" width="60" align="center" show-overflow-tooltip />
|
<el-table-column prop="rs" label="人数" width="60" align="center" show-overflow-tooltip />
|
||||||
<el-table-column prop="ksbh" label="考试编号" width="100" align="center" show-overflow-tooltip />
|
<el-table-column prop="ksbh" label="考试编号" width="100" align="center" show-overflow-tooltip />
|
||||||
<el-table-column prop="ksdd" label="考试地点" width="110" align="center" show-overflow-tooltip />
|
<el-table-column prop="ksdd" label="考试地点" width="110" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="人培差异" width="90" align="center">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-tag v-if="isPlanMismatch(row)" type="danger" size="mini">不一致</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
||||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
@@ -72,7 +82,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="select-tip">
|
<div class="select-tip">
|
||||||
提示:勾选多条记录后可进行 预设合班 / 预设拆班 / 选定区域应用于其它班次 操作;删除为物理删除,请谨慎操作。
|
提示:粉红行为与人培不一致,可用「同步人培」按人培覆盖。已发布到任务书或已排课的行不能删除。复制后粘贴会生成独立任务。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -304,6 +314,55 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible="libraryVisible"
|
||||||
|
title="从课程库选择"
|
||||||
|
width="760px"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@update:visible="val => libraryVisible = val"
|
||||||
|
>
|
||||||
|
<el-input v-model="libraryKeyword" size="small" placeholder="简称 / 课程名称" clearable style="width: 240px; margin-bottom: 8px" @keyup.enter.native="loadLibrary" />
|
||||||
|
<el-button size="small" type="primary" @click="loadLibrary">查询</el-button>
|
||||||
|
<el-table v-loading="pickerLoading" :data="libraryRows" border size="small" max-height="360" highlight-current-row @current-change="row => libraryCurrent = row">
|
||||||
|
<el-table-column prop="kbh" label="课编号" width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="jc" label="简称" width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="kmc" label="课程名称" min-width="160" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="xs" label="学时" width="70" align="center" />
|
||||||
|
<el-table-column prop="klx" label="课类型" width="90" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<div slot="footer">
|
||||||
|
<el-button size="small" @click="libraryVisible = false">取消</el-button>
|
||||||
|
<el-button size="small" type="primary" :disabled="!libraryCurrent" @click="confirmLibrary">加入任务</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible="planVisible"
|
||||||
|
title="其它学期人培课程"
|
||||||
|
width="760px"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@update:visible="val => planVisible = val"
|
||||||
|
>
|
||||||
|
<el-table v-loading="pickerLoading" :data="planRows" border size="small" max-height="360" highlight-current-row @current-change="row => planCurrent = row">
|
||||||
|
<el-table-column prop="jc" label="简称" width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="kbh" label="课编号" width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="xqdc" label="学期第次" width="90" align="center" />
|
||||||
|
<el-table-column prop="xs" label="学时" width="70" align="center" />
|
||||||
|
<el-table-column prop="klx" label="课类型" width="90" show-overflow-tooltip />
|
||||||
|
<el-table-column label="完成情况" width="90" align="center">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-tag :type="row.completed ? 'success' : 'info'" size="mini">{{ row.completed ? '已完成' : '未完成' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div slot="footer">
|
||||||
|
<el-button size="small" @click="planVisible = false">取消</el-button>
|
||||||
|
<el-button size="small" type="primary" :disabled="!planCurrent || planCurrent.completed" @click="confirmPlan">加入当前学期</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<!-- ==================== 目标班次学期选取弹窗 ==================== -->
|
<!-- ==================== 目标班次学期选取弹窗 ==================== -->
|
||||||
<ClassTeamSelectDialog
|
<ClassTeamSelectDialog
|
||||||
:visible="teamSelectVisible"
|
:visible="teamSelectVisible"
|
||||||
@@ -325,10 +384,17 @@ import {
|
|||||||
batchCopyCalendarBySemester,
|
batchCopyCalendarBySemester,
|
||||||
addTeamTask,
|
addTeamTask,
|
||||||
delTeamTask,
|
delTeamTask,
|
||||||
batchPresetMerge,
|
autoGenerateRequiredCourses,
|
||||||
batchPresetSplit,
|
listPlanCourses,
|
||||||
autoGenerateRequiredCourses
|
addTaskFromLibrary,
|
||||||
|
addTaskFromPlan,
|
||||||
|
syncTaskFromPlan,
|
||||||
|
batchDeleteTasks,
|
||||||
|
pasteTasks
|
||||||
} from '@/api/studentRecords/classCalendar'
|
} from '@/api/studentRecords/classCalendar'
|
||||||
|
import { listKb } from '@/api/teachOffice/kb'
|
||||||
|
|
||||||
|
const TASK_CLIPBOARD_KEY = 'education.classTaskClipboard'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ClassCalendarDialog',
|
name: 'ClassCalendarDialog',
|
||||||
@@ -358,7 +424,17 @@ export default {
|
|||||||
// ==================== 复制到其它班次 ====================
|
// ==================== 复制到其它班次 ====================
|
||||||
teamSelectVisible: false,
|
teamSelectVisible: false,
|
||||||
applyMode: 'region',
|
applyMode: 'region',
|
||||||
copyNote: ''
|
copyNote: '',
|
||||||
|
clipboardCount: 0,
|
||||||
|
planMap: {},
|
||||||
|
libraryVisible: false,
|
||||||
|
libraryKeyword: '',
|
||||||
|
libraryRows: [],
|
||||||
|
libraryCurrent: null,
|
||||||
|
planVisible: false,
|
||||||
|
planRows: [],
|
||||||
|
planCurrent: null,
|
||||||
|
pickerLoading: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -398,12 +474,13 @@ export default {
|
|||||||
return { totalXs, totalXf }
|
return { totalXs, totalXf }
|
||||||
},
|
},
|
||||||
editTitle() {
|
editTitle() {
|
||||||
return this.editMode === 'edit' ? '编辑班历记录' : '新增班历记录'
|
return this.editMode === 'edit' ? '编辑课程任务' : '新增课程任务'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
visible(val) {
|
visible(val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
|
this.clipboardCount = this.readClipboard().length
|
||||||
this.loadData()
|
this.loadData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,8 +488,21 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
/* ---------- 格式化 ---------- */
|
/* ---------- 格式化 ---------- */
|
||||||
fmtDate(val) {
|
fmtDate(val) {
|
||||||
if (!val) return '-'
|
if (val == null || val === '') return '-'
|
||||||
return String(val).slice(0, 10)
|
if (Array.isArray(val) && val.length >= 3) {
|
||||||
|
return `${val[0]}-${String(val[1]).padStart(2, '0')}-${String(val[2]).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
const year = val.year
|
||||||
|
const month = val.monthValue || val.month
|
||||||
|
const day = val.dayOfMonth || val.day
|
||||||
|
if (year && month && day) {
|
||||||
|
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
const text = String(val)
|
||||||
|
return text.length >= 10 ? text.slice(0, 10) : text
|
||||||
},
|
},
|
||||||
xqdcLabel(val) {
|
xqdcLabel(val) {
|
||||||
if (val === 1 || val === '1') return '第1学期'
|
if (val === 1 || val === '1') return '第1学期'
|
||||||
@@ -436,14 +526,44 @@ export default {
|
|||||||
const s = this.semester || {}
|
const s = this.semester || {}
|
||||||
if (!s.bh) return
|
if (!s.bh) return
|
||||||
this.loading = true
|
this.loading = true
|
||||||
listClassCalendar(s.bh).then(res => {
|
Promise.all([
|
||||||
this.records = (res && res.data) || []
|
listClassCalendar(s.bh),
|
||||||
|
listPlanCourses(s.bh, false).catch(() => ({ data: [] }))
|
||||||
|
]).then(([taskRes, planRes]) => {
|
||||||
|
this.records = (taskRes && taskRes.data) || []
|
||||||
|
const plans = (planRes && planRes.data) || []
|
||||||
|
const map = {}
|
||||||
|
plans.forEach(item => {
|
||||||
|
if (item.kbh) map[item.kbh] = item
|
||||||
|
})
|
||||||
|
this.planMap = map
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.records = []
|
this.records = []
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
isPlanMismatch(row) {
|
||||||
|
const plan = row && row.kbh ? this.planMap[row.kbh] : null
|
||||||
|
if (!plan) return false
|
||||||
|
return String(row.xs || '') !== String(plan.xs || '')
|
||||||
|
|| String(row.klx || '') !== String(plan.klx || '')
|
||||||
|
|| String(row.xf || '') !== String(plan.xf || '')
|
||||||
|
|| String(row.jc || '') !== String(plan.jc || '')
|
||||||
|
|| String(row.zks || '') !== String(plan.zks || '')
|
||||||
|
},
|
||||||
|
rowClassName({ row }) {
|
||||||
|
return this.isPlanMismatch(row) ? 'plan-mismatch-row' : ''
|
||||||
|
},
|
||||||
|
readClipboard() {
|
||||||
|
try {
|
||||||
|
const raw = sessionStorage.getItem(TASK_CLIPBOARD_KEY)
|
||||||
|
const parsed = raw ? JSON.parse(raw) : []
|
||||||
|
return Array.isArray(parsed) ? parsed : []
|
||||||
|
} catch (e) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleSelectionChange(rows) {
|
handleSelectionChange(rows) {
|
||||||
this.selection = rows
|
this.selection = rows
|
||||||
@@ -529,7 +649,7 @@ export default {
|
|||||||
req.then(() => {
|
req.then(() => {
|
||||||
this.saving = false
|
this.saving = false
|
||||||
this.editVisible = false
|
this.editVisible = false
|
||||||
this.$message.success(this.editMode === 'edit' ? '班历记录已更新' : '班历记录已新增')
|
this.$message.success(this.editMode === 'edit' ? '课程任务已更新' : '课程任务已新增')
|
||||||
this.loadData()
|
this.loadData()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.saving = false
|
this.saving = false
|
||||||
@@ -539,7 +659,7 @@ export default {
|
|||||||
|
|
||||||
/* ---------- 删除 ---------- */
|
/* ---------- 删除 ---------- */
|
||||||
handleDelete(row) {
|
handleDelete(row) {
|
||||||
this.$confirm(`确定删除该班历记录(${row.jc || row.bh})吗?`, '提示', {
|
this.$confirm(`确定删除该课程任务(${row.jc || row.bh})吗?`, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
@@ -571,65 +691,36 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ---------- 预设合班 / 拆班 ---------- */
|
|
||||||
handlePresetMerge() {
|
|
||||||
const bhs = this.selection.map(r => r.bh)
|
|
||||||
if (!bhs.length) {
|
|
||||||
this.$message.warning('请先勾选要合班的班历记录')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$confirm(`将按年度为选中的 ${bhs.length} 条记录设置统一的课次序号,是否继续?`, '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
batchPresetMerge(bhs).then(res => {
|
|
||||||
const count = (res && res.data) || 0
|
|
||||||
this.$message.success(`已完成 ${count} 条记录的预设合班`)
|
|
||||||
this.loadData()
|
|
||||||
})
|
|
||||||
}).catch(() => {})
|
|
||||||
},
|
|
||||||
|
|
||||||
handlePresetSplit() {
|
|
||||||
const bhs = this.selection.map(r => r.bh)
|
|
||||||
if (!bhs.length) {
|
|
||||||
this.$message.warning('请先勾选要拆班的班历记录')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$confirm(`将清空选中的 ${bhs.length} 条记录的课次序号,是否继续?`, '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
batchPresetSplit(bhs).then(res => {
|
|
||||||
const count = (res && res.data) || 0
|
|
||||||
this.$message.success(`已完成 ${count} 条记录的预设拆班`)
|
|
||||||
this.loadData()
|
|
||||||
})
|
|
||||||
}).catch(() => {})
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ---------- 应用于其它班次 ---------- */
|
/* ---------- 应用于其它班次 ---------- */
|
||||||
handleApplyRegion() {
|
handleApplyRegion() {
|
||||||
const bhs = this.selection.map(r => r.bh)
|
const bhs = this.selection.map(r => r.bh)
|
||||||
if (!bhs.length) {
|
if (!bhs.length) {
|
||||||
this.$message.warning('请先勾选要应用的班历记录(选定区域)')
|
this.$message.warning('请先勾选要应用的课程任务(选定区域)')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.applyMode = 'region'
|
this.applyMode = 'region'
|
||||||
this.copyNote = `将选中的 ${bhs.length} 条班历记录复制到所选班次`
|
this.copyNote = `将选中的 ${bhs.length} 条课程任务复制到所选班次`
|
||||||
this.teamSelectVisible = true
|
this.teamSelectVisible = true
|
||||||
},
|
},
|
||||||
|
|
||||||
handleApplyWhole() {
|
handleApplyWhole() {
|
||||||
this.applyMode = 'whole'
|
this.applyMode = 'whole'
|
||||||
this.copyNote = '将整个班历复制到所选班次'
|
this.copyNote = '将整个班次教学任务复制到所选班次'
|
||||||
this.teamSelectVisible = true
|
this.teamSelectVisible = true
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTeamConfirm(targets) {
|
handleTeamConfirm(targets) {
|
||||||
if (!targets || !targets.length) return
|
if (!targets || !targets.length) return
|
||||||
|
if (this.applyMode === 'paste') {
|
||||||
|
const bhList = this.readClipboard()
|
||||||
|
Promise.all(targets.map(item => pasteTasks(bhList, item.bh))).then(results => {
|
||||||
|
const count = results.reduce((sum, res) => sum + ((res && res.data) || 0), 0)
|
||||||
|
this.$message.success(`已粘贴 ${count} 条独立课程任务`)
|
||||||
|
this.teamSelectVisible = false
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
const targetBhList = targets.map(t => t.bh)
|
const targetBhList = targets.map(t => t.bh)
|
||||||
if (this.applyMode === 'whole') {
|
if (this.applyMode === 'whole') {
|
||||||
batchCopyCalendarBySemester({
|
batchCopyCalendarBySemester({
|
||||||
@@ -637,7 +728,7 @@ export default {
|
|||||||
targetBhList: targetBhList
|
targetBhList: targetBhList
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
const data = (res && res.data) || {}
|
const data = (res && res.data) || {}
|
||||||
this.$message.success(`已复制整个班历,共新增 ${data.count || 0} 条记录`)
|
this.$message.success(`已复制整个班次教学任务,共新增 ${data.count || 0} 条记录`)
|
||||||
this.loadData()
|
this.loadData()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -652,10 +743,108 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleCopySelected() {
|
||||||
|
const bhList = this.selection.map(item => item.bh).filter(Boolean)
|
||||||
|
if (!bhList.length) return
|
||||||
|
sessionStorage.setItem(TASK_CLIPBOARD_KEY, JSON.stringify(bhList))
|
||||||
|
this.clipboardCount = bhList.length
|
||||||
|
this.$message.success(`已复制 ${bhList.length} 条课程任务,可在其它班次粘贴`)
|
||||||
|
},
|
||||||
|
handlePaste() {
|
||||||
|
if (!this.readClipboard().length) {
|
||||||
|
this.$message.warning('剪贴板没有课程任务')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.applyMode = 'paste'
|
||||||
|
this.copyNote = `将剪贴板中的 ${this.clipboardCount} 条课程任务粘贴为独立记录`
|
||||||
|
this.teamSelectVisible = true
|
||||||
|
},
|
||||||
|
handleSyncPlan() {
|
||||||
|
const bhList = this.selection.map(item => item.bh).filter(Boolean)
|
||||||
|
if (!bhList.length) return
|
||||||
|
this.$confirm('将按人培覆盖所选行的学时、类型、学分和周课时,是否继续?', '同步人培', { type: 'warning' }).then(() => {
|
||||||
|
syncTaskFromPlan(bhList).then(res => {
|
||||||
|
this.$message.success(`已同步 ${res.data || 0} 条`)
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
handleBatchDelete() {
|
||||||
|
const bhList = this.selection.map(item => item.bh).filter(Boolean)
|
||||||
|
if (!bhList.length) return
|
||||||
|
this.$confirm('已发布到任务书或已排课的行会拒绝删除,其余将物理删除。', '批量删除', { type: 'warning' }).then(() => {
|
||||||
|
batchDeleteTasks(bhList).then(res => {
|
||||||
|
this.$message.success(`已删除 ${res.data || 0} 条`)
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
openLibraryPicker() {
|
||||||
|
this.libraryVisible = true
|
||||||
|
this.libraryCurrent = null
|
||||||
|
this.loadLibrary()
|
||||||
|
},
|
||||||
|
loadLibrary() {
|
||||||
|
this.pickerLoading = true
|
||||||
|
const keyword = (this.libraryKeyword || '').trim()
|
||||||
|
const unwrap = res => {
|
||||||
|
const data = (res && res.data) || {}
|
||||||
|
return data.records || (Array.isArray(data) ? data : [])
|
||||||
|
}
|
||||||
|
const requests = keyword
|
||||||
|
? [listKb({ pageNum: 1, pageSize: 50, kmc: keyword }), listKb({ pageNum: 1, pageSize: 50, jc: keyword })]
|
||||||
|
: [listKb({ pageNum: 1, pageSize: 50 })]
|
||||||
|
Promise.all(requests).then(results => {
|
||||||
|
const merged = []
|
||||||
|
const seen = {}
|
||||||
|
results.forEach(res => {
|
||||||
|
unwrap(res).forEach(item => {
|
||||||
|
if (!item.kbh || seen[item.kbh]) return
|
||||||
|
seen[item.kbh] = true
|
||||||
|
merged.push(item)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.libraryRows = merged
|
||||||
|
this.pickerLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.libraryRows = []
|
||||||
|
this.pickerLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
confirmLibrary() {
|
||||||
|
if (!this.libraryCurrent || !this.semester) return
|
||||||
|
addTaskFromLibrary(this.semester.bh, this.libraryCurrent.kbh).then(() => {
|
||||||
|
this.libraryVisible = false
|
||||||
|
this.$message.success('已从课程库加入,学时和类型已带出')
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openPlanPicker() {
|
||||||
|
if (!this.semester || !this.semester.bh) return
|
||||||
|
this.planVisible = true
|
||||||
|
this.planCurrent = null
|
||||||
|
this.pickerLoading = true
|
||||||
|
listPlanCourses(this.semester.bh, true).then(res => {
|
||||||
|
this.planRows = res.data || []
|
||||||
|
this.pickerLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.planRows = []
|
||||||
|
this.pickerLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
confirmPlan() {
|
||||||
|
if (!this.planCurrent || !this.semester) return
|
||||||
|
addTaskFromPlan(this.semester.bh, this.planCurrent.bh).then(() => {
|
||||||
|
this.planVisible = false
|
||||||
|
this.$message.success('已加入当前学期任务')
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
/* ---------- 刷新 ---------- */
|
/* ---------- 刷新 ---------- */
|
||||||
handleRefresh() {
|
handleRefresh() {
|
||||||
this.loadData()
|
this.loadData()
|
||||||
this.$message.success('已刷新班历')
|
this.$message.success('已刷新班次教学任务')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,6 +924,10 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::v-deep .plan-mismatch-row > td {
|
||||||
|
background: #fde2e2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 弹窗内表单分区标题 ==========
|
// ========== 弹窗内表单分区标题 ==========
|
||||||
.edit-form {
|
.edit-form {
|
||||||
.form-section-title {
|
.form-section-title {
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:visible="dialogVisible"
|
||||||
|
:title="`编辑班历——${titleText}`"
|
||||||
|
width="92%"
|
||||||
|
top="4vh"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
class="class-event-calendar-dialog"
|
||||||
|
@update:visible="val => dialogVisible = val"
|
||||||
|
>
|
||||||
|
<div class="dialog-toolbar">
|
||||||
|
<el-button size="small" :disabled="!semesterBh" @click="handleApplyRegion">选定区域应用于其它班次</el-button>
|
||||||
|
<el-button size="small" :disabled="!semesterBh" @click="handleApplyWhole">整个班历应用于其它班次</el-button>
|
||||||
|
<span class="hint">应用到其它班次只覆盖班历时间格,不改课程任务。</span>
|
||||||
|
</div>
|
||||||
|
<div class="editor-wrap">
|
||||||
|
<SchoolCalendarEditor
|
||||||
|
v-if="dialogVisible && semesterBh"
|
||||||
|
ref="editor"
|
||||||
|
mode="class"
|
||||||
|
:xydxqbh="semesterBh"
|
||||||
|
:xydbh="xydbh"
|
||||||
|
:range-start="rangeStart"
|
||||||
|
:range-end="rangeEnd"
|
||||||
|
:semester-name="titleText"
|
||||||
|
@close="dialogVisible = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ClassTeamSelectDialog
|
||||||
|
:visible="teamSelectVisible"
|
||||||
|
title="选择要覆盖班历的班次"
|
||||||
|
:semester-list="semesterOptions"
|
||||||
|
:exclude-bh="semesterBh"
|
||||||
|
:exclude-note="applyNote"
|
||||||
|
@update:visible="val => teamSelectVisible = val"
|
||||||
|
@confirm="handleTeamConfirm"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SchoolCalendarEditor from '@/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue'
|
||||||
|
import ClassTeamSelectDialog from './ClassTeamSelectDialog.vue'
|
||||||
|
import { applyClassCalendarEvent } from '@/api/teachOffice/classCalendarEvent'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ClassEventCalendarDialog',
|
||||||
|
components: { SchoolCalendarEditor, ClassTeamSelectDialog },
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, default: false },
|
||||||
|
semester: { type: Object, default: null },
|
||||||
|
semesterOptions: { type: Array, default: () => [] }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
teamSelectVisible: false,
|
||||||
|
applyWhole: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogVisible: {
|
||||||
|
get() { return this.visible },
|
||||||
|
set(val) { this.$emit('update:visible', val) }
|
||||||
|
},
|
||||||
|
semesterBh() {
|
||||||
|
return (this.semester && this.semester.bh) || ''
|
||||||
|
},
|
||||||
|
xydbh() {
|
||||||
|
return (this.semester && this.semester.xydbh) || ''
|
||||||
|
},
|
||||||
|
rangeStart() {
|
||||||
|
return this.fmtDate(this.semester && this.semester.kxrq)
|
||||||
|
},
|
||||||
|
rangeEnd() {
|
||||||
|
return this.fmtDate(this.semester && this.semester.jsrq)
|
||||||
|
},
|
||||||
|
titleText() {
|
||||||
|
const s = this.semester || {}
|
||||||
|
const name = s.xydmc || s.xydbh || ''
|
||||||
|
return name ? `${name} ${s.nd || ''}年 第${s.xqdc || '-'}学期` : '班历'
|
||||||
|
},
|
||||||
|
applyNote() {
|
||||||
|
return this.applyWhole
|
||||||
|
? '将覆盖目标班次相同日期和节次的班历事件,不改课程任务。'
|
||||||
|
: '只覆盖当前选中的时间格,不改课程任务。'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fmtDate(val) {
|
||||||
|
if (val == null || val === '') return ''
|
||||||
|
if (Array.isArray(val) && val.length >= 3) {
|
||||||
|
return `${val[0]}-${String(val[1]).padStart(2, '0')}-${String(val[2]).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
const year = val.year
|
||||||
|
const month = val.monthValue || val.month
|
||||||
|
const day = val.dayOfMonth || val.day
|
||||||
|
if (year && month && day) {
|
||||||
|
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return String(val).slice(0, 10)
|
||||||
|
},
|
||||||
|
handleApplyRegion() {
|
||||||
|
const editor = this.$refs.editor
|
||||||
|
const bhs = editor && editor.selectedEventBhs ? editor.selectedEventBhs() : []
|
||||||
|
if (!bhs.length) {
|
||||||
|
this.$message.warning('请先在班历中选定时间格')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.applyWhole = false
|
||||||
|
this.teamSelectVisible = true
|
||||||
|
},
|
||||||
|
handleApplyWhole() {
|
||||||
|
this.applyWhole = true
|
||||||
|
this.teamSelectVisible = true
|
||||||
|
},
|
||||||
|
handleTeamConfirm(rows) {
|
||||||
|
const targetBhList = (rows || []).map(item => item.bh).filter(Boolean)
|
||||||
|
if (!targetBhList.length) return
|
||||||
|
const editor = this.$refs.editor
|
||||||
|
const eventBhList = this.applyWhole
|
||||||
|
? []
|
||||||
|
: (editor && editor.selectedEventBhs ? editor.selectedEventBhs() : [])
|
||||||
|
applyClassCalendarEvent({
|
||||||
|
sourceXydxqbh: this.semesterBh,
|
||||||
|
targetBhList,
|
||||||
|
eventBhList
|
||||||
|
}).then(res => {
|
||||||
|
this.teamSelectVisible = false
|
||||||
|
this.$message.success(`已覆盖 ${res.data || 0} 个时间格`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dialog-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.editor-wrap {
|
||||||
|
height: 72vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
:visible="dialogVisible"
|
:visible="dialogVisible"
|
||||||
:title="isEdit ? '编辑班次学期信息' : '教学班次学期信息明细'"
|
:title="isEdit ? '编辑班次学期信息' : '教学班次学期信息明细'"
|
||||||
width="620px"
|
width="720px"
|
||||||
class="class-detail-dialog"
|
class="class-detail-dialog"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@update:visible="val => dialogVisible = val"
|
@update:visible="val => dialogVisible = val"
|
||||||
@@ -16,24 +16,41 @@
|
|||||||
</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="班次编号" prop="xydbh">
|
||||||
<el-input v-model="form.xydbh" :readonly="isEdit" :disabled="isEdit" placeholder="编辑模式不可修改" />
|
<el-select
|
||||||
|
v-if="!isEdit"
|
||||||
|
v-model="form.xydbh"
|
||||||
|
filterable
|
||||||
|
placeholder="请先选择年度和学期第次"
|
||||||
|
style="width: 100%"
|
||||||
|
:loading="classLoading"
|
||||||
|
@change="handleClassChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in creatableClasses"
|
||||||
|
:key="item.xydbh"
|
||||||
|
:label="classOptionLabel(item)"
|
||||||
|
:value="item.xydbh"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-input v-else v-model="form.xydbh" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="年度" prop="nd">
|
<el-form-item label="年度" prop="nd">
|
||||||
<el-select v-model="form.nd" placeholder="请选择年度" filterable style="width: 100%">
|
<el-select v-model="form.nd" placeholder="请选择年度" filterable style="width: 100%" @change="handleSemesterFilterChange">
|
||||||
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" />
|
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" />
|
||||||
</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="xqdc">
|
<el-form-item label="学期第次" prop="xqdc">
|
||||||
<el-select v-model="form.xqdc" placeholder="请选择学期" style="width: 100%">
|
<el-select v-model="form.xqdc" placeholder="请选择学期" style="width: 100%" :disabled="halfYear" @change="handleXqdcChange">
|
||||||
<el-option v-for="opt in levelOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
<el-option v-for="opt in levelOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<div v-if="halfYear" class="field-tip">学制半年以内,学期第次固定为第1学期</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -52,7 +69,25 @@
|
|||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="专用教室">
|
<el-form-item label="专用教室">
|
||||||
<el-input v-model="form.zyjsbh" placeholder="请输入专用教室编号" clearable />
|
<el-select
|
||||||
|
v-model="form.zyjsbh"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
remote
|
||||||
|
reserve-keyword
|
||||||
|
placeholder="按名称、编号或拼音查找"
|
||||||
|
style="width: 100%"
|
||||||
|
:remote-method="searchRooms"
|
||||||
|
:loading="roomLoading"
|
||||||
|
@focus="loadRooms()"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="room in roomOptions"
|
||||||
|
:key="room.id || room.jsbh"
|
||||||
|
:label="roomLabel(room)"
|
||||||
|
:value="room.id || room.jsbh"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@@ -79,6 +114,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { initClassSemester, listCreatableClasses, listSemesterRooms, presetSemesterDates } from '@/api/studentRecords/semester'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ClassSemesterDetailDialog',
|
name: 'ClassSemesterDetailDialog',
|
||||||
props: {
|
props: {
|
||||||
@@ -92,7 +129,9 @@ export default {
|
|||||||
/** 年度下拉 */
|
/** 年度下拉 */
|
||||||
yearOptions: { type: Array, default: () => [] },
|
yearOptions: { type: Array, default: () => [] },
|
||||||
/** 教学任务下拉({ bh, rwmc }) */
|
/** 教学任务下拉({ bh, rwmc }) */
|
||||||
taskOptions: { type: Array, default: () => [] }
|
taskOptions: { type: Array, default: () => [] },
|
||||||
|
/** 页面已吸取的开学/结束日期,作为半年以上班次的窗口预设 */
|
||||||
|
presetDates: { type: Object, default: () => ({ kxrq: '', jsrq: '' }) }
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -103,7 +142,13 @@ export default {
|
|||||||
{ label: '第3学期', value: 3 }
|
{ label: '第3学期', value: 3 }
|
||||||
],
|
],
|
||||||
saving: false,
|
saving: false,
|
||||||
|
classLoading: false,
|
||||||
|
creatableClasses: [],
|
||||||
|
halfYear: false,
|
||||||
|
roomLoading: false,
|
||||||
|
roomOptions: [],
|
||||||
rules: {
|
rules: {
|
||||||
|
xydbh: [{ required: true, message: '请选择可新建班次', trigger: 'change' }],
|
||||||
nd: [{ required: true, message: '请选择年度', trigger: 'change' }],
|
nd: [{ required: true, message: '请选择年度', trigger: 'change' }],
|
||||||
xqdc: [{ required: true, message: '请选择学期第次', trigger: 'change' }],
|
xqdc: [{ required: true, message: '请选择学期第次', trigger: 'change' }],
|
||||||
kxrq: [{ required: true, message: '请选择开学日期', trigger: 'change' }],
|
kxrq: [{ required: true, message: '请选择开学日期', trigger: 'change' }],
|
||||||
@@ -165,14 +210,119 @@ export default {
|
|||||||
form.jxrwbh = row.jxrwbh || undefined
|
form.jxrwbh = row.jxrwbh || undefined
|
||||||
form.kfjypk = Number(row.kfjypk) === 1
|
form.kfjypk = Number(row.kfjypk) === 1
|
||||||
form.bz = row.bz || ''
|
form.bz = row.bz || ''
|
||||||
|
this.ensureRoomOption(row.zyjsbh, row.zyjsmc)
|
||||||
} else if (this.teamInfo) {
|
} else if (this.teamInfo) {
|
||||||
form.xydbh = this.teamInfo.xydbh || ''
|
form.xydbh = this.teamInfo.xydbh || ''
|
||||||
form.xydmc = this.teamInfo.xydmc || ''
|
form.xydmc = this.teamInfo.xydmc || ''
|
||||||
// 默认取当前选中年度的第一学期,日期可后续修改
|
form.nd = this.yearOptions[0]
|
||||||
|
form.xqdc = 1
|
||||||
|
} else {
|
||||||
form.nd = this.yearOptions[0]
|
form.nd = this.yearOptions[0]
|
||||||
form.xqdc = 1
|
form.xqdc = 1
|
||||||
}
|
}
|
||||||
this.form = form
|
this.form = form
|
||||||
|
this.halfYear = false
|
||||||
|
if (!this.isEdit) this.loadCreatableClasses()
|
||||||
|
if (form.zyjsbh) this.ensureRoomOption(form.zyjsbh, this.semester && this.semester.zyjsmc)
|
||||||
|
},
|
||||||
|
classOptionLabel(item) {
|
||||||
|
return item.xydmc ? `${item.xydmc}(${item.xydbh})` : item.xydbh
|
||||||
|
},
|
||||||
|
handleSemesterFilterChange() {
|
||||||
|
if (this.isEdit) return
|
||||||
|
this.form.xydbh = ''
|
||||||
|
this.form.xydmc = ''
|
||||||
|
this.halfYear = false
|
||||||
|
this.loadCreatableClasses()
|
||||||
|
},
|
||||||
|
handleXqdcChange() {
|
||||||
|
this.handleSemesterFilterChange()
|
||||||
|
if (this.form.xydbh) this.applySmartDefaults(false)
|
||||||
|
},
|
||||||
|
loadCreatableClasses() {
|
||||||
|
if (!this.form.nd || !this.form.xqdc) {
|
||||||
|
this.creatableClasses = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.classLoading = true
|
||||||
|
listCreatableClasses({ nd: this.form.nd, xqdc: this.form.xqdc }).then(res => {
|
||||||
|
this.creatableClasses = (res && res.data) || []
|
||||||
|
this.classLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.creatableClasses = []
|
||||||
|
this.classLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleClassChange(xydbh) {
|
||||||
|
const item = this.creatableClasses.find(row => row.xydbh === xydbh)
|
||||||
|
this.form.xydmc = item ? (item.xydmc || '') : ''
|
||||||
|
this.applySmartDefaults(true)
|
||||||
|
},
|
||||||
|
applySmartDefaults(overwriteDates) {
|
||||||
|
if (!this.form.xydbh) return
|
||||||
|
const preset = this.presetDates || {}
|
||||||
|
initClassSemester({
|
||||||
|
xydbh: this.form.xydbh,
|
||||||
|
xqdc: this.form.xqdc,
|
||||||
|
presetKxrq: preset.kxrq || this.form.kxrq || undefined,
|
||||||
|
presetJsrq: preset.jsrq || this.form.jsrq || undefined
|
||||||
|
}).then(res => {
|
||||||
|
const data = (res && res.data) || {}
|
||||||
|
this.halfYear = !!data.halfYear
|
||||||
|
if (this.halfYear) {
|
||||||
|
this.form.xqdc = 1
|
||||||
|
this.form.kxrq = data.kxrq ? String(data.kxrq).slice(0, 10) : this.form.kxrq
|
||||||
|
this.form.jsrq = data.jsrq ? String(data.jsrq).slice(0, 10) : this.form.jsrq
|
||||||
|
} else if (overwriteDates) {
|
||||||
|
if (!this.form.kxrq && data.kxrq) this.form.kxrq = String(data.kxrq).slice(0, 10)
|
||||||
|
if (!this.form.jsrq && data.jsrq) this.form.jsrq = String(data.jsrq).slice(0, 10)
|
||||||
|
if (preset.kxrq) this.form.kxrq = preset.kxrq
|
||||||
|
if (preset.jsrq) this.form.jsrq = preset.jsrq
|
||||||
|
}
|
||||||
|
if (data.zyjsbh) {
|
||||||
|
this.form.zyjsbh = data.zyjsbh
|
||||||
|
this.ensureRoomOption(data.zyjsbh, data.zyjsmc)
|
||||||
|
}
|
||||||
|
if (!this.halfYear && overwriteDates && (!this.form.kxrq || !this.form.jsrq) && this.form.nd && this.form.xqdc) {
|
||||||
|
this.fillSchoolDates()
|
||||||
|
}
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
fillSchoolDates() {
|
||||||
|
presetSemesterDates({ nd: this.form.nd, xqdc: this.form.xqdc }).then(res => {
|
||||||
|
const data = (res && res.data) || {}
|
||||||
|
if (!this.form.kxrq && data.kxrq) this.form.kxrq = data.kxrq
|
||||||
|
if (!this.form.jsrq && data.jsrq) this.form.jsrq = data.jsrq
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
roomLabel(room) {
|
||||||
|
if (!room) return ''
|
||||||
|
const name = room.jsmc || room.zyjsmc || ''
|
||||||
|
const code = room.jsbh || room.id || ''
|
||||||
|
return name && code ? `${name}(${code})` : (name || code)
|
||||||
|
},
|
||||||
|
ensureRoomOption(id, name) {
|
||||||
|
if (!id) return
|
||||||
|
if (this.roomOptions.some(item => (item.id || item.jsbh) === id)) return
|
||||||
|
this.roomOptions = [{ id: id, jsbh: id, jsmc: name || '' }].concat(this.roomOptions)
|
||||||
|
},
|
||||||
|
loadRooms(keyword) {
|
||||||
|
this.roomLoading = true
|
||||||
|
listSemesterRooms({ py: keyword || undefined }).then(res => {
|
||||||
|
const list = (res && res.data) || []
|
||||||
|
const current = this.form.zyjsbh
|
||||||
|
const currentOpt = this.roomOptions.find(item => (item.id || item.jsbh) === current)
|
||||||
|
this.roomOptions = list
|
||||||
|
if (current && !list.some(item => item.id === current || item.jsbh === current)) {
|
||||||
|
this.ensureRoomOption(current, currentOpt && (currentOpt.jsmc || currentOpt.zyjsmc))
|
||||||
|
}
|
||||||
|
this.roomLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.roomLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
searchRooms(keyword) {
|
||||||
|
this.loadRooms(keyword)
|
||||||
},
|
},
|
||||||
/** 移除空值(保留 0 等有效值) */
|
/** 移除空值(保留 0 等有效值) */
|
||||||
cleanPayload(obj) {
|
cleanPayload(obj) {
|
||||||
@@ -218,6 +368,12 @@ export default {
|
|||||||
::v-deep .el-input__inner[readonly] {
|
::v-deep .el-input__inner[readonly] {
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
.field-tip {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,8 +54,12 @@
|
|||||||
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
|
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="xydbh" label="班次编号" min-width="150" align="center" show-overflow-tooltip />
|
<el-table-column prop="xydbh" label="班次编号" min-width="150" align="center" show-overflow-tooltip />
|
||||||
<el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" />
|
<el-table-column label="开学日期" width="110" align="center">
|
||||||
<el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" />
|
<template slot-scope="{ row }">{{ formatDate(row.kxrq) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="结束日期" width="110" align="center">
|
||||||
|
<template slot-scope="{ row }">{{ formatDate(row.jsrq) }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-empty v-if="!filteredList.length" description="暂无可选的目标班次学期" :image-size="60" />
|
<el-empty v-if="!filteredList.length" description="暂无可选的目标班次学期" :image-size="60" />
|
||||||
@@ -125,9 +129,22 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fmtDate(val) {
|
formatDate(val) {
|
||||||
if (!val) return '-'
|
if (val == null || val === '') return '-'
|
||||||
return String(val).slice(0, 10)
|
if (Array.isArray(val) && val.length >= 3) {
|
||||||
|
return `${val[0]}-${String(val[1]).padStart(2, '0')}-${String(val[2]).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
const year = val.year
|
||||||
|
const month = val.monthValue || val.month
|
||||||
|
const day = val.dayOfMonth || val.day
|
||||||
|
if (year && month && day) {
|
||||||
|
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
const text = String(val)
|
||||||
|
return text.length >= 10 ? text.slice(0, 10) : text
|
||||||
},
|
},
|
||||||
xqdcLabel(val) {
|
xqdcLabel(val) {
|
||||||
if (val === 1 || val === '1') return '第1学期'
|
if (val === 1 || val === '1') return '第1学期'
|
||||||
|
|||||||
@@ -22,11 +22,21 @@
|
|||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
style="width: 140px"
|
style="width: 140px"
|
||||||
@change="handleYearChange"
|
@change="handleQuery"
|
||||||
>
|
>
|
||||||
<el-option v-for="y in yearFilterOptions" :key="y" :label="`${y}年`" :value="y" />
|
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="学期第次">
|
||||||
|
<el-select v-model="searchForm.xqdc" placeholder="全部" clearable style="width: 120px" @change="handleQuery">
|
||||||
|
<el-option label="第1学期" :value="1" />
|
||||||
|
<el-option label="第2学期" :value="2" />
|
||||||
|
<el-option label="第3学期" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="sortWave" @change="handleQuery">按波次排序</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||||
@@ -42,10 +52,17 @@
|
|||||||
<el-button type="primary" plain icon="el-icon-edit" :disabled="!currentRow" @click="handleEdit">编辑</el-button>
|
<el-button type="primary" plain icon="el-icon-edit" :disabled="!currentRow" @click="handleEdit">编辑</el-button>
|
||||||
<el-button type="danger" plain icon="el-icon-delete" :disabled="!selection.length" @click="handleDelete">删除所选</el-button>
|
<el-button type="danger" plain icon="el-icon-delete" :disabled="!selection.length" @click="handleDelete">删除所选</el-button>
|
||||||
<el-button type="primary" plain icon="el-icon-date" :disabled="!selection.length" @click="handleQuickSetDates">快速设定学期日期</el-button>
|
<el-button type="primary" plain icon="el-icon-date" :disabled="!selection.length" @click="handleQuickSetDates">快速设定学期日期</el-button>
|
||||||
|
<el-button type="primary" plain icon="el-icon-download" :disabled="!currentRow" @click="handleAbsorbDates">吸取预设日期</el-button>
|
||||||
<el-button type="primary" plain icon="el-icon-notebook-2" :disabled="!selection.length" @click="handleSetJxrw">批量设置教学任务</el-button>
|
<el-button type="primary" plain icon="el-icon-notebook-2" :disabled="!selection.length" @click="handleSetJxrw">批量设置教学任务</el-button>
|
||||||
|
<el-button type="primary" plain :disabled="!selection.length" @click="handleSetXqdc">批量学期第次</el-button>
|
||||||
|
<el-button type="primary" plain :disabled="!selection.length" @click="handleSetKfjypk">开放教员排课</el-button>
|
||||||
|
<el-button type="warning" plain :disabled="selection.length < 2" @click="handleWaveMerge">预设合班</el-button>
|
||||||
|
<el-button type="warning" plain :disabled="!selection.length" @click="handleWaveSplit">预设拆班</el-button>
|
||||||
|
<el-button type="primary" plain :disabled="!selection.length" @click="handleBatchGenerateTasks">批量生成必修课程</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-group">
|
<div class="right-group">
|
||||||
<el-button type="success" plain icon="el-icon-calendar" :disabled="!currentRow" @click="handleEditCalendar">编辑班历</el-button>
|
<el-button type="success" plain icon="el-icon-date" :disabled="!currentRow" @click="handleEditEventCalendar">编辑班历</el-button>
|
||||||
|
<el-button type="success" plain icon="el-icon-calendar" :disabled="!currentRow" @click="handleEditCalendar">编辑班次教学任务</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -61,6 +78,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
max-height="480"
|
max-height="480"
|
||||||
class="class-table"
|
class="class-table"
|
||||||
|
:row-class-name="waveRowClass"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
>
|
>
|
||||||
@@ -69,17 +87,32 @@
|
|||||||
</template>
|
</template>
|
||||||
<el-table-column type="selection" width="44" align="center" />
|
<el-table-column type="selection" width="44" align="center" />
|
||||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||||
<el-table-column prop="xydbh" label="班次编号" min-width="150" align="center" show-overflow-tooltip />
|
<el-table-column prop="xydmc" label="班次名称" min-width="140" align="center" show-overflow-tooltip>
|
||||||
|
<template slot-scope="{ row }">{{ row.xydmc || '-' }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="xydbh" label="班次编号" min-width="130" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="ysbbh" label="预设编班号" width="100" align="center">
|
||||||
|
<template slot-scope="{ row }">{{ waveLabel(row.ysbbh) }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="nd" label="年度" width="80" align="center" show-overflow-tooltip />
|
<el-table-column prop="nd" label="年度" width="80" align="center" show-overflow-tooltip />
|
||||||
<el-table-column label="学期第次" width="90" align="center">
|
<el-table-column label="学期第次" width="90" align="center">
|
||||||
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
|
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" />
|
<el-table-column label="开学日期" width="110" align="center">
|
||||||
<el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" />
|
<template slot-scope="{ row }">{{ formatDate(row.kxrq) }}</template>
|
||||||
<el-table-column prop="zyjsbh" label="专用教室" width="100" align="center" show-overflow-tooltip />
|
</el-table-column>
|
||||||
|
<el-table-column label="结束日期" width="110" align="center">
|
||||||
|
<template slot-scope="{ row }">{{ formatDate(row.jsrq) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="专用教室" min-width="140" align="center" show-overflow-tooltip>
|
||||||
|
<template slot-scope="{ row }">{{ roomLabel(row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="教学任务" min-width="160" align="center" show-overflow-tooltip>
|
<el-table-column label="教学任务" min-width="160" align="center" show-overflow-tooltip>
|
||||||
<template slot-scope="{ row }">{{ taskName(row.jxrwbh) }}</template>
|
<template slot-scope="{ row }">{{ taskName(row.jxrwbh) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="zkcs" label="总课程数" width="90" align="center">
|
||||||
|
<template slot-scope="{ row }">{{ row.zkcs == null ? 0 : row.zkcs }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="开放教员排课" width="110" align="center">
|
<el-table-column label="开放教员排课" width="110" align="center">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
<el-tag v-if="Number(row.kfjypk) === 1" type="success" size="small">开放</el-tag>
|
<el-tag v-if="Number(row.kfjypk) === 1" type="success" size="small">开放</el-tag>
|
||||||
@@ -87,10 +120,11 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
|
||||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
<el-table-column label="操作" width="250" align="center" fixed="right">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
<el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
|
<el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
|
||||||
<el-button type="text" size="small" @click="handleEditCalendar(row)">班历</el-button>
|
<el-button type="text" size="small" @click="handleEditEventCalendar(row)">班历</el-button>
|
||||||
|
<el-button type="text" size="small" @click="handleEditCalendar(row)">教学任务</el-button>
|
||||||
<el-button type="text" size="small" class="text-danger" @click="handleDeleteRow(row)">删除</el-button>
|
<el-button type="text" size="small" class="text-danger" @click="handleDeleteRow(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -116,11 +150,12 @@
|
|||||||
:team-info="detailTeamInfo"
|
:team-info="detailTeamInfo"
|
||||||
:year-options="yearOptions"
|
:year-options="yearOptions"
|
||||||
:task-options="taskOptions"
|
:task-options="taskOptions"
|
||||||
|
:preset-dates="presetDates"
|
||||||
@update:visible="val => detailVisible = val"
|
@update:visible="val => detailVisible = val"
|
||||||
@submit="handleDetailSubmit"
|
@submit="handleDetailSubmit"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- ==================== 班历管理弹窗 ==================== -->
|
<!-- ==================== 班次教学任务弹窗 ==================== -->
|
||||||
<ClassCalendarDialog
|
<ClassCalendarDialog
|
||||||
:visible="calendarVisible"
|
:visible="calendarVisible"
|
||||||
:semester="calendarSemester"
|
:semester="calendarSemester"
|
||||||
@@ -128,6 +163,13 @@
|
|||||||
@update:visible="val => calendarVisible = val"
|
@update:visible="val => calendarVisible = val"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ClassEventCalendarDialog
|
||||||
|
:visible="eventCalendarVisible"
|
||||||
|
:semester="eventCalendarSemester"
|
||||||
|
:semester-options="semesterOptions"
|
||||||
|
@update:visible="val => eventCalendarVisible = val"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- ==================== 批量创建班次学期弹窗 ==================== -->
|
<!-- ==================== 批量创建班次学期弹窗 ==================== -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible="batchAddVisible"
|
:visible="batchAddVisible"
|
||||||
@@ -138,15 +180,15 @@
|
|||||||
>
|
>
|
||||||
<el-form ref="batchAddFormRef" :model="batchAddForm" :rules="batchAddRules" label-width="100px">
|
<el-form ref="batchAddFormRef" :model="batchAddForm" :rules="batchAddRules" label-width="100px">
|
||||||
<el-form-item label="年度" prop="nd">
|
<el-form-item label="年度" prop="nd">
|
||||||
<el-select v-model="batchAddForm.nd" placeholder="请选择年度" filterable style="width: 100%">
|
<el-select v-model="batchAddForm.nd" placeholder="请选择年度" filterable style="width: 100%" @change="loadBatchPreset">
|
||||||
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" />
|
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="学期" prop="xqdc">
|
<el-form-item label="学期" prop="xqdc">
|
||||||
<el-select v-model="batchAddForm.xqdc" placeholder="请选择学期" style="width: 100%">
|
<el-select v-model="batchAddForm.xqdc" placeholder="请选择学期" style="width: 100%" @change="loadBatchPreset">
|
||||||
<el-option label="春季学期" value="春季学期" />
|
<el-option label="第1学期" :value="1" />
|
||||||
<el-option label="夏季学期" value="夏季学期" />
|
<el-option label="第2学期" :value="2" />
|
||||||
<el-option label="秋季学期" value="秋季学期" />
|
<el-option label="第3学期" :value="3" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="开始日期" prop="startTime">
|
<el-form-item label="开始日期" prop="startTime">
|
||||||
@@ -155,6 +197,16 @@
|
|||||||
<el-form-item label="结束日期" prop="endTime">
|
<el-form-item label="结束日期" prop="endTime">
|
||||||
<el-date-picker v-model="batchAddForm.endTime" type="date" value-format="yyyy-MM-dd" placeholder="请选择结束日期" style="width: 100%" />
|
<el-date-picker v-model="batchAddForm.endTime" type="date" value-format="yyyy-MM-dd" placeholder="请选择结束日期" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button size="small" @click="loadBatchPreset">按学校学期带出日期</el-button>
|
||||||
|
<el-button size="small" :disabled="!currentRow" @click="absorbIntoBatch">吸取选中班次日期</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-alert
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
:title="`将为未毕业且尚未建立的班次创建学期信息,当前可新建 ${batchEligibleCount} 个班次`"
|
||||||
|
/>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<el-button @click="batchAddVisible = false">取消</el-button>
|
<el-button @click="batchAddVisible = false">取消</el-button>
|
||||||
@@ -218,13 +270,58 @@
|
|||||||
<el-button type="primary" :loading="saving" @click="handleJxrwSubmit">确定</el-button>
|
<el-button type="primary" :loading="saving" @click="handleJxrwSubmit">确定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible="xqdcVisible"
|
||||||
|
title="批量设定学期第次"
|
||||||
|
width="420px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@update:visible="val => xqdcVisible = val"
|
||||||
|
>
|
||||||
|
<el-form label-width="100px">
|
||||||
|
<el-form-item label="学期第次">
|
||||||
|
<el-select v-model="xqdcForm.xqdc" placeholder="请选择学期第次" style="width: 100%">
|
||||||
|
<el-option label="第1学期" :value="1" />
|
||||||
|
<el-option label="第2学期" :value="2" />
|
||||||
|
<el-option label="第3学期" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer">
|
||||||
|
<el-button @click="xqdcVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="saving" @click="handleXqdcSubmit">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible="kfjypkVisible"
|
||||||
|
title="批量设定开放教员排课"
|
||||||
|
width="420px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@update:visible="val => kfjypkVisible = val"
|
||||||
|
>
|
||||||
|
<el-form label-width="120px">
|
||||||
|
<el-form-item label="开放教员排课">
|
||||||
|
<el-radio-group v-model="kfjypkForm.kfjypk">
|
||||||
|
<el-radio :label="1">开放</el-radio>
|
||||||
|
<el-radio :label="0">关闭</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer">
|
||||||
|
<el-button @click="kfjypkVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="saving" @click="handleKfjypkSubmit">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ClassSemesterDetailDialog from './ClassSemesterDetailDialog.vue'
|
import ClassSemesterDetailDialog from './ClassSemesterDetailDialog.vue'
|
||||||
import ClassCalendarDialog from './ClassCalendarDialog.vue'
|
import ClassCalendarDialog from './ClassCalendarDialog.vue'
|
||||||
import { listSemester, allSemester, addSemester, updateSemester, delSemester, batchDeleteSemester, batchUpdateDateRange, batchUpdateJxrwbh, batchAddFromElective } from '@/api/studentRecords/semester'
|
import ClassEventCalendarDialog from './ClassEventCalendarDialog.vue'
|
||||||
|
import { batchAutoGenerateTasks } from '@/api/studentRecords/classCalendar'
|
||||||
|
import { listSemester, allSemester, addSemester, updateSemester, delSemester, batchDeleteSemester, batchUpdateDateRange, batchUpdateJxrwbh, batchCreateSemester, batchUpdateXqdc, batchUpdateKfjypk, batchWaveMerge, batchWaveSplit, listCreatableClasses, presetSemesterDates } from '@/api/studentRecords/semester'
|
||||||
import { listAllSemester } from '@/api/teachBusiness/semester'
|
import { listAllSemester } from '@/api/teachBusiness/semester'
|
||||||
import { listTeachingTask } from '@/api/teachBusiness/teachingTask'
|
import { listTeachingTask } from '@/api/teachBusiness/teachingTask'
|
||||||
|
|
||||||
@@ -232,7 +329,8 @@ export default {
|
|||||||
name: 'ShiftSemester',
|
name: 'ShiftSemester',
|
||||||
components: {
|
components: {
|
||||||
ClassSemesterDetailDialog,
|
ClassSemesterDetailDialog,
|
||||||
ClassCalendarDialog
|
ClassCalendarDialog,
|
||||||
|
ClassEventCalendarDialog
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -240,9 +338,10 @@ export default {
|
|||||||
saving: false,
|
saving: false,
|
||||||
|
|
||||||
// ==================== 查询条件 ====================
|
// ==================== 查询条件 ====================
|
||||||
searchForm: { xydbh: '' },
|
searchForm: { xydbh: '', xqdc: undefined },
|
||||||
filterYear: undefined,
|
filterYear: undefined,
|
||||||
yearFilterOptions: [],
|
sortWave: true,
|
||||||
|
presetDates: { kxrq: '', jsrq: '' },
|
||||||
|
|
||||||
// ==================== 列表与分页 ====================
|
// ==================== 列表与分页 ====================
|
||||||
tableData: [],
|
tableData: [],
|
||||||
@@ -269,10 +368,13 @@ export default {
|
|||||||
// ==================== 班历管理 ====================
|
// ==================== 班历管理 ====================
|
||||||
calendarVisible: false,
|
calendarVisible: false,
|
||||||
calendarSemester: null,
|
calendarSemester: null,
|
||||||
|
eventCalendarVisible: false,
|
||||||
|
eventCalendarSemester: null,
|
||||||
|
|
||||||
// ==================== 批量创建班次学期 ====================
|
// ==================== 批量创建班次学期 ====================
|
||||||
batchAddVisible: false,
|
batchAddVisible: false,
|
||||||
batchAddForm: { nd: undefined, xqdc: '', startTime: '', endTime: '' },
|
batchAddForm: { nd: undefined, xqdc: undefined, startTime: '', endTime: '' },
|
||||||
|
batchEligibleCount: 0,
|
||||||
batchAddRules: {
|
batchAddRules: {
|
||||||
nd: [{ required: true, message: '请选择年度', trigger: 'change' }],
|
nd: [{ required: true, message: '请选择年度', trigger: 'change' }],
|
||||||
xqdc: [{ required: true, message: '请选择学期', trigger: 'change' }],
|
xqdc: [{ required: true, message: '请选择学期', trigger: 'change' }],
|
||||||
@@ -293,14 +395,16 @@ export default {
|
|||||||
jxrwForm: { jxrwbh: undefined },
|
jxrwForm: { jxrwbh: undefined },
|
||||||
jxrwRules: {
|
jxrwRules: {
|
||||||
jxrwbh: [{ required: true, message: '请选择教学任务', trigger: 'change' }]
|
jxrwbh: [{ required: true, message: '请选择教学任务', trigger: 'change' }]
|
||||||
}
|
},
|
||||||
|
xqdcVisible: false,
|
||||||
|
xqdcForm: { xqdc: 1 },
|
||||||
|
kfjypkVisible: false,
|
||||||
|
kfjypkForm: { kfjypk: 1 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
/** 本地按年度过滤(后端 /semester/list 仅支持 xydbh 模糊筛选) */
|
|
||||||
displayData() {
|
displayData() {
|
||||||
if (!this.filterYear) return this.tableData
|
return this.tableData
|
||||||
return this.tableData.filter(item => String(item.nd) === String(this.filterYear))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -311,9 +415,42 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* ==================== 格式化 ==================== */
|
/* ==================== 格式化 ==================== */
|
||||||
fmtDate(val) {
|
formatDate(val) {
|
||||||
if (!val) return '-'
|
if (val == null || val === '') return '-'
|
||||||
return String(val).slice(0, 10)
|
if (Array.isArray(val) && val.length >= 3) {
|
||||||
|
return `${val[0]}-${String(val[1]).padStart(2, '0')}-${String(val[2]).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
const year = val.year
|
||||||
|
const month = val.monthValue || val.month
|
||||||
|
const day = val.dayOfMonth || val.day
|
||||||
|
if (year && month && day) {
|
||||||
|
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
const text = String(val)
|
||||||
|
return text.length >= 10 ? text.slice(0, 10) : text
|
||||||
|
},
|
||||||
|
yearFromNd(nd) {
|
||||||
|
const text = String(nd || '')
|
||||||
|
if (text.length >= 6) return Number(text.slice(0, 4))
|
||||||
|
const n = Number(text)
|
||||||
|
return Number.isFinite(n) && n > 0 ? n : null
|
||||||
|
},
|
||||||
|
roomLabel(row) {
|
||||||
|
if (!row) return '-'
|
||||||
|
if (row.zyjsmc && row.zyjsbh) return `${row.zyjsmc}(${row.zyjsbh})`
|
||||||
|
return row.zyjsmc || row.zyjsbh || '-'
|
||||||
|
},
|
||||||
|
waveLabel(val) {
|
||||||
|
const n = Number(val)
|
||||||
|
return n > 0 ? n : '未编波'
|
||||||
|
},
|
||||||
|
waveRowClass({ row }) {
|
||||||
|
const n = Number(row.ysbbh)
|
||||||
|
if (!n) return ''
|
||||||
|
return 'wave-row wave-row-' + (n % 8)
|
||||||
},
|
},
|
||||||
xqdcLabel(val) {
|
xqdcLabel(val) {
|
||||||
if (val === 1 || val === '1') return '第1学期'
|
if (val === 1 || val === '1') return '第1学期'
|
||||||
@@ -342,7 +479,7 @@ export default {
|
|||||||
loadYearOptions() {
|
loadYearOptions() {
|
||||||
listAllSemester().then(res => {
|
listAllSemester().then(res => {
|
||||||
const list = (res && res.data) || []
|
const list = (res && res.data) || []
|
||||||
const years = list.map(x => x.nd).filter(v => v !== undefined && v !== null && v !== '')
|
const years = list.map(x => this.yearFromNd(x.nd)).filter(v => v)
|
||||||
this.yearOptions = [...new Set(years)].sort((a, b) => Number(a) - Number(b))
|
this.yearOptions = [...new Set(years)].sort((a, b) => Number(a) - Number(b))
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.yearOptions = []
|
this.yearOptions = []
|
||||||
@@ -370,13 +507,15 @@ export default {
|
|||||||
const query = this.cleanPayload({
|
const query = this.cleanPayload({
|
||||||
pageNum: this.pageNum,
|
pageNum: this.pageNum,
|
||||||
pageSize: this.pageSize,
|
pageSize: this.pageSize,
|
||||||
xydbh: this.searchForm.xydbh
|
xydbh: this.searchForm.xydbh,
|
||||||
|
nd: this.filterYear,
|
||||||
|
xqdc: this.searchForm.xqdc,
|
||||||
|
sortWave: this.sortWave ? 1 : 0
|
||||||
})
|
})
|
||||||
listSemester(query).then(res => {
|
listSemester(query).then(res => {
|
||||||
const data = (res && res.data) || {}
|
const data = (res && res.data) || {}
|
||||||
this.tableData = data.records || []
|
this.tableData = data.records || []
|
||||||
this.total = data.total || 0
|
this.total = data.total || 0
|
||||||
this.buildYearFilterOptions()
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.tableData = []
|
this.tableData = []
|
||||||
@@ -384,17 +523,6 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 本地年度过滤下拉(从当前数据动态生成,避免硬编码) */
|
|
||||||
buildYearFilterOptions() {
|
|
||||||
const years = this.tableData.map(r => r.nd).filter(v => v !== undefined && v !== null && v !== '')
|
|
||||||
this.yearFilterOptions = [...new Set(years)].sort((a, b) => Number(a) - Number(b))
|
|
||||||
},
|
|
||||||
handleYearChange() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.tableRef) this.$refs.tableRef.setCurrentRow(null)
|
|
||||||
this.currentRow = null
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleSizeChange(size) {
|
handleSizeChange(size) {
|
||||||
this.pageSize = size
|
this.pageSize = size
|
||||||
this.loadList()
|
this.loadList()
|
||||||
@@ -417,6 +545,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleReset() {
|
handleReset() {
|
||||||
this.searchForm.xydbh = ''
|
this.searchForm.xydbh = ''
|
||||||
|
this.searchForm.xqdc = undefined
|
||||||
this.filterYear = undefined
|
this.filterYear = undefined
|
||||||
this.pageNum = 1
|
this.pageNum = 1
|
||||||
this.loadList()
|
this.loadList()
|
||||||
@@ -462,7 +591,7 @@ export default {
|
|||||||
this.$message.warning('请先勾选要删除的班次学期')
|
this.$message.warning('请先勾选要删除的班次学期')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$confirm(`确定删除选中的 ${this.selection.length} 条班次学期吗?删除后其下班历记录将一并删除。`, '提示', {
|
this.$confirm(`确定删除选中的 ${this.selection.length} 条班次学期吗?若已有课程任务将禁止删除。`, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
@@ -476,7 +605,7 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
handleDeleteRow(row) {
|
handleDeleteRow(row) {
|
||||||
this.$confirm(`确定删除班次学期「${row.xydbh || row.bh}」吗?删除后其下班历记录将一并删除。`, '提示', {
|
this.$confirm(`确定删除班次学期「${row.xydbh || row.bh}」吗?若已有课程任务将禁止删除。`, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
@@ -489,7 +618,33 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ==================== 编辑班历 ==================== */
|
handleEditEventCalendar(row) {
|
||||||
|
const target = row || this.currentRow
|
||||||
|
if (!target) {
|
||||||
|
this.$message.warning('请先在列表中选择一条班次学期信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.eventCalendarSemester = target
|
||||||
|
this.eventCalendarVisible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBatchGenerateTasks() {
|
||||||
|
if (!this.selection.length) {
|
||||||
|
this.$message.warning('请先勾选班次学期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const ids = this.selection.map(item => item.bh).filter(Boolean)
|
||||||
|
this.$confirm(`将为所选 ${ids.length} 个班次学期按人培补齐必修课程,已有课程不会重复生成。`, '批量生成必修课程', {
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
batchAutoGenerateTasks(ids).then(res => {
|
||||||
|
this.$message.success(`已生成 ${res.data || 0} 条课程任务`)
|
||||||
|
this.loadList()
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
|
||||||
|
/* ==================== 编辑班次教学任务 ==================== */
|
||||||
handleEditCalendar(row) {
|
handleEditCalendar(row) {
|
||||||
const target = row || this.currentRow
|
const target = row || this.currentRow
|
||||||
if (!target) {
|
if (!target) {
|
||||||
@@ -502,26 +657,53 @@ export default {
|
|||||||
|
|
||||||
/* ==================== 批量创建班次学期 ==================== */
|
/* ==================== 批量创建班次学期 ==================== */
|
||||||
handleBatchAdd() {
|
handleBatchAdd() {
|
||||||
this.batchAddForm = { nd: this.yearOptions[0] || undefined, xqdc: '', startTime: '', endTime: '' }
|
this.batchAddForm = {
|
||||||
|
nd: this.filterYear || this.yearOptions[this.yearOptions.length - 1] || undefined,
|
||||||
|
xqdc: this.searchForm.xqdc || 1,
|
||||||
|
startTime: this.presetDates.kxrq || '',
|
||||||
|
endTime: this.presetDates.jsrq || ''
|
||||||
|
}
|
||||||
|
this.batchEligibleCount = 0
|
||||||
this.batchAddVisible = true
|
this.batchAddVisible = true
|
||||||
|
this.loadBatchPreset()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.$refs.batchAddFormRef) this.$refs.batchAddFormRef.clearValidate()
|
if (this.$refs.batchAddFormRef) this.$refs.batchAddFormRef.clearValidate()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
loadBatchPreset() {
|
||||||
|
const f = this.batchAddForm
|
||||||
|
if (!f.nd || !f.xqdc) return
|
||||||
|
presetSemesterDates({ nd: f.nd, xqdc: f.xqdc }).then(res => {
|
||||||
|
const data = (res && res.data) || {}
|
||||||
|
if (data.kxrq) this.batchAddForm.startTime = data.kxrq
|
||||||
|
if (data.jsrq) this.batchAddForm.endTime = data.jsrq
|
||||||
|
}).catch(() => {})
|
||||||
|
listCreatableClasses({ nd: f.nd, xqdc: f.xqdc }).then(res => {
|
||||||
|
this.batchEligibleCount = ((res && res.data) || []).length
|
||||||
|
}).catch(() => {
|
||||||
|
this.batchEligibleCount = 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
absorbIntoBatch() {
|
||||||
|
if (!this.currentRow) return
|
||||||
|
this.absorbDatesFrom(this.currentRow)
|
||||||
|
this.batchAddForm.startTime = this.presetDates.kxrq
|
||||||
|
this.batchAddForm.endTime = this.presetDates.jsrq
|
||||||
|
},
|
||||||
handleBatchAddSubmit() {
|
handleBatchAddSubmit() {
|
||||||
this.$refs.batchAddFormRef.validate(valid => {
|
this.$refs.batchAddFormRef.validate(valid => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
const f = this.batchAddForm
|
const f = this.batchAddForm
|
||||||
this.saving = true
|
this.saving = true
|
||||||
batchAddFromElective({
|
batchCreateSemester({
|
||||||
nd: f.nd,
|
nd: f.nd,
|
||||||
xqdc: f.xqdc,
|
xqdc: f.xqdc,
|
||||||
startTime: f.startTime,
|
kxrq: f.startTime,
|
||||||
endTime: f.endTime
|
jsrq: f.endTime
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.saving = false
|
this.saving = false
|
||||||
this.batchAddVisible = false
|
this.batchAddVisible = false
|
||||||
const count = (res && res.data) || 0
|
const count = Number((res && res.data) || 0)
|
||||||
this.$message.success(`已创建 ${count} 个班次学期`)
|
this.$message.success(`已创建 ${count} 个班次学期`)
|
||||||
this.loadList()
|
this.loadList()
|
||||||
this.loadSemesterOptions()
|
this.loadSemesterOptions()
|
||||||
@@ -530,6 +712,79 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
handleAbsorbDates() {
|
||||||
|
if (!this.currentRow) {
|
||||||
|
this.$message.warning('请先选中一条班次学期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.absorbDatesFrom(this.currentRow)
|
||||||
|
this.$message.success(`已吸取开学日期 ${this.presetDates.kxrq}、结束日期 ${this.presetDates.jsrq}`)
|
||||||
|
},
|
||||||
|
absorbDatesFrom(row) {
|
||||||
|
this.presetDates = {
|
||||||
|
kxrq: this.formatDate(row.kxrq) === '-' ? '' : this.formatDate(row.kxrq),
|
||||||
|
jsrq: this.formatDate(row.jsrq) === '-' ? '' : this.formatDate(row.jsrq)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSetXqdc() {
|
||||||
|
if (!this.selection.length) return
|
||||||
|
this.xqdcForm = { xqdc: this.selection[0].xqdc || 1 }
|
||||||
|
this.xqdcVisible = true
|
||||||
|
},
|
||||||
|
handleXqdcSubmit() {
|
||||||
|
this.saving = true
|
||||||
|
batchUpdateXqdc({
|
||||||
|
bhList: this.selection.map(r => r.bh),
|
||||||
|
xqdc: this.xqdcForm.xqdc
|
||||||
|
}).then(res => {
|
||||||
|
this.saving = false
|
||||||
|
this.xqdcVisible = false
|
||||||
|
this.$message.success(`已更新 ${Number((res && res.data) || 0)} 条学期第次`)
|
||||||
|
this.loadList()
|
||||||
|
}).catch(() => {
|
||||||
|
this.saving = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleSetKfjypk() {
|
||||||
|
if (!this.selection.length) return
|
||||||
|
this.kfjypkForm = { kfjypk: 1 }
|
||||||
|
this.kfjypkVisible = true
|
||||||
|
},
|
||||||
|
handleKfjypkSubmit() {
|
||||||
|
this.saving = true
|
||||||
|
batchUpdateKfjypk({
|
||||||
|
bhList: this.selection.map(r => r.bh),
|
||||||
|
kfjypk: this.kfjypkForm.kfjypk
|
||||||
|
}).then(res => {
|
||||||
|
this.saving = false
|
||||||
|
this.kfjypkVisible = false
|
||||||
|
this.$message.success(`已更新 ${Number((res && res.data) || 0)} 条开放教员排课`)
|
||||||
|
this.loadList()
|
||||||
|
}).catch(() => {
|
||||||
|
this.saving = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleWaveMerge() {
|
||||||
|
if (this.selection.length < 2) {
|
||||||
|
this.$message.warning('请至少勾选两个班次')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm(`将选中的 ${this.selection.length} 个班次设为同一预设编班号。只改编波,不改课次序号。`, '预设合班', {
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => batchWaveMerge({ bhList: this.selection.map(r => r.bh) })).then(res => {
|
||||||
|
this.$message.success(`已合班 ${Number((res && res.data) || 0)} 个班次`)
|
||||||
|
this.loadList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
handleWaveSplit() {
|
||||||
|
if (!this.selection.length) return
|
||||||
|
this.$confirm(`将选中的 ${this.selection.length} 个班次各自独立成波。只改编波,不改课次序号。`, '预设拆班', {
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => batchWaveSplit({ bhList: this.selection.map(r => r.bh) })).then(res => {
|
||||||
|
this.$message.success(`已拆班 ${Number((res && res.data) || 0)} 个班次`)
|
||||||
|
this.loadList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
|
||||||
/* ==================== 快速设定学期日期 ==================== */
|
/* ==================== 快速设定学期日期 ==================== */
|
||||||
handleQuickSetDates() {
|
handleQuickSetDates() {
|
||||||
@@ -537,7 +792,10 @@ export default {
|
|||||||
this.$message.warning('请先勾选要设定日期的班次学期')
|
this.$message.warning('请先勾选要设定日期的班次学期')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.dateRangeForm = { kxrq: '', jsrq: '' }
|
this.dateRangeForm = {
|
||||||
|
kxrq: this.presetDates.kxrq || '',
|
||||||
|
jsrq: this.presetDates.jsrq || ''
|
||||||
|
}
|
||||||
this.dateRangeVisible = true
|
this.dateRangeVisible = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.$refs.dateRangeFormRef) this.$refs.dateRangeFormRef.clearValidate()
|
if (this.$refs.dateRangeFormRef) this.$refs.dateRangeFormRef.clearValidate()
|
||||||
@@ -651,6 +909,15 @@ export default {
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::v-deep .wave-row-1 td { background: #f0f9eb !important; }
|
||||||
|
::v-deep .wave-row-2 td { background: #ecf5ff !important; }
|
||||||
|
::v-deep .wave-row-3 td { background: #fdf6ec !important; }
|
||||||
|
::v-deep .wave-row-4 td { background: #fef0f0 !important; }
|
||||||
|
::v-deep .wave-row-5 td { background: #f4f4f5 !important; }
|
||||||
|
::v-deep .wave-row-6 td { background: #f0f9ff !important; }
|
||||||
|
::v-deep .wave-row-7 td { background: #f9f0ff !important; }
|
||||||
|
::v-deep .wave-row-0 td { background: #fff7e6 !important; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-select v-model="searchForm.zt" placeholder="请选择状态" clearable style="width: 140px">
|
<el-select v-model="searchForm.zt" placeholder="请选择状态" clearable style="width: 140px">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="opt in statusOptions"
|
v-for="opt in searchStatusOptions"
|
||||||
:key="opt.value"
|
:key="opt.value"
|
||||||
:label="opt.label"
|
:label="opt.label"
|
||||||
:value="opt.value"
|
:value="opt.value"
|
||||||
@@ -54,8 +54,8 @@
|
|||||||
<el-table-column prop="nd" label="年度" width="150" align="center" />
|
<el-table-column prop="nd" label="年度" width="150" align="center" />
|
||||||
<el-table-column label="状态" width="100" align="center">
|
<el-table-column label="状态" width="100" align="center">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
<el-tag :type="row.zt === '发布' ? 'success' : 'info'" size="small">
|
<el-tag :type="taskTagType(row.zt)" size="small">
|
||||||
{{ row.zt || '-' }}
|
{{ taskStatusLabel(row.zt) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -63,17 +63,23 @@
|
|||||||
<el-table-column prop="jssj" label="结束时间" width="180" align="center" :formatter="fmtDateTime" />
|
<el-table-column prop="jssj" label="结束时间" width="180" align="center" :formatter="fmtDateTime" />
|
||||||
<el-table-column prop="cjsj" label="创建时间" width="180" align="center" :formatter="fmtDateTime" />
|
<el-table-column prop="cjsj" label="创建时间" width="180" align="center" :formatter="fmtDateTime" />
|
||||||
<el-table-column prop="jcxqscsj" label="教材需求生成时间" align="center" :formatter="fmtDateTime" />
|
<el-table-column prop="jcxqscsj" label="教材需求生成时间" align="center" :formatter="fmtDateTime" />
|
||||||
<el-table-column label="操作" width="300" align="center" fixed="right">
|
<el-table-column label="操作" width="380" align="center" fixed="right">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
<el-button type="text" size="small" @click="handleDetail(row)">详情</el-button>
|
<el-button type="text" size="small" @click="handleDetail(row)">详情</el-button>
|
||||||
<el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
|
<el-button type="text" size="small" :disabled="isTaskLocked(row)" @click="handleEdit(row)">编辑</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
:disabled="row.zt === '发布'"
|
:disabled="isTaskPublished(row) || isTaskEnded(row)"
|
||||||
@click="handlePublish(row)"
|
@click="handlePublish(row)"
|
||||||
>发布</el-button>
|
>发布</el-button>
|
||||||
<el-button type="text" size="small" class="text-danger" @click="handleDelete(row)">删除</el-button>
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
:disabled="!isTaskPublished(row)"
|
||||||
|
@click="handleEndPublish(row)"
|
||||||
|
>结束发布</el-button>
|
||||||
|
<el-button type="text" size="small" class="text-danger" :disabled="isTaskEnded(row)" @click="handleDelete(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -116,7 +122,7 @@
|
|||||||
<el-form-item label="状态" prop="zt">
|
<el-form-item label="状态" prop="zt">
|
||||||
<el-select v-model="form.zt" placeholder="请选择状态" style="width: 100%">
|
<el-select v-model="form.zt" placeholder="请选择状态" style="width: 100%">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="opt in statusOptions"
|
v-for="opt in formStatusOptions"
|
||||||
:key="opt.value"
|
:key="opt.value"
|
||||||
:label="opt.label"
|
:label="opt.label"
|
||||||
:value="opt.value"
|
:value="opt.value"
|
||||||
@@ -197,7 +203,8 @@ import {
|
|||||||
addTeachingTask,
|
addTeachingTask,
|
||||||
updateTeachingTask,
|
updateTeachingTask,
|
||||||
deleteTeachingTask,
|
deleteTeachingTask,
|
||||||
publishTeachingTask
|
publishTeachingTask,
|
||||||
|
endPublishTeachingTask
|
||||||
} from '@/api/teachBusiness/teachingTask'
|
} from '@/api/teachBusiness/teachingTask'
|
||||||
import { listAllSemester } from '@/api/teachBusiness/semester'
|
import { listAllSemester } from '@/api/teachBusiness/semester'
|
||||||
|
|
||||||
@@ -212,7 +219,13 @@ export default {
|
|||||||
zt: ''
|
zt: ''
|
||||||
},
|
},
|
||||||
yearOptions: [],
|
yearOptions: [],
|
||||||
statusOptions: [
|
searchStatusOptions: [
|
||||||
|
{ label: '未发布', value: '未发布' },
|
||||||
|
{ label: '发布', value: '发布' },
|
||||||
|
{ label: '已发布', value: '已发布' },
|
||||||
|
{ label: '已结束', value: '已结束' }
|
||||||
|
],
|
||||||
|
formStatusOptions: [
|
||||||
{ label: '未发布', value: '未发布' },
|
{ label: '未发布', value: '未发布' },
|
||||||
{ label: '发布', value: '发布' }
|
{ label: '发布', value: '发布' }
|
||||||
],
|
],
|
||||||
@@ -425,6 +438,25 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isTaskPublished(row) {
|
||||||
|
return row && (row.zt === '发布' || row.zt === '已发布')
|
||||||
|
},
|
||||||
|
isTaskEnded(row) {
|
||||||
|
return row && row.zt === '已结束'
|
||||||
|
},
|
||||||
|
isTaskLocked(row) {
|
||||||
|
return this.isTaskPublished(row) || this.isTaskEnded(row)
|
||||||
|
},
|
||||||
|
taskStatusLabel(zt) {
|
||||||
|
if (zt === '已结束') return '已结束'
|
||||||
|
if (zt === '发布' || zt === '已发布') return '已发布'
|
||||||
|
return zt || '未发布'
|
||||||
|
},
|
||||||
|
taskTagType(zt) {
|
||||||
|
if (zt === '已结束') return 'warning'
|
||||||
|
if (zt === '发布' || zt === '已发布') return 'success'
|
||||||
|
return 'info'
|
||||||
|
},
|
||||||
/* ---------- 发布 ---------- */
|
/* ---------- 发布 ---------- */
|
||||||
handlePublish(row) {
|
handlePublish(row) {
|
||||||
this.$confirm(`确定要发布教学任务「${row.rwmc || row.bh || '该记录'}」吗?发布前请先填写关联的教研室任务书。`, '系统提示', {
|
this.$confirm(`确定要发布教学任务「${row.rwmc || row.bh || '该记录'}」吗?发布前请先填写关联的教研室任务书。`, '系统提示', {
|
||||||
@@ -435,6 +467,16 @@ export default {
|
|||||||
this.$message.success('发布成功')
|
this.$message.success('发布成功')
|
||||||
this.fetchList()
|
this.fetchList()
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
handleEndPublish(row) {
|
||||||
|
this.$confirm(`确定要结束发布教学任务「${row.rwmc || row.bh || '该记录'}」吗?结束后任务书和班次课程任务将只读。`, '系统提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => endPublishTeachingTask(row.bh)).then(() => {
|
||||||
|
this.$message.success('已结束发布')
|
||||||
|
this.fetchList()
|
||||||
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user