Kaynağa Gözat

Merge branch 'pre'

dzx 11 ay önce
ebeveyn
işleme
69366e76f6
100 değiştirilmiş dosya ile 4951 ekleme ve 628 silme
  1. 18 0
      src/main/java/com/xjrsoft/common/enums/ArchivesStatusEnum.java
  2. 42 0
      src/main/java/com/xjrsoft/common/enums/RoleCodeEnum.java
  3. 36 0
      src/main/java/com/xjrsoft/common/enums/StudentChangeTypeEnum.java
  4. 15 0
      src/main/java/com/xjrsoft/common/enums/StudyStatusEnum.java
  5. 134 110
      src/main/java/com/xjrsoft/module/base/controller/BaseClassCourseController.java
  6. 48 0
      src/main/java/com/xjrsoft/module/base/dto/AddBaseClassAdminCourseDto.java
  7. 5 1
      src/main/java/com/xjrsoft/module/base/dto/ClassCourseReuseDto.java
  8. 98 0
      src/main/java/com/xjrsoft/module/base/entity/BaseClassAdminCourse.java
  9. 1 1
      src/main/java/com/xjrsoft/module/base/entity/BaseClassCourse.java
  10. 6 10
      src/main/java/com/xjrsoft/module/base/entity/ClassCourseTextbook.java
  11. 17 0
      src/main/java/com/xjrsoft/module/base/mapper/BaseClassAdminCourseMapper.java
  12. 10 3
      src/main/java/com/xjrsoft/module/base/service/IBaseClassCourseService.java
  13. 3 0
      src/main/java/com/xjrsoft/module/base/service/IBaseClassService.java
  14. 228 193
      src/main/java/com/xjrsoft/module/base/service/impl/BaseClassCourseServiceImpl.java
  15. 24 0
      src/main/java/com/xjrsoft/module/base/service/impl/BaseClassServiceImpl.java
  16. 6 0
      src/main/java/com/xjrsoft/module/ledger/controller/LedgerStatisticsController.java
  17. 7 1
      src/main/java/com/xjrsoft/module/liteflow/node/StudentChangeClassNode.java
  18. 20 0
      src/main/java/com/xjrsoft/module/liteflow/node/StudentDropOutNode.java
  19. 4 0
      src/main/java/com/xjrsoft/module/liteflow/node/StudentTransferNode.java
  20. 6 0
      src/main/java/com/xjrsoft/module/liteflow/node/TemporaryChangeClassNode.java
  21. 8 0
      src/main/java/com/xjrsoft/module/liteflow/node/WfRoomApplicantNode.java
  22. 3 0
      src/main/java/com/xjrsoft/module/liteflow/node/WfSchoolRollStudentNode.java
  23. 0 1
      src/main/java/com/xjrsoft/module/organization/controller/UserController.java
  24. 2 2
      src/main/java/com/xjrsoft/module/schedule/controller/ScheduleController.java
  25. 117 0
      src/main/java/com/xjrsoft/module/student/controller/StudentChangeRecordController.java
  26. 210 0
      src/main/java/com/xjrsoft/module/student/controller/StudentReportPlanController.java
  27. 90 0
      src/main/java/com/xjrsoft/module/student/controller/StudentReportRecordController.java
  28. 47 0
      src/main/java/com/xjrsoft/module/student/dto/AddStudentChangeRecordDto.java
  29. 32 0
      src/main/java/com/xjrsoft/module/student/dto/AddStudentReportPlanClassRelationDto.java
  30. 68 0
      src/main/java/com/xjrsoft/module/student/dto/AddStudentReportPlanDto.java
  31. 7 0
      src/main/java/com/xjrsoft/module/student/dto/BaseStudentUserPageDto.java
  32. 0 1
      src/main/java/com/xjrsoft/module/student/dto/MajorGradeClassDto.java
  33. 41 0
      src/main/java/com/xjrsoft/module/student/dto/StudentChangeRecordPageDto.java
  34. 27 0
      src/main/java/com/xjrsoft/module/student/dto/StudentReportPlanPageDto.java
  35. 21 0
      src/main/java/com/xjrsoft/module/student/dto/StudentReportPlanStatusDto.java
  36. 38 0
      src/main/java/com/xjrsoft/module/student/dto/StudentReportRecordPageDto.java
  37. 5 0
      src/main/java/com/xjrsoft/module/student/dto/StudentReportRecordStatisticsDto.java
  38. 18 0
      src/main/java/com/xjrsoft/module/student/dto/StudentReportSignDto.java
  39. 24 0
      src/main/java/com/xjrsoft/module/student/dto/UpdateStudentChangeRecordDto.java
  40. 24 0
      src/main/java/com/xjrsoft/module/student/dto/UpdateStudentReportPlanDto.java
  41. 106 0
      src/main/java/com/xjrsoft/module/student/entity/StudentChangeRecord.java
  42. 119 0
      src/main/java/com/xjrsoft/module/student/entity/StudentReportPlan.java
  43. 43 0
      src/main/java/com/xjrsoft/module/student/entity/StudentReportPlanClassRelation.java
  44. 3 0
      src/main/java/com/xjrsoft/module/student/entity/StudentReportRecord.java
  45. 2 1
      src/main/java/com/xjrsoft/module/student/mapper/BaseStudentMapper.java
  46. 21 0
      src/main/java/com/xjrsoft/module/student/mapper/StudentChangeRecordMapper.java
  47. 16 0
      src/main/java/com/xjrsoft/module/student/mapper/StudentReportPlanClassRelationMapper.java
  48. 27 0
      src/main/java/com/xjrsoft/module/student/mapper/StudentReportPlanMapper.java
  49. 5 0
      src/main/java/com/xjrsoft/module/student/mapper/StudentReportRecordMapper.java
  50. 30 0
      src/main/java/com/xjrsoft/module/student/service/IStudentChangeRecordService.java
  51. 1 0
      src/main/java/com/xjrsoft/module/student/service/IStudentManagerService.java
  52. 51 0
      src/main/java/com/xjrsoft/module/student/service/IStudentReportPlanService.java
  53. 16 0
      src/main/java/com/xjrsoft/module/student/service/IStudentReportRecordService.java
  54. 19 0
      src/main/java/com/xjrsoft/module/student/service/impl/SchoolRollStudentServiceImpl.java
  55. 156 0
      src/main/java/com/xjrsoft/module/student/service/impl/StudentChangeRecordServiceImpl.java
  56. 10 6
      src/main/java/com/xjrsoft/module/student/service/impl/StudentManagerServiceImpl.java
  57. 213 0
      src/main/java/com/xjrsoft/module/student/service/impl/StudentReportPlanServiceImpl.java
  58. 118 0
      src/main/java/com/xjrsoft/module/student/service/impl/StudentReportRecordServiceImpl.java
  59. 0 2
      src/main/java/com/xjrsoft/module/student/vo/BaseStudentAssessmentInspectionMobileVo.java
  60. 72 0
      src/main/java/com/xjrsoft/module/student/vo/StudentChangeRecordPageVo.java
  61. 48 0
      src/main/java/com/xjrsoft/module/student/vo/StudentChangeRecordVo.java
  62. 36 0
      src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanClassRelationVo.java
  63. 122 0
      src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanPageVo.java
  64. 32 0
      src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanTreeVo.java
  65. 66 0
      src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanVo.java
  66. 77 0
      src/main/java/com/xjrsoft/module/student/vo/StudentReportRecordPlanPageVo.java
  67. 0 1
      src/main/java/com/xjrsoft/module/textbook/controller/SubjectGroupCourseController.java
  68. 35 29
      src/main/java/com/xjrsoft/module/textbook/controller/TextbookSubscriptionController.java
  69. 112 0
      src/main/java/com/xjrsoft/module/textbook/controller/TextbookSubscriptionItemHistoryController.java
  70. 5 1
      src/main/java/com/xjrsoft/module/textbook/dto/AddTextbookSubscriptionItemDto.java
  71. 123 0
      src/main/java/com/xjrsoft/module/textbook/dto/AddTextbookSubscriptionItemHistoryDto.java
  72. 14 3
      src/main/java/com/xjrsoft/module/textbook/dto/BaseclassPageDto.java
  73. 10 4
      src/main/java/com/xjrsoft/module/textbook/dto/TextbookInstockroomDto.java
  74. 49 0
      src/main/java/com/xjrsoft/module/textbook/dto/TextbookSubscriptionItemHistoryPageDto.java
  75. 3 3
      src/main/java/com/xjrsoft/module/textbook/dto/TextbookSubscriptionListDto.java
  76. 61 0
      src/main/java/com/xjrsoft/module/textbook/dto/UpdateTextbookSubscriptionItemDto.java
  77. 32 0
      src/main/java/com/xjrsoft/module/textbook/dto/UpdateTextbookSubscriptionItemHistoryDto.java
  78. 10 1
      src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItem.java
  79. 98 0
      src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItemClass.java
  80. 173 0
      src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItemHistory.java
  81. 17 0
      src/main/java/com/xjrsoft/module/textbook/mapper/TextbookSubscriptionItemClassMapper.java
  82. 17 0
      src/main/java/com/xjrsoft/module/textbook/mapper/TextbookSubscriptionItemHistoryMapper.java
  83. 1 1
      src/main/java/com/xjrsoft/module/textbook/service/ITextbookService.java
  84. 17 0
      src/main/java/com/xjrsoft/module/textbook/service/ITextbookSubscriptionItemHistoryService.java
  85. 8 0
      src/main/java/com/xjrsoft/module/textbook/service/ITextbookSubscriptionService.java
  86. 193 118
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookServiceImpl.java
  87. 25 0
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookSubscriptionItemHistoryServiceImpl.java
  88. 288 71
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookSubscriptionServiceImpl.java
  89. 29 29
      src/main/java/com/xjrsoft/module/textbook/service/impl/WfTextbookSubscriptionServiceImpl.java
  90. 218 0
      src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemHistoryPageVo.java
  91. 124 0
      src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemHistoryVo.java
  92. 7 0
      src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemPageVo.java
  93. 5 0
      src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionListVo.java
  94. 38 34
      src/main/resources/mapper/base/BaseClassCourse.xml
  95. 7 1
      src/main/resources/mapper/student/BaseStudentMapper.xml
  96. 31 0
      src/main/resources/mapper/student/StudentChangeRecordMapper.xml
  97. 35 0
      src/main/resources/mapper/student/StudentReportPlanMapper.xml
  98. 121 0
      src/main/resources/mapper/student/StudentReportRecordMapper.xml
  99. 10 0
      src/main/resources/sqlScript/20250116_sql.sql
  100. 116 0
      src/main/resources/sqlScript/20250120_sql.sql

+ 18 - 0
src/main/java/com/xjrsoft/common/enums/ArchivesStatusEnum.java

@@ -1,5 +1,8 @@
 package com.xjrsoft.common.enums;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * @author dzx
  * @date 2023/12/1
@@ -51,6 +54,16 @@ public enum ArchivesStatusEnum {
     final String code;
     final String value;
 
+    private static final Map<String, String> lookup = new HashMap<>();
+
+    static {
+        for (ArchivesStatusEnum s : ArchivesStatusEnum.values()) {
+            lookup.put(s.getCode(), s.getValue());
+        }
+    }
+
+
+
     public String getCode() {
         return this.code;
     }
@@ -63,4 +76,9 @@ public enum ArchivesStatusEnum {
         this.code = code;
         this.value = message;
     }
+
+    public static String fromCode(String code) {
+        return lookup.get(code);
+    }
+
 }

+ 42 - 0
src/main/java/com/xjrsoft/common/enums/RoleCodeEnum.java

@@ -0,0 +1,42 @@
+package com.xjrsoft.common.enums;
+
+
+/**
+ * 系统角色编码
+ */
+public enum RoleCodeEnum {
+    /**
+     * 超级管理员
+     */
+    ADMIN("ADMIN", "超级管理员"),
+    /**
+     * 教师
+     */
+    TEACHER("TEACHER", "教师"),
+    /**
+     * 学生
+     */
+    STUDENT("STUDENT", "学生"),
+    /**
+     * 家长
+     */
+    PARENT("PARENT", "家长"),
+
+    CLASSTE("CLASSTE", "班主任");
+
+    final String code;
+    final String value;
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+
+    RoleCodeEnum(final String code, final String message) {
+        this.code = code;
+        this.value = message;
+    }
+}

+ 36 - 0
src/main/java/com/xjrsoft/common/enums/StudentChangeTypeEnum.java

@@ -0,0 +1,36 @@
+package com.xjrsoft.common.enums;
+
+/**
+ * @description: 学生异动类型
+ * @author: dzx
+ * @create: 2025年1月20日10:54:34
+ * @Version 1.0
+ */
+public enum StudentChangeTypeEnum {
+
+    ChangeClass("change_class", "转班"),
+
+    StduyStatus("stduy_status", "就读方式"),
+
+    StudentType("student_type", "学生类别"),
+
+    LearnStatus("learn_status", "学习形式"),
+
+    ArchivesStatus("archives_status", "在读状态");
+
+    final String code;
+    final String value;
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+
+    StudentChangeTypeEnum(final String code, final String message) {
+        this.code = code;
+        this.value = message;
+    }
+}

+ 15 - 0
src/main/java/com/xjrsoft/common/enums/StudyStatusEnum.java

@@ -1,5 +1,8 @@
 package com.xjrsoft.common.enums;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * @description: 就读方式stduy_status
  * @author: phoenix
@@ -30,6 +33,14 @@ public enum StudyStatusEnum {
     final String code;
     final String value;
 
+    private static final Map<String, String> lookup = new HashMap<>();
+
+    static {
+        for (ArchivesStatusEnum s : ArchivesStatusEnum.values()) {
+            lookup.put(s.getCode(), s.getValue());
+        }
+    }
+
     public String getCode() {
         return this.code;
     }
@@ -42,4 +53,8 @@ public enum StudyStatusEnum {
         this.code = code;
         this.value = message;
     }
+
+    public static String fromCode(String code) {
+        return lookup.get(code);
+    }
 }

+ 134 - 110
src/main/java/com/xjrsoft/module/base/controller/BaseClassCourseController.java

@@ -4,37 +4,32 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.bean.BeanUtil;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.support.ExcelTypeEnum;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
-import com.xjrsoft.module.base.dto.AddBaseClassCourseDto;
-import com.xjrsoft.module.base.dto.BaseClassCourseListDto;
-import com.xjrsoft.module.base.dto.BaseClassCoursePageDto;
-import com.xjrsoft.module.base.dto.ClassCourseReuseDto;
-import com.xjrsoft.module.base.dto.UpdateBaseClassCourseDto;
-import com.xjrsoft.module.base.entity.BaseClass;
-import com.xjrsoft.module.base.entity.BaseClassCourse;
-import com.xjrsoft.module.base.entity.BaseCourseSubject;
-import com.xjrsoft.module.base.entity.BaseSemester;
-import com.xjrsoft.module.base.entity.ClassCourseTextbook;
-import com.xjrsoft.module.base.entity.CourseBookInfo;
+import com.xjrsoft.module.base.dto.*;
+import com.xjrsoft.module.base.entity.*;
+import com.xjrsoft.module.base.mapper.BaseClassAdminCourseMapper;
 import com.xjrsoft.module.base.service.IBaseClassCourseService;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseCourseSubjectService;
 import com.xjrsoft.module.base.service.IBaseSemesterService;
 import com.xjrsoft.module.base.vo.*;
-import com.xjrsoft.module.base.dto.ClassCourseTextbookExportQueryDto;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
 import com.xjrsoft.module.textbook.entity.Textbook;
 import com.xjrsoft.module.textbook.service.ITextbookService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.ObjectUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.ResponseEntity;
@@ -56,6 +51,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @title: 班级课程
@@ -68,23 +64,20 @@ import java.util.Map;
 @Api(value = "/base" + "/baseClassCourse", tags = "班级课程代码")
 @AllArgsConstructor
 public class BaseClassCourseController {
-
-
     private static final Logger log = LoggerFactory.getLogger(BaseClassCourseController.class);
     private final IBaseClassCourseService baseClassCourseService;
     private final IBaseCourseSubjectService subjectService;
     private final ITextbookService textbookService;
     private final IBaseClassService classService;
     private final IBaseSemesterService semesterService;
+    private final BaseClassAdminCourseMapper baseClassAdminCourseMapper;
 
     @GetMapping(value = "/page")
     @ApiOperation(value = "班级课程列表(分页)")
     @SaCheckPermission("baseclasscourse:detail")
     public RT<PageOutput<BaseClassCoursePageVo>> page(@Valid BaseClassCoursePageDto dto) {
         if(dto.getSemester() == null || dto.getSemester() == 0){
-            Page<BaseClassCoursePageVo> page = new Page<>();
-            page.setRecords(new ArrayList<>());
-            return RT.ok(ConventPage.getPageOutput(page, BaseClassCoursePageVo.class));
+            return RT.ok(ConventPage.getPageOutputNull(BaseClassCoursePageVo.class));
         }
         Page<BaseClassCoursePageVo> page = baseClassCourseService.getPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
         PageOutput<BaseClassCoursePageVo> pageOutput = ConventPage.getPageOutput(page, BaseClassCoursePageVo.class);
@@ -94,49 +87,16 @@ public class BaseClassCourseController {
     @GetMapping(value = "/list")
     @ApiOperation(value = "单个班级班级课程列表")
     @SaCheckPermission("baseclasscourse:detail")
-    public RT<List<BaseClassCourseListVo>> list(@Valid BaseClassCourseListDto dto) {
-        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
-        baseClassCourseMPJLambdaWrapper
-                .disableSubLogicDel()
-                .select(BaseClassCourse::getId)
-                .selectAs(BaseClass::getName, BaseClassCourseListVo::getClassIdCn)
-                .selectAs(BaseCourseSubject::getName, BaseClassCourseListVo::getCourseIdCn)
-                .selectAs(Textbook::getBookName, BaseClassCourseListVo::getTextbookIdCn)
-                .selectAs(BaseSemester::getName, BaseClassCourseListVo::getBaseSemesterIdCn)
-                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseListVo.class).contains(x.getProperty()))
-                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassCourse::getClassId)
-                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
-                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
-                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassCourse::getBaseSemesterId)
-                .eq(dto.getBaseSemesterId() != null && dto.getBaseSemesterId() > 0, BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .eq(dto.getClassId() != null && dto.getClassId() > 0, BaseClassCourse::getClassId, dto.getClassId())
-                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-                ;
-        List<BaseClassCourseListVo> baseClassCourseListVoList = baseClassCourseService.selectJoinList(BaseClassCourseListVo.class, baseClassCourseMPJLambdaWrapper);
+    public RT<List<BaseClassCourseListVo>> oneClassClassCourseList(@Valid BaseClassCourseListDto dto) {
+        List<BaseClassCourseListVo> baseClassCourseListVoList = baseClassCourseService.oneClassClassCourseList(dto);
         return RT.ok(baseClassCourseListVoList);
     }
 
     @GetMapping(value = "/mobile-list")
-    @ApiOperation(value = "单个班级班级课程列表")
+    @ApiOperation(value = "单个班级班级课程列表(移动端)")
     @SaCheckPermission("baseclasscourse:detail")
-    public RT<List<BaseClassCourseMobileListVo>> mobileList(@Valid BaseClassCourseListDto dto) {
-        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
-        baseClassCourseMPJLambdaWrapper
-                .disableSubLogicDel()
-                .select(BaseClassCourse::getId)
-                .selectAs(BaseCourseSubject::getName, BaseClassCourseMobileListVo::getCourseName)
-                .selectAs(Textbook::getBookName, BaseClassCourseMobileListVo::getBookName)
-                .selectAs(Textbook::getPrice, BaseClassCourseMobileListVo::getPrice)
-                .selectAs(DictionaryDetail::getName, BaseClassCourseMobileListVo::getTextbookTypeName)
-                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseMobileListVo.class).contains(x.getProperty()))
-                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
-                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
-                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,Textbook::getTextbookType)
-                .eq(dto.getBaseSemesterId() != null && dto.getBaseSemesterId() > 0, BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .eq(dto.getClassId() != null && dto.getClassId() > 0, BaseClassCourse::getClassId, dto.getClassId())
-                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-        ;
-        List<BaseClassCourseMobileListVo> baseClassCourseListVoList = baseClassCourseService.selectJoinList(BaseClassCourseMobileListVo.class, baseClassCourseMPJLambdaWrapper);
+    public RT<List<BaseClassCourseMobileListVo>> mobileOneClassClassCourseList(@Valid BaseClassCourseListDto dto) {
+        List<BaseClassCourseMobileListVo> baseClassCourseListVoList = baseClassCourseService.mobileOneClassClassCourseList(dto);
         return RT.ok(baseClassCourseListVoList);
     }
 
@@ -168,10 +128,13 @@ public class BaseClassCourseController {
     }
 
     @GetMapping("/getAllSelectedCoursesAndTextbooks")
-    @ApiOperation(value = "获取所有以选择课程教材")
+    @ApiOperation(value = "获取所有已经选择的课程教材")
     @SaCheckPermission("baseclasscourse:detail")
     public RT<List<CourseBookInfo>> getAllSelectedCoursesAndTextbooks(@RequestParam(required = false) Long[] classIds, @RequestParam(required = false) Long semester) {
         List<CourseBookInfo> data = baseClassCourseService.getSelectedCourseBook(classIds, semester);
+        if(ObjectUtils.isEmpty(data)){
+            return RT.ok(new ArrayList<>());
+        }
         return RT.ok(data);
     }
 
@@ -179,6 +142,9 @@ public class BaseClassCourseController {
     @ApiOperation(value = "单个班级更新课程教材")
     @SaCheckPermission("baseclasscourse:detail")
     public RT<Boolean> oneUpdateClassCoursesAndTextbooks(@Valid @RequestBody ClassCourseTextbook dto) {
+        if (ObjectUtils.isEmpty(dto.getBaseClassAdminCourseIds())) {
+            throw new MyException("请选中班级");
+        }
         return RT.ok(baseClassCourseService.oneUpdateClassCoursesAndTextbooks(dto));
     }
 
@@ -186,6 +152,9 @@ public class BaseClassCourseController {
     @ApiOperation(value = "更新增加课程教材")
     @SaCheckPermission("baseclasscourse:detail")
     public RT<Boolean> updateAddCoursesAndTextbooks(@Valid @RequestBody ClassCourseTextbook dto) {
+        if (ObjectUtils.isEmpty(dto.getBaseClassAdminCourseIds())) {
+            throw new MyException("请选中班级");
+        }
         return RT.ok(baseClassCourseService.updateAddCourseBook(dto));
     }
 
@@ -203,6 +172,14 @@ public class BaseClassCourseController {
         return RT.ok(baseClassCourseService.duplicateCourseBook(dto));
     }
 
+    @PostMapping("/setting_up_classes")
+    @ApiOperation(value = "设置需要进行课程管理的班级")
+    @SaCheckPermission("baseclasscourse:add")
+    public RT<Boolean> settingUpClasses(@Valid @RequestBody AddBaseClassAdminCourseDto dto) {
+        boolean isSuccess = baseClassCourseService.settingUpClasses(dto);
+        return RT.ok(isSuccess);
+    }
+
     @PostMapping
     @ApiOperation(value = "新增班级课程")
     @SaCheckPermission("baseclasscourse:add")
@@ -229,8 +206,19 @@ public class BaseClassCourseController {
         return RT.ok(baseClassCourseService.removeBatchByIds(ids));
     }
 
+    @DeleteMapping("/deleteSetting_up_classes")
+    @ApiOperation(value = "移除需要进行课程管理的班级")
+    @SaCheckPermission("baseclasscourse:add")
+    public RT<Boolean> deleteSettingUpClasses(@Valid @RequestBody List<Long> ids) {
+        if(ObjectUtils.isEmpty(ids) || ids.isEmpty()){
+            return RT.ok(true);
+        }
+        boolean isSuccess = baseClassCourseService.deleteSettingUpClasses(ids);
+        return RT.ok(isSuccess);
+    }
+
     @PostMapping("/import")
-    @ApiOperation(value = "导入")
+    @ApiOperation(value = "班级课程导入")
     public RT<Boolean> importData(@RequestParam MultipartFile file) throws IOException {
         List<BaseClassCourseExcelVo> savedDataList = EasyExcel.read(file.getInputStream()).headRowNumber(3).head(BaseClassCourseExcelVo.class).sheet().doReadSync();
 
@@ -242,84 +230,120 @@ public class BaseClassCourseController {
         for (BaseClass baseClass : classList) {
             classMap.put(baseClass.getName(), baseClass.getId());
         }
+        if(ObjectUtils.isEmpty(classMap)){
+            throw new MyException("系统中还没有维护班级数据");
+        }
         List<BaseCourseSubject> courseSubjectList = subjectService.list(new QueryWrapper<BaseCourseSubject>());
         Map<String, Long> courseSubjectMap = new HashMap<>();
         for (BaseCourseSubject baseCourseSubject : courseSubjectList) {
             courseSubjectMap.put(baseCourseSubject.getName(), baseCourseSubject.getId());
         }
+        if(ObjectUtils.isEmpty(courseSubjectMap)){
+            throw new MyException("系统中还没有维护课程学科数据");
+        }
         List<Textbook> textbookList = textbookService.list(new QueryWrapper<Textbook>());
         Map<String, Long> textbookMap = new HashMap<>();
         for (Textbook textbook : textbookList) {
             textbookMap.put(textbook.getBookName(), textbook.getId());
         }
-
+        if(ObjectUtils.isEmpty(textbookMap)){
+            throw new MyException("系统中还没有维护教材数据");
+        }
         List<BaseSemester> semesterList = semesterService.list(new QueryWrapper<BaseSemester>());
         Map<String, Long> semesterMap = new HashMap<>();
         for (BaseSemester baseSemester : semesterList) {
             semesterMap.put(baseSemester.getName(), baseSemester.getId());
         }
-
-        for (BaseClassCourseExcelVo vo : savedDataList) {
-            if(vo.getClassName() == null){
+        if(ObjectUtils.isEmpty(semesterMap)){
+            throw new MyException("系统中还没有维护学期数据");
+        }
+        // 已经维护了课程教材信息的班级和所在学期
+        List<BaseClassAdminCourse> baseClassAdminCourses = baseClassAdminCourseMapper.selectList(
+                Wrappers.lambdaQuery(BaseClassAdminCourse.class)
+                        .eq(BaseClassAdminCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+        );
+        Map<String, Long> classSemester = new HashMap<>();
+        for (BaseClassAdminCourse baseClassAdminCourse : baseClassAdminCourses) {
+            classSemester.put(baseClassAdminCourse.getClassId() + "_" + baseClassAdminCourse.getBaseSemesterId(), baseClassAdminCourse.getId());
+        }
+        // 所有的班级课程数据
+        List<BaseClassCourse> oldList = baseClassCourseService.list(
+                Wrappers.lambdaQuery(BaseClassCourse.class)
+                        .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+        );
+        // 使用Stream API和Lambda表达式生成所需的字符串列表
+        Map<Long, List<String>> courseIdTextbookIdMap = oldList.stream()
+                .collect(Collectors.groupingBy(
+                        BaseClassCourse::getClassId,
+                        Collectors.mapping(
+                                course -> course.getCourseId() + "_" + course.getTextbookId(),
+                                Collectors.toList()
+                        )
+                ));
+
+        // 开始处理导入
+        BaseClassCourse baseClassCourse;
+        for (int i = 0; i < savedDataList.size(); i++) {
+            baseClassCourse = new BaseClassCourse();
+            BaseClassCourseExcelVo vo = savedDataList.get(i);
+            if(ObjectUtils.isEmpty(vo.getClassName())
+                || ObjectUtils.isEmpty(vo.getSemester())
+            ){
                 continue;
             }
-            if(vo.getTextbookName() != null){
-                String[] textbookNames = vo.getTextbookName().split(" ");
-                for (String textbookName : textbookNames) {
-                    try {
-                        Long classId = classMap.get(vo.getClassName());
-                        Long courseId = courseSubjectMap.get(vo.getCourseName());
-                        Long textbookId = textbookMap.get(textbookName);
-                        Long baseSemesterId = semesterMap.get(vo.getSemester());
-
-                        if (baseClassCourseService.checkExits(classId, courseId, textbookId)) {
-                            duplicateLogs.add(String.format("[输入的信息重复添加] 班级: %s, 课程: %s, 教材: %s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName()));
-                            continue;
-                        }
-
-                        if (classId != null && courseId != null && textbookId != null && baseSemesterId != null) {
-                            BaseClassCourse baseClassCourse = new BaseClassCourse();
-                            baseClassCourse.setClassId(classId);
-                            baseClassCourse.setCourseId(courseId);
-                            baseClassCourse.setTextbookId(textbookId);
-                            baseClassCourse.setCreateDate(new Date());
-                            baseClassCourse.setDeleteMark(0);
-                            baseClassCourse.setBaseSemesterId(baseSemesterId);
-                            baseClassCourses.add(baseClassCourse);
-                        }
-                    } catch (NumberFormatException e) {
-                        errorLogs.add(String.format("[无法解析输入的信息] 班级: %s, 班级: %s, 教材: %s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName()));
-                    } catch (Exception e) {
-                        errorLogs.add(String.format("[意外错误(检查输入的名称是否正确且存在,输入错误可能返回 null)] 班级: %s, 课程: %s, 教材: %s - 错误信息:%s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName(), e.getMessage()));
-                    }
-                }
-            }else{
-                Long classId = classMap.get(vo.getClassName());
-                Long courseId = courseSubjectMap.get(vo.getCourseName());
-                Long baseSemesterId = semesterMap.get(vo.getSemester());
-                if (baseClassCourseService.checkExitsWithoutTextbook(classId, courseId)) {
-                    continue;
-                }
 
-                BaseClassCourse baseClassCourse = new BaseClassCourse();
-                baseClassCourse.setClassId(classId);
+            // 判断当前学期当前班级是否已经成为添加课程的班级
+            Long classId = classMap.get(vo.getClassName());;
+            Long baseSemesterId = semesterMap.get(vo.getSemester());
+            if(ObjectUtils.isEmpty(classId)){
+                throw new MyException("第" + (i + 4) + "行数据的班级信息不存在于系统中");
+            }
+            if(ObjectUtils.isEmpty(baseSemesterId)){
+                throw new MyException("第" + (i + 4) + "行数据的学期信息不存在于系统中");
+            }
+
+            // 判断本学期本班级是否已经加入课程管理的班级中
+            String newClassSemester = classId + "_" + baseSemesterId;
+            Long classAdminCourseId = null;
+            BaseClassAdminCourse baseClassAdminCourse = null;
+            if(ObjectUtils.isNotEmpty(classSemester) && classSemester.containsKey(newClassSemester)){
+                classAdminCourseId = classSemester.get(newClassSemester);
+            } else {
+                baseClassAdminCourse = new BaseClassAdminCourse();
+                baseClassAdminCourse.setClassId(classId);
+                baseClassAdminCourse.setBaseSemesterId(baseSemesterId);
+                baseClassAdminCourseMapper.insert(baseClassAdminCourse);
+                classSemester.put(newClassSemester, baseClassAdminCourse.getId());
+            }
+
+            baseClassCourse.setClassId(classAdminCourseId);
+
+            Long courseId = null;
+            Long textbookId = null;
+            if(ObjectUtils.isNotEmpty(vo.getCourseName())){
+                courseId = courseSubjectMap.get(vo.getCourseName());
                 baseClassCourse.setCourseId(courseId);
-                baseClassCourse.setCreateDate(new Date());
-                baseClassCourse.setDeleteMark(0);
-                baseClassCourse.setBaseSemesterId(baseSemesterId);
-                baseClassCourse.setCreateDate(new Date());
-                baseClassCourses.add(baseClassCourse);
             }
 
-        }
+            if(ObjectUtils.isNotEmpty(vo.getTextbookName())){
+                textbookId = textbookMap.get(vo.getTextbookName());
+                baseClassCourse.setTextbookId(textbookId);
+            }
 
-        Boolean result = baseClassCourseService.saveBatch(baseClassCourses);
+            if(ObjectUtils.isNotEmpty(courseId) && ObjectUtils.isNotEmpty(textbookId)){
+                String courseIdTextbookId = courseId + "_" + textbookId;
+                if(ObjectUtils.isNotEmpty(courseIdTextbookIdMap) && ObjectUtils.isNotEmpty(courseIdTextbookIdMap.get(classAdminCourseId))){
+                    List<String> courseIdTextbookIdList = courseIdTextbookIdMap.get(classAdminCourseId);
+                    if(courseIdTextbookIdList.contains(courseIdTextbookId)){
+                        continue;
+                    }
+                }
+            }
 
-        if (!duplicateLogs.isEmpty() || !errorLogs.isEmpty()) {
-            String detailedMessage = String.format("[导入完成但存在问题] 问题: %s. 其他错误: %s", String.join("; ", duplicateLogs), String.join("; ", errorLogs));
-            return RT.error(400, detailedMessage);
+            baseClassCourses.add(baseClassCourse);
         }
 
+        Boolean result = baseClassCourseService.saveBatch(baseClassCourses);
         return RT.ok(result);
     }
 

+ 48 - 0
src/main/java/com/xjrsoft/module/base/dto/AddBaseClassAdminCourseDto.java

@@ -0,0 +1,48 @@
+package com.xjrsoft.module.base.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+
+/**
+* @title: 需要进行课程管理的班级
+* @Author phoenix
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+public class AddBaseClassAdminCourseDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 备注
+    */
+    @ApiModelProperty("备注")
+    private String remark;
+    /**
+    * 班级id(base_class)
+    */
+    @ApiModelProperty("班级id(base_class)")
+    private List<Long> classIds;
+    /**
+    * 学期id
+    */
+    @ApiModelProperty("学期id")
+    private Long baseSemesterId;
+
+}

+ 5 - 1
src/main/java/com/xjrsoft/module/base/dto/ClassCourseReuseDto.java

@@ -2,7 +2,9 @@ package com.xjrsoft.module.base.dto;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import lombok.NonNull;
 
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.util.List;
 
@@ -22,6 +24,7 @@ public class ClassCourseReuseDto implements Serializable {
     * 旧的班级id
     */
     @ApiModelProperty("旧的班级id")
+    @NotNull(message = "被复用的班级不能为空")
     private Long oldClassId;
     /**
      * 新的班级id集合
@@ -31,7 +34,8 @@ public class ClassCourseReuseDto implements Serializable {
     /**
      * 旧的学期ID
      */
-    @ApiModelProperty("旧的学期ID")
+    @ApiModelProperty(value = "旧的学期ID", required = true)
+    @NotNull(message = "被复用的学期不能为空")
     private Long oldBaseSemesterId;
     /**
      * 新的学期ID

+ 98 - 0
src/main/java/com/xjrsoft/module/base/entity/BaseClassAdminCourse.java

@@ -0,0 +1,98 @@
+package com.xjrsoft.module.base.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.github.yulichang.annotation.EntityMapping;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+/**
+* @title: 需要进行课程管理的班级
+* @Author phoenix
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+@TableName("base_class_admin_course")
+@ApiModel(value = "base_class_admin_course", description = "需要进行课程管理的班级")
+public class BaseClassAdminCourse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人
+    */
+    @ApiModelProperty("修改人")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改时间
+    */
+    @ApiModelProperty("修改时间")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+    /**
+    * 有效标志
+    */
+    @ApiModelProperty("有效标志")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer enabledMark;
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 备注
+    */
+    @ApiModelProperty("备注")
+    private String remark;
+    /**
+    * 班级id(base_class)
+    */
+    @ApiModelProperty("班级id(base_class)")
+    private Long classId;
+    /**
+    * 学期id
+    */
+    @ApiModelProperty("学期id")
+    private Long baseSemesterId;
+
+
+}

+ 1 - 1
src/main/java/com/xjrsoft/module/base/entity/BaseClassCourse.java

@@ -77,7 +77,7 @@ public class BaseClassCourse implements Serializable {
     /**
     * 班级id(base_class)
     */
-    @ApiModelProperty("班级id(base_class)")
+    @ApiModelProperty("需要进行课程管理的班级id(base_class_admin_course)(原有班级主键id字段)")
     private Long classId;
     /**
     * 课程id(base_course_subject)

+ 6 - 10
src/main/java/com/xjrsoft/module/base/entity/ClassCourseTextbook.java

@@ -3,19 +3,15 @@ package com.xjrsoft.module.base.entity;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.util.List;
+
 @Data
 public class ClassCourseTextbook {
-    @ApiModelProperty("班级id")
-    private Long[] classIds;
-
-    @ApiModelProperty("主键id")
-    private String[] ids;
-
-    @ApiModelProperty(value = "课程id", hidden = true)
-    private Long[] courseId;
+    @ApiModelProperty("需要设置课程教材的班级id")
+    private List<Long> baseClassAdminCourseIds;
 
-    @ApiModelProperty(value = "教材id", hidden = true)
-    private Long[] textbookId;
+    @ApiModelProperty("课程主键和教材主键合并的id")
+    private List<String> ids;
 
     /**
      * 学期ID(base_semester)

+ 17 - 0
src/main/java/com/xjrsoft/module/base/mapper/BaseClassAdminCourseMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.base.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.base.entity.BaseClassAdminCourse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 需要进行课程管理的班级
+* @Author phoenix
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Mapper
+public interface BaseClassAdminCourseMapper extends MPJBaseMapper<BaseClassAdminCourse> {
+
+}

+ 10 - 3
src/main/java/com/xjrsoft/module/base/service/IBaseClassCourseService.java

@@ -2,13 +2,13 @@ package com.xjrsoft.module.base.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseService;
-import com.xjrsoft.module.base.dto.BaseClassCoursePageDto;
-import com.xjrsoft.module.base.dto.ClassCourseReuseDto;
+import com.xjrsoft.module.base.dto.*;
 import com.xjrsoft.module.base.entity.BaseClassCourse;
 import com.xjrsoft.module.base.entity.ClassCourseTextbook;
 import com.xjrsoft.module.base.entity.CourseBookInfo;
+import com.xjrsoft.module.base.vo.BaseClassCourseListVo;
+import com.xjrsoft.module.base.vo.BaseClassCourseMobileListVo;
 import com.xjrsoft.module.base.vo.BaseClassCoursePageVo;
-import com.xjrsoft.module.base.dto.ClassCourseTextbookExportQueryDto;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -26,6 +26,9 @@ public interface IBaseClassCourseService extends MPJBaseService<BaseClassCourse>
 
     Page<BaseClassCoursePageVo> getPage(Page<BaseClassCoursePageVo> objectPage, BaseClassCoursePageDto dto);
 
+    List<BaseClassCourseListVo> oneClassClassCourseList(BaseClassCourseListDto dto);
+
+    List<BaseClassCourseMobileListVo> mobileOneClassClassCourseList(BaseClassCourseListDto dto);
 
     List<CourseBookInfo> getAllCourseBook(Long[] classIds, Long subjectGroupId, Long semester);
 
@@ -41,6 +44,10 @@ public interface IBaseClassCourseService extends MPJBaseService<BaseClassCourse>
 
     Boolean duplicateCourseBook(ClassCourseReuseDto dto);
 
+    Boolean settingUpClasses(AddBaseClassAdminCourseDto dto);
+
+    Boolean deleteSettingUpClasses(List<Long> ids);
+
     Map<String, Map<String, Object>> getSemesterTree();
 
     Long GetClassIdByName(String name);

+ 3 - 0
src/main/java/com/xjrsoft/module/base/service/IBaseClassService.java

@@ -21,4 +21,7 @@ public interface IBaseClassService extends MPJBaseService<BaseClass> {
     List<StudentClassVo> getStudentClass();
 
     Page<ClassStatisticsVo> getAttendancePage(Page<ClassStatisticsVo> page, AttendanceStatisticDto dto);
+
+
+    Long getIdByTeacherId(Long teacherId);
 }

+ 228 - 193
src/main/java/com/xjrsoft/module/base/service/impl/BaseClassCourseServiceImpl.java

@@ -1,9 +1,11 @@
 package com.xjrsoft.module.base.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
@@ -12,20 +14,17 @@ import com.xjrsoft.common.enums.DeleteMark;
 import com.xjrsoft.common.enums.UseSemesterTypeEnum;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.utils.VoToColumnUtil;
-import com.xjrsoft.module.base.dto.BaseClassCoursePageDto;
-import com.xjrsoft.module.base.dto.ClassCourseReuseDto;
+import com.xjrsoft.module.base.dto.*;
 import com.xjrsoft.module.base.entity.*;
+import com.xjrsoft.module.base.mapper.BaseClassAdminCourseMapper;
 import com.xjrsoft.module.base.mapper.BaseClassCourseMapper;
 import com.xjrsoft.module.base.mapper.BaseClassMapper;
 import com.xjrsoft.module.base.service.IBaseClassCourseService;
-import com.xjrsoft.module.base.vo.BaseClassCourseExportListVo;
-import com.xjrsoft.module.base.vo.BaseClassCoursePageVo;
+import com.xjrsoft.module.base.vo.*;
 import com.xjrsoft.module.generator.entity.ImportConfig;
 import com.xjrsoft.module.organization.entity.Department;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.mapper.BaseStudentSchoolRollMapper;
-import com.xjrsoft.module.base.dto.ClassCourseTextbookExportQueryDto;
-import com.xjrsoft.module.base.vo.ClassCourseTextbookExportQueryVo;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
 import com.xjrsoft.module.textbook.entity.Textbook;
 import com.xjrsoft.module.textbook.entity.TextbookStudentClaim;
@@ -36,6 +35,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -66,114 +66,92 @@ public class BaseClassCourseServiceImpl extends MPJBaseServiceImpl<BaseClassCour
 
     private final BaseClassMapper baseClassMapper;
 
+    private final BaseClassAdminCourseMapper baseClassAdminCourseMapper;
+
     @Override
     public Page<BaseClassCoursePageVo> getPage(Page<BaseClassCoursePageVo> page, BaseClassCoursePageDto dto) {
         return baseClassCourseMapper.getPage(page, dto);
     }
 
+    @Override
+    public List<BaseClassCourseListVo> oneClassClassCourseList(BaseClassCourseListDto dto) {
+        MPJLambdaWrapper<BaseClassAdminCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        baseClassCourseMPJLambdaWrapper
+                .disableSubLogicDel()
+                .select(BaseClassCourse::getId)
+                .selectAs(BaseClass::getName, BaseClassCourseListVo::getClassIdCn)
+                .selectAs(BaseCourseSubject::getName, BaseClassCourseListVo::getCourseIdCn)
+                .selectAs(Textbook::getBookName, BaseClassCourseListVo::getTextbookIdCn)
+                .selectAs(BaseSemester::getName, BaseClassCourseListVo::getBaseSemesterIdCn)
+                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseListVo.class).contains(x.getProperty()))
+                .innerJoin(BaseClassCourse.class, BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassAdminCourse::getClassId)
+                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassAdminCourse::getBaseSemesterId)
+                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
+                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
+                .eq(dto.getBaseSemesterId() != null && dto.getBaseSemesterId() > 0, BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                .eq(dto.getClassId() != null && dto.getClassId() > 0, BaseClassAdminCourse::getClassId, dto.getClassId())
+                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+        ;
+
+        return baseClassAdminCourseMapper.selectJoinList(BaseClassCourseListVo.class, baseClassCourseMPJLambdaWrapper);
+    }
+
+    @Override
+    public List<BaseClassCourseMobileListVo> mobileOneClassClassCourseList(BaseClassCourseListDto dto) {
+        MPJLambdaWrapper<BaseClassAdminCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        baseClassCourseMPJLambdaWrapper
+                .disableSubLogicDel()
+                .select(BaseClassCourse::getId)
+                .selectAs(BaseCourseSubject::getName, BaseClassCourseMobileListVo::getCourseName)
+                .selectAs(Textbook::getBookName, BaseClassCourseMobileListVo::getBookName)
+                .selectAs(Textbook::getPrice, BaseClassCourseMobileListVo::getPrice)
+                .selectAs(DictionaryDetail::getName, BaseClassCourseMobileListVo::getTextbookTypeName)
+                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseMobileListVo.class).contains(x.getProperty()))
+                .innerJoin(BaseClassCourse.class, BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
+                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,Textbook::getTextbookType)
+                .eq(dto.getBaseSemesterId() != null && dto.getBaseSemesterId() > 0, BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                .eq(dto.getClassId() != null && dto.getClassId() > 0, BaseClassAdminCourse::getClassId, dto.getClassId())
+                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+        ;
+        return baseClassAdminCourseMapper.selectJoinList(BaseClassCourseMobileListVo.class, baseClassCourseMPJLambdaWrapper);
+    }
+
     @Override
     public List<CourseBookInfo> getAllCourseBook(Long[] classIds, Long subjectGroupId, Long semester){
         return baseClassCourseMapper.getAllCourseBook(classIds, subjectGroupId, semester);
     }
 
     @Override
-    public List<CourseBookInfo> getSelectedCourseBook(Long[] subjectGroupId, Long semester){
-        return baseClassCourseMapper.getSelectedCourseBook(subjectGroupId, semester);
+    public List<CourseBookInfo> getSelectedCourseBook(Long[] classIds, Long semester){
+        return baseClassCourseMapper.getSelectedCourseBook(classIds, semester);
     }
 
     @Override
     @Transactional
     public Boolean oneUpdateClassCoursesAndTextbooks(ClassCourseTextbook dto) {
-        if (ObjectUtils.isEmpty(dto.getClassIds()) || ObjectUtils.isEmpty(dto.getBaseSemesterId())) {
-            throw new MyException("请选中班级和学期");
-        }
-
-        boolean isSuccess = false;
-
-        List<Long> classIdList = Arrays.asList(dto.getClassIds());
-
-        //删除班级的这学期的所有课程教材
-        LambdaUpdateWrapper<BaseClassCourse> baseClassCourseLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
-        baseClassCourseLambdaUpdateWrapper
-                .in(BaseClassCourse::getClassId, classIdList)
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-        ;
-        isSuccess = this.remove(baseClassCourseLambdaUpdateWrapper);
-
-//        // 获取所有班级的所有学生
-//        LambdaQueryWrapper<BaseStudentSchoolRoll> baseStudentSchoolRollLambdaQueryWrapper = new LambdaQueryWrapper<>();
-//        baseStudentSchoolRollLambdaQueryWrapper
-//                .in(BaseStudentSchoolRoll::getClassId, classIdList)
-//                .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
-//                ;
-//        List<BaseStudentSchoolRoll> baseStudentSchoolRolls = baseStudentSchoolRollMapper.selectList(baseStudentSchoolRollLambdaQueryWrapper);
-//
-//        Map<Long, List<Long>> userIdsMap = baseStudentSchoolRolls.stream()
-//                .filter(student -> student.getClassId() != null && student.getUserId() != null)
-//                .collect(Collectors.groupingBy(
-//                                BaseStudentSchoolRoll::getClassId, // 根据classId分组
-//                                Collectors.mapping(BaseStudentSchoolRoll::getUserId, // 提取userId
-//                                        Collectors.toList()) // 收集到List<Long>
-//                        )
-//                );
-
-        List<BaseClassCourse> baseClassCourseList = new ArrayList<>();
-//        List<TextbookStudentClaim> textbookStudentClaimList = new ArrayList<>();
-        for (Long classId : dto.getClassIds()) {
-            for (String id : dto.getIds()) {
-                String[] idArr = id.split("_");
-                if (idArr[0].equals("") || idArr[1].equals("")) {
-                    continue;
-                }
-                Long courseId = Long.parseLong(idArr[0]);
-                Long textbookId = Long.parseLong(idArr[1]);
-                baseClassCourseList.add(new BaseClassCourse() {{
-                    setBaseSemesterId(dto.getBaseSemesterId());
-                    setClassId(classId);
-                    setCourseId(courseId);
-                    setTextbookId(textbookId);
-                }});
-
-//                // 添加学生领取教材数据
-//                List<Long> userIds = userIdsMap.get(classId);
-//                for (Long userId : userIds) {
-//                    textbookStudentClaimList.add(new TextbookStudentClaim() {{
-//                        setStudentUserId(userId);
-//                        setBaseSemesterId(dto.getBaseSemesterId());
-//                        setClassId(classId);
-//                        setTextbookId(textbookId);
-//                    }});
-//                }
-            }
-        }
-
-//        for (TextbookStudentClaim textbookStudentClaim : textbookStudentClaimList) {
-//            textbookStudentClaimMapper.insert(textbookStudentClaim);
-//        }
-        return this.saveBatch(baseClassCourseList);
+        return updateAddCourseBook(dto);
     }
 
     @Override
     @Transactional
     public Boolean updateAddCourseBook(ClassCourseTextbook dto){
-        if (ObjectUtils.isEmpty(dto.getClassIds()) || ObjectUtils.isEmpty(dto.getBaseSemesterId())) {
-            throw new MyException("请选中班级和学期");
+        if (ObjectUtils.isEmpty(dto.getBaseClassAdminCourseIds())) {
+            throw new MyException("添加课程的班级无效,请刷新重试");
         }
 
-        boolean isSuccess = false;
-
-        // 根据班级id查出班级已经存在的课程和教程
-        List<Long> classIdList = Arrays.asList(dto.getClassIds());
+        // 根据班级id查出班级已经存在的课程和教材
         LambdaQueryWrapper<BaseClassCourse> baseClassCourseLambdaQueryWrapper = new LambdaQueryWrapper<>();
         baseClassCourseLambdaQueryWrapper
-                .in(BaseClassCourse::getClassId, classIdList)
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                .in(BaseClassCourse::getClassId, dto.getBaseClassAdminCourseIds())
                 .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
         ;
         List<BaseClassCourse> oldList = this.list(baseClassCourseLambdaQueryWrapper);
 
         // 使用Stream API和Lambda表达式生成所需的字符串列表
-        Map<Long, List<String>> tourseId_textbookIdMap = oldList.stream()
+        Map<Long, List<String>> courseIdTextbookIdMap = oldList.stream()
                 .collect(Collectors.groupingBy(
                         BaseClassCourse::getClassId,
                         Collectors.mapping(
@@ -182,96 +160,81 @@ public class BaseClassCourseServiceImpl extends MPJBaseServiceImpl<BaseClassCour
                         )
                 ));
 
-//        //删除班级的这学期的所有课程教材
-//        LambdaQueryWrapper<BaseClassCourse> baseClassCourseLambdaQueryWrapper = new LambdaQueryWrapper<>();
-//        baseClassCourseLambdaQueryWrapper
-//                .in(BaseClassCourse::getClassId, classIdList)
-//                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-//        ;
-//        isSuccess = this.remove(baseClassCourseLambdaQueryWrapper);
-
-//        // 获取所有班级的所有学生
-//        LambdaQueryWrapper<BaseStudentSchoolRoll> baseStudentSchoolRollLambdaQueryWrapper = new LambdaQueryWrapper<>();
-//        baseStudentSchoolRollLambdaQueryWrapper
-//                .in(BaseStudentSchoolRoll::getClassId, classIdList)
-//                .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
-//                ;
-//        List<BaseStudentSchoolRoll> baseStudentSchoolRolls = baseStudentSchoolRollMapper.selectList(baseStudentSchoolRollLambdaQueryWrapper);
-//
-//        Map<Long, List<Long>> userIdsMap = baseStudentSchoolRolls.stream()
-//                .filter(student -> student.getClassId() != null && student.getUserId() != null)
-//                .collect(Collectors.groupingBy(
-//                                BaseStudentSchoolRoll::getClassId, // 根据classId分组
-//                                Collectors.mapping(BaseStudentSchoolRoll::getUserId, // 提取userId
-//                                        Collectors.toList()) // 收集到List<Long>
-//                        )
-//                );
+        // 处理所有需要新增的教材
+        Map<String, BaseClassCourse> newClassCourseTextbookMap = new HashMap<>();
+        for (String id : dto.getIds()) {
+            String[] idArr = id.split("_");
+            if (idArr[0].isEmpty() || idArr[1].isEmpty()) {
+                continue;
+            }
+            Long courseId = Long.parseLong(idArr[0]);
+            Long textbookId = Long.parseLong(idArr[1]);
+            newClassCourseTextbookMap.put(id, new BaseClassCourse() {{
+                setCourseId(courseId);
+                setTextbookId(textbookId);
+                setCreateDate(new Date());
+            }});
+        }
 
+        // 处理每一个班需要新增的课程
         List<BaseClassCourse> baseClassCourseList = new ArrayList<>();
-//        List<TextbookStudentClaim> textbookStudentClaimList = new ArrayList<>();
-        for (Long classId : dto.getClassIds()) {
+        BaseClassCourse newBaseClassCourse;
+        for (Long classId : dto.getBaseClassAdminCourseIds()) {
             // 判断当前的班级是否已经有了该课程和教材
-            List<String> tourseId_textbookIdList = tourseId_textbookIdMap.get(classId);
-            for (String id : dto.getIds()) {
-                if(ObjectUtils.isNotEmpty(tourseId_textbookIdList) && !tourseId_textbookIdList.isEmpty() && tourseId_textbookIdList.contains(id)){
-                    continue;
-                }
-                String[] idArr = id.split("_");
-                if (idArr[0].equals("") || idArr[1].equals("")) {
+            List<String> courseIdTextbookIdList = null;
+            if(ObjectUtils.isNotEmpty(courseIdTextbookIdMap)){
+                courseIdTextbookIdList = courseIdTextbookIdMap.get(classId);
+            }
+            for (Map.Entry<String, BaseClassCourse> entry : newClassCourseTextbookMap.entrySet()) {
+                String key = entry.getKey();
+                BaseClassCourse value = entry.getValue();
+                newBaseClassCourse = new BaseClassCourse();
+                BeanUtils.copyProperties(value, newBaseClassCourse);
+                if(ObjectUtils.isNotEmpty(courseIdTextbookIdList) && !courseIdTextbookIdList.isEmpty() && courseIdTextbookIdList.contains(key)){
                     continue;
                 }
-                Long courseId = Long.parseLong(idArr[0]);
-                Long textbookId = Long.parseLong(idArr[1]);
-                baseClassCourseList.add(new BaseClassCourse() {{
-                    setBaseSemesterId(dto.getBaseSemesterId());
-                    setClassId(classId);
-                    setCourseId(courseId);
-                    setTextbookId(textbookId);
-                }});
-
-//                // 添加学生领取教材数据
-//                List<Long> userIds = userIdsMap.get(classId);
-//                for (Long userId : userIds) {
-//                    textbookStudentClaimList.add(new TextbookStudentClaim() {{
-//                        setStudentUserId(userId);
-//                        setBaseSemesterId(dto.getBaseSemesterId());
-//                        setClassId(classId);
-//                        setTextbookId(textbookId);
-//                    }});
-//                }
+                newBaseClassCourse.setClassId(classId);
+                baseClassCourseList.add(newBaseClassCourse);
             }
         }
 
-//        for (TextbookStudentClaim textbookStudentClaim : textbookStudentClaimList) {
-//            textbookStudentClaimMapper.insert(textbookStudentClaim);
-//        }
         return this.saveBatch(baseClassCourseList);
     }
 
     @Override
     @Transactional
     public Boolean updateRemoveCourseBook(ClassCourseTextbook dto){
-        if (ObjectUtils.isEmpty(dto.getClassIds()) || ObjectUtils.isEmpty(dto.getBaseSemesterId())) {
-            throw new MyException("请选中班级和学期");
+        if (ObjectUtils.isEmpty(dto.getBaseClassAdminCourseIds())) {
+            throw new MyException("移除课程的班级无效,请刷新重试");
         }
 
-//        baseClassCourseMapper.updateRemoveClassCourseTextbooks(classId, courseId, textbookId);
-        for (Long classId : dto.getClassIds()) {
-            for (String id : dto.getIds()) {
-                String[] idArr = id.split("_");
-                if (idArr[0].equals("") || idArr[1].equals("")) {
-                    continue;
+        Map<String, BaseClassCourse> newClassCourseTextbookMap = new HashMap<>();
+        for (String id : dto.getIds()) {
+            String[] idArr = id.split("_");
+            if (idArr[0].isEmpty() || idArr[1].isEmpty()) {
+                continue;
+            }
+            Long courseId = Long.parseLong(idArr[0]);
+            Long textbookId = Long.parseLong(idArr[1]);
+            newClassCourseTextbookMap.put(id, new BaseClassCourse() {{
+                setCourseId(courseId);
+                setTextbookId(textbookId);
+            }});
+        }
+
+        for (Long classId : dto.getBaseClassAdminCourseIds()) {
+            for (Map.Entry<String, BaseClassCourse> entry : newClassCourseTextbookMap.entrySet()) {
+                BaseClassCourse value = entry.getValue();
+                if(ObjectUtils.isNotEmpty(value)){
+                    // 移除
+                    LambdaUpdateWrapper<BaseClassCourse> baseClassCourseLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                    baseClassCourseLambdaUpdateWrapper
+                            .eq(BaseClassCourse::getClassId, classId)
+                            .eq(BaseClassCourse::getCourseId, value.getCourseId())
+                            .eq(BaseClassCourse::getTextbookId, value.getTextbookId())
+                    ;
+                    this.remove(baseClassCourseLambdaUpdateWrapper);
                 }
-                Long courseId = Long.parseLong(idArr[0]);
-                Long textbookId = Long.parseLong(idArr[1]);
-                LambdaUpdateWrapper<BaseClassCourse> baseClassCourseLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
-                baseClassCourseLambdaUpdateWrapper
-                        .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                        .eq(BaseClassCourse::getClassId, classId)
-                        .eq(BaseClassCourse::getCourseId, courseId)
-                        .eq(BaseClassCourse::getTextbookId, textbookId)
-                        ;
-                this.remove(baseClassCourseLambdaUpdateWrapper);
             }
         }
         return true;
@@ -285,43 +248,119 @@ public class BaseClassCourseServiceImpl extends MPJBaseServiceImpl<BaseClassCour
     @Override
     @Transactional
     public Boolean duplicateCourseBook(ClassCourseReuseDto dto){
-        LambdaQueryWrapper<BaseClassCourse> baseClassCourseLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        // 根据旧的学期和班级找到所有的课程
+        MPJLambdaWrapper<BaseClassAdminCourse> baseClassCourseLambdaQueryWrapper = new MPJLambdaWrapper<>();
         baseClassCourseLambdaQueryWrapper
-                .eq(dto.getOldClassId() != null && dto.getOldClassId() > 0, BaseClassCourse::getClassId, dto.getOldClassId())
-                .eq(dto.getOldBaseSemesterId() != null && dto.getOldBaseSemesterId() > 0, BaseClassCourse::getBaseSemesterId, dto.getOldBaseSemesterId())
+                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourse.class).contains(x.getProperty()))
+                .innerJoin(BaseClassCourse.class, BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+                .eq(BaseClassAdminCourse::getClassId, dto.getOldClassId())
+                .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getOldBaseSemesterId())
                 ;
-        List<BaseClassCourse> baseClassCourseList = this.list(baseClassCourseLambdaQueryWrapper);
+        List<BaseClassCourse> baseClassCourseList = baseClassAdminCourseMapper.selectJoinList(BaseClassCourse.class, baseClassCourseLambdaQueryWrapper);
         if(baseClassCourseList == null || baseClassCourseList.isEmpty()){
-            throw new MyException("该学期的该班级没有可以复用的课程!");
+            throw new MyException("被复用的学期的被复用班级没有可以复用的课程!");
         }
 
-        boolean isSuccess = false;
+        // 已经维护了课程教材信息的班级和所在学期
+        // 一个班级一个学期应该只需要设置一次
+        List<BaseClassAdminCourse> baseClassAdminCourses = baseClassAdminCourseMapper.selectList(
+                Wrappers.lambdaQuery(BaseClassAdminCourse.class)
+                        .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getNewBaseSemesterId())
+        );
+
+        Map<Long, BaseClassAdminCourse> oldClassIdMap = baseClassAdminCourses.stream()
+                .collect(Collectors.toMap(BaseClassAdminCourse::getClassId, b -> b, (b1, b2) -> b1));
+
+        // 判断复用的学期复用的班级是否已经进入了班级课程列表
+        // 判断本学期本班级是否已经加入课程管理的班级中
+        List<Long> classAdminCourseIds = new ArrayList<>();
+        Long classAdminCourseId;
+        BaseClassAdminCourse baseClassAdminCourse;
+        for (Long classId : dto.getNewClassIds()){
+            if(ObjectUtils.isNotEmpty(oldClassIdMap) && oldClassIdMap.containsKey(classId)){
+                classAdminCourseId = oldClassIdMap.get(classId).getId();
+            } else {
+                baseClassAdminCourse = new BaseClassAdminCourse();
+                baseClassAdminCourse.setClassId(classId);
+                baseClassAdminCourse.setBaseSemesterId(dto.getNewBaseSemesterId());
+                baseClassAdminCourseMapper.insert(baseClassAdminCourse);
+
+                classAdminCourseId = baseClassAdminCourse.getId();
+                oldClassIdMap.put(classId, baseClassAdminCourse);
+            }
+            classAdminCourseIds.add(classAdminCourseId);
+        }
 
-        //删除班级的所有课程教材
+        // 删除班级的所有课程教材
         LambdaQueryWrapper<BaseClassCourse> removeLambdaQueryWrapper = new LambdaQueryWrapper<>();
         removeLambdaQueryWrapper
-                .in(BaseClassCourse::getClassId, dto.getNewClassIds())
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getNewBaseSemesterId())
+                .in(BaseClassCourse::getClassId, classAdminCourseIds)
         ;
-        isSuccess = this.remove(removeLambdaQueryWrapper);
+        this.remove(removeLambdaQueryWrapper);
 
         List<BaseClassCourse> newBaseClassCourseList = new ArrayList<>();
-        for (Long newClassId : dto.getNewClassIds()){
+        for (Long id : classAdminCourseIds){
             for (BaseClassCourse baseClassCourse : baseClassCourseList){
                 Long courseId = baseClassCourse.getCourseId();
                 Long textbookId = baseClassCourse.getTextbookId();
                 newBaseClassCourseList.add(new BaseClassCourse(){{
-                    setBaseSemesterId(dto.getNewBaseSemesterId());
-                    setClassId(newClassId);
+                    setClassId(id);
                     setCourseId(courseId);
                     setTextbookId(textbookId);
+                    setCreateDate(new Date());
                 }});
             }
         }
 
-        isSuccess = this.saveBatch(newBaseClassCourseList);
-        return isSuccess;
-        //baseClassCourseMapper.insertClassCourseTextbookCombinations(newClassId, sourceClassId, semester);
+        this.saveBatch(newBaseClassCourseList);
+        return true;
+    }
+
+    @Override
+    @Transactional
+    public Boolean settingUpClasses(AddBaseClassAdminCourseDto dto) {
+        if(ObjectUtils.isEmpty(dto.getBaseSemesterId())){
+            throw new MyException("请选择需要设置课程的学期");
+        }
+        if(ObjectUtils.isEmpty(dto.getClassIds()) || dto.getClassIds().isEmpty()){
+            throw new MyException("请选择需要设置课程的班级");
+        }
+
+        // 一个班级一个学期应该只需要设置一次
+        List<BaseClassAdminCourse> baseClassAdminCourses = baseClassAdminCourseMapper.selectList(
+                Wrappers.lambdaQuery(BaseClassAdminCourse.class)
+                        .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+        );
+
+        List<Long> oldClassId = baseClassAdminCourses.stream()
+                .map(BaseClassAdminCourse::getClassId)
+                .collect(Collectors.toList());
+
+        BaseClassAdminCourse baseClassAdminCourse;
+        for(Long classId : dto.getClassIds()){
+            if(ObjectUtils.isNotEmpty(oldClassId) && oldClassId.contains(classId)){
+                continue;
+            }
+            baseClassAdminCourse = new BaseClassAdminCourse();
+            baseClassAdminCourse.setBaseSemesterId(dto.getBaseSemesterId());
+            baseClassAdminCourse.setClassId(classId);
+            baseClassAdminCourseMapper.insert(baseClassAdminCourse);
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional
+    public Boolean deleteSettingUpClasses(List<Long> ids) {
+        // 先移除已经添加的课程数据
+        LambdaUpdateWrapper<BaseClassCourse> baseClassCourseLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        baseClassCourseLambdaUpdateWrapper
+                .in(BaseClassCourse::getClassId, ids)
+                ;
+        this.remove(baseClassCourseLambdaUpdateWrapper);
+
+        baseClassAdminCourseMapper.deleteBatchIds(ids);
+        return true;
     }
 
     @Override
@@ -387,7 +426,7 @@ public class BaseClassCourseServiceImpl extends MPJBaseServiceImpl<BaseClassCour
 
     @Override
     public ByteArrayOutputStream classCourseTextbookExportQuery(ClassCourseTextbookExportQueryDto dto) throws IOException {
-        MPJLambdaWrapper<BaseClass> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        MPJLambdaWrapper<BaseClassAdminCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
         baseClassCourseMPJLambdaWrapper
                 .disableSubLogicDel()
                 .selectAs(BaseSemester::getName, ClassCourseTextbookExportQueryVo::getSemester)
@@ -399,39 +438,35 @@ public class BaseClassCourseServiceImpl extends MPJBaseServiceImpl<BaseClassCour
                 .selectAs(Textbook::getUseType, ClassCourseTextbookExportQueryVo::getUseType)
                 .selectAs(Textbook::getPrice, ClassCourseTextbookExportQueryVo::getPrice)
                 .selectAs(Textbook::getDiscountPrice, ClassCourseTextbookExportQueryVo::getDiscountPrice)
+                .leftJoin(BaseClassCourse.class,
+                        wrapper -> wrapper
+                                .eq(BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+                                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+                )
+
+                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassAdminCourse::getBaseSemesterId)
 
-                .leftJoin(BaseClassCourse.class, BaseClassCourse::getClassId, BaseClass::getId)
-                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassCourse::getBaseSemesterId)
-                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassCourse::getClassId)
+                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassAdminCourse::getClassId)
                 .leftJoin(Department.class, Department::getId, BaseClass::getOrgId)
+
                 .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
                 .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
                 .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
                         wrapper -> wrapper
                                 .selectAs(DictionaryDetail::getName, ClassCourseTextbookExportQueryVo::getTextbookType)
                         )
-                .in(ObjectUtils.isNotEmpty(dto.getClassIds()) && !dto.getClassIds().isEmpty(), BaseClassCourse::getClassId, dto.getClassIds())
+
+                .in(ObjectUtils.isNotEmpty(dto.getClassIds()) && !dto.getClassIds().isEmpty(), BaseClassAdminCourse::getClassId, dto.getClassIds())
                 .like(StringUtils.isNotBlank(dto.getClassName()), BaseClass::getName, dto.getClassName())
                 .eq(ObjectUtils.isNotEmpty(dto.getDeptId()), Department::getId, dto.getDeptId())
-                .having(ObjectUtils.isNotEmpty(dto.getCourseSet()) && dto.getCourseSet() == 1, "HAVING LENGTH(course_name) > 0")
-                .having(ObjectUtils.isNotEmpty(dto.getCourseSet()) && dto.getCourseSet() == 2, "HAVING COALESCE(LENGTH(course_name), 0) = 0")
-                .and(ObjectUtils.isNotEmpty(dto.getSemester()),
-                        wrapper -> wrapper
-                                .eq(BaseClassCourse::getBaseSemesterId, dto.getSemester())
-                                .or()
-                                .isNull(BaseClassCourse::getBaseSemesterId)
-                )
-                .and(wrapper -> wrapper
-                                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-                                .or()
-                                .isNull(BaseClassCourse::getDeleteMark)
-                )
-                .eq(BaseClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+//                .having(ObjectUtils.isNotEmpty(dto.getCourseSet()) && dto.getCourseSet() == 1, "HAVING LENGTH(course_name) > 0")
+//                .having(ObjectUtils.isNotEmpty(dto.getCourseSet()) && dto.getCourseSet() == 2, "HAVING COALESCE(LENGTH(course_name), 0) = 0")
+                .eq(ObjectUtils.isNotEmpty(dto.getSemester()),BaseClassAdminCourse::getBaseSemesterId, dto.getSemester())
                 .orderByDesc(BaseCourseSubject::getName)
                 .orderByDesc(Textbook::getBookName)
         ;
 
-        List<ClassCourseTextbookExportQueryVo> dataList = baseClassMapper.selectJoinList(ClassCourseTextbookExportQueryVo.class, baseClassCourseMPJLambdaWrapper);
+        List<ClassCourseTextbookExportQueryVo> dataList = baseClassAdminCourseMapper.selectJoinList(ClassCourseTextbookExportQueryVo.class, baseClassCourseMPJLambdaWrapper);
 
         // 根据班级分组
         Map<Long, List<ClassCourseTextbookExportQueryVo>> dataMapByClassId = dataList.stream()

+ 24 - 0
src/main/java/com/xjrsoft/module/base/service/impl/BaseClassServiceImpl.java

@@ -1,9 +1,12 @@
 package com.xjrsoft.module.base.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
 import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
 import com.xjrsoft.module.base.dto.BaseClassPageDto;
@@ -103,4 +106,25 @@ public class BaseClassServiceImpl extends MPJBaseServiceImpl<BaseClassMapper, Ba
     public Page<ClassStatisticsVo> getAttendancePage(Page<ClassStatisticsVo> page, AttendanceStatisticDto dto){
         return baseClassMapper.getAttendanceClass(page, dto);
     };
+
+
+    /**
+     * 根据教师id查询班级id
+     * @param teacherId 教师userId
+     * @return 班主任所负责的班级id
+     */
+    @Override
+    public Long getIdByTeacherId(Long teacherId){
+        List<BaseClass> list = this.baseMapper.selectList(
+                new QueryWrapper<BaseClass>().lambda()
+                        .eq(BaseClass::getTeacherId, teacherId)
+                        .eq(BaseClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        .eq(BaseClass::getEnabledMark, EnabledMark.ENABLED.getCode())
+                        .orderByDesc(BaseClass::getCreateDate)
+        );
+        if(list.isEmpty()){
+            return null;
+        }
+        return list.get(0).getId();
+    };
 }

+ 6 - 0
src/main/java/com/xjrsoft/module/ledger/controller/LedgerStatisticsController.java

@@ -114,6 +114,12 @@ public class LedgerStatisticsController {
         if(!userIdList.isEmpty()){
             dto.setUserIds(userIdList);
         }
+
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            dto.setStartTime(dto.getStartDate().atTime(0,0,0));
+            dto.setEndTime(dto.getEndDate().atTime(23,59,59));
+        }
+
         List<LedgerStatisticsLeaveVo> list = teacherleaveService.getStatisticsList(dto);
         List<LedgerStatisticsLeaveExcelVo> dataList = new ArrayList<>();
         int sortCode = 1;

+ 7 - 1
src/main/java/com/xjrsoft/module/liteflow/node/StudentChangeClassNode.java

@@ -8,6 +8,7 @@ import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.student.entity.StudentChangeClass;
 import com.xjrsoft.module.student.mapper.StudentChangeClassMapper;
 import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.workflow.entity.WorkflowRecord;
 import com.xjrsoft.module.workflow.mapper.WorkflowRecordMapper;
 import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
@@ -42,6 +43,9 @@ public class StudentChangeClassNode extends NodeComponent {
     @Autowired
     private WorkflowRecordMapper workflowRecordMapper;
 
+    @Autowired
+    private IStudentChangeRecordService changeRecordService;
+
     @Override
     public void process() throws Exception {
         // 获取表单中数据编号
@@ -84,9 +88,11 @@ public class StudentChangeClassNode extends NodeComponent {
                         //查询出数据
                         StudentChangeClass changeClass = studentChangeClassMapper.selectById(formId);
 
-                        BaseClass baseClass =baseClassService.getById(changeClass.getAfterClassId());
+                        BaseClass baseClass = baseClassService.getById(changeClass.getAfterClassId());
                         //修改学生班级
                         studentSchoolRollService.updateStudentClass(changeClass.getAfterClassId(),baseClass.getMajorSetId(), changeClass.getStudentUserId());
+
+                        changeRecordService.insertDataByChangeClass(formId);
                     });
                 }
             });

+ 20 - 0
src/main/java/com/xjrsoft/module/liteflow/node/StudentDropOutNode.java

@@ -5,11 +5,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.xjrsoft.common.enums.ArchivesStatusEnum;
 import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.StudentChangeTypeEnum;
 import com.xjrsoft.common.enums.WorkflowApproveType;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.entity.StudentDropOut;
 import com.xjrsoft.module.student.mapper.StudentDropOutMapper;
 import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.workflow.entity.WorkflowRecord;
 import com.xjrsoft.module.workflow.mapper.WorkflowRecordMapper;
 import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
@@ -42,6 +44,9 @@ public class StudentDropOutNode extends NodeComponent {
     @Autowired
     private WorkflowRecordMapper workflowRecordMapper;
 
+    @Autowired
+    private IStudentChangeRecordService changeRecordService;
+
 
     @Override
     public void process() throws Exception {
@@ -91,6 +96,21 @@ public class StudentDropOutNode extends NodeComponent {
                                         .eq(BaseStudentSchoolRoll::getUserId, studentDropOut.getStudentUserId())
                                         .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
                         );
+
+                        //记录异动
+                        changeRecordService.insertData(
+                                schoolRoll.getArchivesStatus(),
+                                ArchivesStatusEnum.fromCode(schoolRoll.getArchivesStatus()),
+                                ArchivesStatusEnum.FB2904.getCode(),
+                                ArchivesStatusEnum.FB2904.getValue(),
+                                studentDropOut.getStudentUserId(),
+                                studentDropOut.getCreateUserId(),
+                                StudentChangeTypeEnum.ArchivesStatus.getCode(),
+                                2
+                        );
+
+
+
                         schoolRoll.setArchivesStatus(ArchivesStatusEnum.FB2904.getCode());
                         studentSchoolRollService.updateById(schoolRoll);
                     });

+ 4 - 0
src/main/java/com/xjrsoft/module/liteflow/node/StudentTransferNode.java

@@ -12,6 +12,7 @@ import com.xjrsoft.module.student.entity.StudentTransfer;
 import com.xjrsoft.module.student.mapper.BaseClassMajorSetMapper;
 import com.xjrsoft.module.student.mapper.StudentTransferMapper;
 import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.yomahub.liteflow.core.NodeComponent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -35,6 +36,9 @@ public class StudentTransferNode extends NodeComponent {
     @Autowired
     private BaseClassMajorSetMapper baseClassMajorSetMapper;
 
+    @Autowired
+    private IStudentChangeRecordService changeRecordService;
+
     @Override
     public void process() throws Exception {
         // 获取表单中数据编号

+ 6 - 0
src/main/java/com/xjrsoft/module/liteflow/node/TemporaryChangeClassNode.java

@@ -10,6 +10,7 @@ import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.student.entity.StudentChangeClass;
 import com.xjrsoft.module.student.mapper.StudentChangeClassMapper;
 import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.workflow.entity.WorkflowRecord;
 import com.xjrsoft.module.workflow.mapper.WorkflowRecordMapper;
 import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
@@ -42,6 +43,9 @@ public class TemporaryChangeClassNode extends NodeComponent {
     @Autowired
     private WorkflowRecordMapper workflowRecordMapper;
 
+    @Autowired
+    private IStudentChangeRecordService changeRecordService;
+
     @Override
     public void process() throws Exception {
         // 获取表单中数据编号
@@ -91,6 +95,8 @@ public class TemporaryChangeClassNode extends NodeComponent {
                         BaseClass baseClass = baseClassService.getById(afterClassId);
                         //修改学生班级
                         studentSchoolRollService.updateStudentClass(afterClassId, baseClass.getMajorSetId(), studentUserId);
+
+                        changeRecordService.insertDataByTemporaryChangeClass(formId);
                     });
                 }
             });

+ 8 - 0
src/main/java/com/xjrsoft/module/liteflow/node/WfRoomApplicantNode.java

@@ -13,6 +13,7 @@ import com.xjrsoft.module.room.entity.WfRoomApplicant;
 import com.xjrsoft.module.room.service.IWfRoomApplicantService;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.workflow.entity.WorkflowRecord;
 import com.xjrsoft.module.workflow.mapper.WorkflowRecordMapper;
 import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
@@ -45,6 +46,9 @@ public class WfRoomApplicantNode extends NodeComponent {
     private IWorkflowExecuteService workflowExecuteService;
     @Autowired
     private WorkflowRecordMapper workflowRecordMapper;
+    @Autowired
+    private IStudentChangeRecordService changeRecordService;
+
 
     @Override
     public void process() throws Exception {
@@ -86,10 +90,14 @@ public class WfRoomApplicantNode extends NodeComponent {
                         }
                         //查询出数据
                         WfRoomApplicant wfRoomApplicant = wfRoomApplicantService.getById(formId);
+
                         BaseStudentSchoolRoll schoolRoll = studentSchoolRollService.getOne(
                                 new QueryWrapper<BaseStudentSchoolRoll>().lambda()
                                         .eq(BaseStudentSchoolRoll::getUserId, wfRoomApplicant.getApplicantUserId())
                         );
+
+                        changeRecordService.insertDataByWfRoomApplicant(wfRoomApplicant, schoolRoll);
+
                         if(RoomApplicantTypeEnum.ToBeBoarder.getCode().equals(wfRoomApplicant.getRecedeType())){
                             schoolRoll.setStduyStatus(StudyStatusEnum.InResidence.getCode());
                         }else if(RoomApplicantTypeEnum.ToBeDayPupil.getCode().equals(wfRoomApplicant.getRecedeType())){

+ 3 - 0
src/main/java/com/xjrsoft/module/liteflow/node/WfSchoolRollStudentNode.java

@@ -3,6 +3,7 @@ package com.xjrsoft.module.liteflow.node;
 import cn.hutool.core.convert.Convert;
 import com.xjrsoft.module.student.service.ISchoolRollStudentService;
 import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.util.Map;
@@ -13,6 +14,8 @@ import java.util.Map;
  */
 @Component("wf_school_roll_student_node")
 public class WfSchoolRollStudentNode extends NodeComponent {
+
+    @Autowired
     private ISchoolRollStudentService schoolRollStudentService;
 
     @Override

+ 0 - 1
src/main/java/com/xjrsoft/module/organization/controller/UserController.java

@@ -170,7 +170,6 @@ public class UserController {
     @GetMapping(value = "/list")
     @ApiOperation(value = "用户列表(不分页)")
     public R list(String keyword) {
-
         List<User> list = userService.list(Wrappers.lambdaQuery(User.class)
                 .like(StrUtil.isNotBlank(keyword), User::getUserName, keyword)
                 .like(StrUtil.isNotBlank(keyword), User::getCode, keyword)

+ 2 - 2
src/main/java/com/xjrsoft/module/schedule/controller/ScheduleController.java

@@ -161,7 +161,7 @@ public class ScheduleController {
     public RT<Integer> currentWeek(CourseTableDto dto){
         BaseSemester baseSemester = semesterService.getCurrentSemester();
         if(baseSemester == null){
-            return RT.ok();
+            return RT.ok(0);
         }
         LocalDateTime now = LocalDateTime.now();
         if(dto.getScheduleDate() != null){
@@ -183,7 +183,7 @@ public class ScheduleController {
             }
         }
 
-        return RT.ok();
+        return RT.ok(0);
     }
 
 

+ 117 - 0
src/main/java/com/xjrsoft/module/student/controller/StudentChangeRecordController.java

@@ -0,0 +1,117 @@
+package com.xjrsoft.module.student.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.module.student.dto.AddStudentChangeRecordDto;
+import com.xjrsoft.module.student.dto.StudentChangeRecordPageDto;
+import com.xjrsoft.module.student.dto.UpdateStudentChangeRecordDto;
+import com.xjrsoft.module.student.entity.StudentChangeRecord;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
+import com.xjrsoft.module.student.vo.StudentChangeRecordPageVo;
+import com.xjrsoft.module.student.vo.StudentChangeRecordVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+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 org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/student" + "/studentChangeRecord")
+@Api(value = "/student"  + "/studentChangeRecord",tags = "学生异动记录表代码")
+@AllArgsConstructor
+public class StudentChangeRecordController {
+
+
+    private final IStudentChangeRecordService studentChangeRecordService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="学生异动记录表列表(分页)")
+    @SaCheckPermission("studentchangerecord:detail")
+    public RT<PageOutput<StudentChangeRecordPageVo>> page(@Valid StudentChangeRecordPageDto dto){
+        Page<StudentChangeRecordPageVo> page = studentChangeRecordService.getPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        PageOutput<StudentChangeRecordPageVo> pageOutput = ConventPage.getPageOutput(page, StudentChangeRecordPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询学生异动记录表信息")
+    @SaCheckPermission("studentchangerecord:detail")
+    public RT<StudentChangeRecordVo> info(@RequestParam Long id){
+        StudentChangeRecord studentChangeRecord = studentChangeRecordService.getById(id);
+        if (studentChangeRecord == null) {
+           return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(studentChangeRecord, StudentChangeRecordVo.class));
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增学生异动记录表")
+    @SaCheckPermission("studentchangerecord:add")
+    public RT<Boolean> add(@Valid @RequestBody AddStudentChangeRecordDto dto){
+        StudentChangeRecord studentChangeRecord = BeanUtil.toBean(dto, StudentChangeRecord.class);
+        boolean isSuccess = studentChangeRecordService.save(studentChangeRecord);
+    return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改学生异动记录表")
+    @SaCheckPermission("studentchangerecord:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateStudentChangeRecordDto dto){
+
+        StudentChangeRecord studentChangeRecord = BeanUtil.toBean(dto, StudentChangeRecord.class);
+        return RT.ok(studentChangeRecordService.updateById(studentChangeRecord));
+
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除学生异动记录表")
+    @SaCheckPermission("studentchangerecord:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(studentChangeRecordService.removeBatchByIds(ids));
+
+    }
+    @PostMapping("/import")
+    @ApiOperation(value = "导入")
+    public RT<Boolean> importData(@RequestParam MultipartFile file) throws IOException {
+        List<StudentChangeRecordPageVo> savedDataList = EasyExcel.read(file.getInputStream()).head(StudentChangeRecordPageVo.class).sheet().doReadSync();
+        Boolean result = studentChangeRecordService.saveBatch(BeanUtil.copyToList(savedDataList, StudentChangeRecord.class));
+        return RT.ok(result);
+    }
+
+    @GetMapping("/export")
+    @ApiOperation(value = "导出")
+    public ResponseEntity<byte[]> exportData(@Valid StudentChangeRecordPageDto dto, @RequestParam(defaultValue = "false") Boolean isTemplate) {
+        List<StudentChangeRecordPageVo> customerList = isTemplate != null && isTemplate ? new ArrayList<>() : ((PageOutput<StudentChangeRecordPageVo>) page(dto).getData()).getList();
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        EasyExcel.write(bot, StudentChangeRecordPageVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(customerList);
+
+        return RT.fileStream(bot.toByteArray(), "StudentChangeRecord" + ExcelTypeEnum.XLSX.getValue());
+    }
+}

+ 210 - 0
src/main/java/com/xjrsoft/module/student/controller/StudentReportPlanController.java

@@ -0,0 +1,210 @@
+package com.xjrsoft.module.student.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.utils.TreeUtil;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.base.service.IBaseClassService;
+import com.xjrsoft.module.base.service.IBaseSemesterService;
+import com.xjrsoft.module.student.dto.AddStudentReportPlanDto;
+import com.xjrsoft.module.student.dto.StudentReportPlanPageDto;
+import com.xjrsoft.module.student.dto.StudentReportPlanStatusDto;
+import com.xjrsoft.module.student.dto.UpdateStudentReportPlanDto;
+import com.xjrsoft.module.student.entity.StudentReportPlan;
+import com.xjrsoft.module.student.entity.StudentReportPlanClassRelation;
+import com.xjrsoft.module.student.service.IStudentReportPlanService;
+import com.xjrsoft.module.student.vo.StudentReportPlanClassRelationVo;
+import com.xjrsoft.module.student.vo.StudentReportPlanPageVo;
+import com.xjrsoft.module.student.vo.StudentReportPlanTreeVo;
+import com.xjrsoft.module.student.vo.StudentReportPlanVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+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 javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/student" + "/studentReportPlan")
+@Api(value = "/student"  + "/studentReportPlan",tags = "学生报到计划代码")
+@AllArgsConstructor
+public class StudentReportPlanController {
+
+
+    private final IStudentReportPlanService studentReportPlanService;
+    private final IBaseSemesterService semesterService;
+    private final IBaseClassService classService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="学生报到计划列表(分页)")
+    @SaCheckPermission("studentreportplan:detail")
+    public RT<PageOutput<StudentReportPlanPageVo>> page(@Valid StudentReportPlanPageDto dto){
+        Page<StudentReportPlanPageVo> page = studentReportPlanService.getPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        PageOutput<StudentReportPlanPageVo> pageOutput = ConventPage.getPageOutput(page, StudentReportPlanPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询学生报到计划信息")
+    @SaCheckPermission("studentreportplan:detail")
+    public RT<StudentReportPlanVo> info(@RequestParam Long id){
+        StudentReportPlan studentReportPlan = studentReportPlanService.getByIdDeep(id);
+        if (studentReportPlan == null) {
+           return RT.error("找不到此数据!");
+        }
+        StudentReportPlanVo planVo = BeanUtil.toBean(studentReportPlan, StudentReportPlanVo.class);
+        List<Long> classIds = studentReportPlan.getStudentReportPlanClassRelationList().stream().map(StudentReportPlanClassRelation::getClassId).collect(Collectors.toList());
+
+        List<BaseClass> classList = classService.listByIds(classIds);
+        Map<Long, String> classMaps = classList.stream().collect(Collectors.toMap(BaseClass::getId, BaseClass::getName));
+        List<StudentReportPlanClassRelationVo> classRelationList = planVo.getStudentReportPlanClassRelationList();
+        for (StudentReportPlanClassRelationVo baseClass : classRelationList) {
+            baseClass.setClassName(classMaps.get(baseClass.getClassId()));
+        }
+
+        return RT.ok(planVo);
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增学生报到计划")
+    @SaCheckPermission("studentreportplan:add")
+    public RT<Boolean> add(@Valid @RequestBody AddStudentReportPlanDto dto){
+        StudentReportPlan studentReportPlan = BeanUtil.toBean(dto, StudentReportPlan.class);
+        boolean isSuccess = studentReportPlanService.add(studentReportPlan);
+        return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改学生报到计划")
+    @SaCheckPermission("studentreportplan:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateStudentReportPlanDto dto){
+
+        StudentReportPlan studentReportPlan = BeanUtil.toBean(dto, StudentReportPlan.class);
+        return RT.ok(studentReportPlanService.update(studentReportPlan));
+
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除学生报到计划")
+    @SaCheckPermission("studentreportplan:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(studentReportPlanService.delete(ids));
+
+    }
+
+    @PostMapping(value = "/change-status")
+    @ApiOperation(value="修改状态")
+    @SaCheckPermission("classroom:detail")
+    public RT<Boolean> changeStatus(@Valid @RequestBody StudentReportPlanStatusDto dto) throws Exception {
+        StudentReportPlan reportPlan = studentReportPlanService.getByIdDeep(dto.getId());
+        if(reportPlan == null){
+            throw new MyException("未能找到计划信息");
+        }
+        //如果发布,需要先验证计划中的班级是否在其他生效的计划内
+        if(dto.getStatus() != null && dto.getStatus() == 1){
+            if(reportPlan.getStudentReportPlanClassRelationList() == null || reportPlan.getStudentReportPlanClassRelationList().isEmpty()){
+                return RT.error("未选择班级,无法进行发布");
+            }
+            List<Long> classIds = reportPlan.getStudentReportPlanClassRelationList()
+                    .stream().map(StudentReportPlanClassRelation::getClassId).collect(Collectors.toList());
+            List<BaseClass> classList = studentReportPlanService.validateClass(dto.getId(), classIds);
+            if(!classList.isEmpty()){
+                Set<String> classNames = classList.stream().map(BaseClass::getName).collect(Collectors.toSet());
+                return RT.error(classNames.toString().replace("[", "").replace("]", "") + "已在其他计划中,无法发布");
+            }
+
+            if(reportPlan.getStatus() == 1){
+                return RT.error("已发布,无法再次发布");
+            }
+
+            studentReportPlanService.release(reportPlan);
+            reportPlan.setStatus(dto.getStatus());
+            reportPlan.setModifyDate(new Date());
+            reportPlan.setModifyUserId(StpUtil.getLoginIdAsLong());
+            studentReportPlanService.update(reportPlan);
+        }else if(dto.getStatus() != null && dto.getStatus() == 2){
+            reportPlan.setStatus(dto.getStatus());
+            reportPlan.setModifyDate(new Date());
+            reportPlan.setModifyUserId(StpUtil.getLoginIdAsLong());
+            studentReportPlanService.update(reportPlan);
+        }
+        return RT.ok(true);
+    }
+
+
+    @GetMapping(value = "/tree")
+    @ApiOperation(value="学期计划树")
+    @SaCheckPermission("studentreportplan:detail")
+    public RT<List<StudentReportPlanTreeVo>> tree(){
+        List<Integer> statusList = new ArrayList<>();
+        statusList.add(1);statusList.add(2);
+        List<StudentReportPlan> list = studentReportPlanService.list(
+                new QueryWrapper<StudentReportPlan>().lambda()
+                        .eq(StudentReportPlan::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        .in(StudentReportPlan::getStatus, statusList)
+        );
+        Set<Long> semesterIds = list.stream().map(StudentReportPlan::getSemesterId).collect(Collectors.toSet());
+
+        List<BaseSemester> semesterList = semesterService.list(
+                new QueryWrapper<BaseSemester>().lambda()
+                        .eq(BaseSemester::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        .orderByDesc(BaseSemester::getName)
+        );
+
+        List<StudentReportPlanTreeVo> resultList = new ArrayList<>();
+        for (BaseSemester baseSemester : semesterList) {
+            if(!semesterIds.contains(baseSemester.getId())){
+                continue;
+            }
+            resultList.add(
+                    new StudentReportPlanTreeVo(){{
+                        setId(baseSemester.getId());
+                        setName(baseSemester.getName());
+                    }}
+            );
+        }
+
+        list.forEach((e->{
+            resultList.add(
+                    new StudentReportPlanTreeVo(){{
+                        setId(e.getId());
+                        setName(e.getName());
+                        setParentId(e.getSemesterId());
+                    }}
+            );
+        }));
+
+
+        List<StudentReportPlanTreeVo> treeVoList = TreeUtil.build(resultList);
+        return RT.ok(treeVoList);
+    }
+}

+ 90 - 0
src/main/java/com/xjrsoft/module/student/controller/StudentReportRecordController.java

@@ -3,12 +3,18 @@ package com.xjrsoft.module.student.controller;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.common.enums.EnrollTypeEnum;
 import com.xjrsoft.common.enums.GenderDictionaryEnum;
+import com.xjrsoft.common.enums.RoleCodeEnum;
 import com.xjrsoft.common.enums.StudyStatusEnum;
 import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.page.ConventPage;
@@ -16,22 +22,29 @@ import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.base.entity.BaseGrade;
 import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseGradeService;
 import com.xjrsoft.module.base.service.IBaseSemesterService;
 import com.xjrsoft.module.databoard.vo.ItemCountVo;
 import com.xjrsoft.module.student.dto.AddStudentReportRecordDto;
 import com.xjrsoft.module.student.dto.StudentReportRecordPageDto;
 import com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto;
+import com.xjrsoft.module.student.dto.StudentReportSignDto;
 import com.xjrsoft.module.student.dto.UpdateStudentReportRecordDto;
+import com.xjrsoft.module.student.entity.StudentReportPlan;
 import com.xjrsoft.module.student.entity.StudentReportRecord;
+import com.xjrsoft.module.student.service.IStudentReportPlanService;
 import com.xjrsoft.module.student.service.IStudentReportRecordService;
+import com.xjrsoft.module.student.vo.BaseMajorCategorPageVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordPageVo;
+import com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -42,8 +55,10 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -66,6 +81,9 @@ public class StudentReportRecordController {
     private final IStudentReportRecordService studentReportRecordService;
     private final IBaseSemesterService semesterService;
     private final IBaseGradeService gradeService;
+    private final IStudentReportPlanService studentReportPlanService;
+    private final IStudentReportPlanService planService;
+    private final IBaseClassService classService;
 
     @GetMapping(value = "/page")
     @ApiOperation(value="学生报到记录表列表(分页)")
@@ -179,6 +197,7 @@ public class StudentReportRecordController {
     @ApiOperation(value="班级统计")
     @SaCheckPermission("studentreportrecord:detail")
     public RT<StudentReportRecordStatisticsVo> classStatistics(@Valid StudentReportRecordStatisticsDto dto){
+
         if(dto.getTeacherId() == null){
             dto.setTeacherId(StpUtil.getLoginIdAsLong());
         }
@@ -202,6 +221,10 @@ public class StudentReportRecordController {
                 dto.setGradeId(gradeList.get(0).getId());
             }
         }
+
+        Long planId = planService.getEffectivePlanId(dto.getTeacherId());
+        dto.setStudentReportPlanId(planId);
+
         StudentReportRecordStatisticsVo statisticsVo = studentReportRecordService.getClassStatistics(dto);
         if(statisticsVo == null){
             statisticsVo = new StudentReportRecordStatisticsVo();
@@ -319,4 +342,71 @@ public class StudentReportRecordController {
         return RT.ok(statisticsVo);
     }
 
+
+    @GetMapping(value = "/plan-page")
+    @ApiOperation(value="学生报到记录表列表(分页)")
+    @SaCheckPermission("studentreportrecord:detail")
+    public RT<PageOutput<StudentReportRecordPlanPageVo>> planPage(@Valid StudentReportRecordPageDto dto){
+        List<String> roleList = StpUtil.getRoleList();
+        if(roleList.size() == 2 && roleList.contains(RoleCodeEnum.TEACHER.getCode()) && roleList.contains(RoleCodeEnum.CLASSTE.getCode())){
+            Long classId = classService.getIdByTeacherId(StpUtil.getLoginIdAsLong());
+            if(ObjectUtil.isNull(classId)){
+                return RT.ok(new PageOutput<>());
+            }
+            dto.setClassId(classId);
+            Long planId = planService.getEffectivePlanId(dto.getTeacherId());
+            dto.setStudentReportPlanId(planId);
+        }
+        Page<StudentReportRecordPlanPageVo> planPage = studentReportRecordService.getPlanPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        PageOutput<StudentReportRecordPlanPageVo> pageOutput = ConventPage.getPageOutput(planPage, StudentReportRecordPlanPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @PostMapping(value = "/sign")
+    @ApiOperation(value="学生报到")
+    @SaCheckPermission("studentreportrecord:detail")
+    public RT<Boolean> sign(@Valid @RequestBody StudentReportSignDto dto){
+        StudentReportRecord record = studentReportRecordService.getById(dto.getId());
+        StudentReportPlan reportPlan = studentReportPlanService.getById(record.getStudentReportPlanId());
+        LocalDateTime now = LocalDateTime.now();
+        if(reportPlan.getStatus() != 1 || (now.isAfter(reportPlan.getStartTime()) && now.isBefore(reportPlan.getEndTime()))){
+            return RT.error("不在报到时间内,无法报到");
+        }
+        return RT.ok(studentReportRecordService.sgin(dto));
+    }
+
+    @PostMapping(value = "/all-sign")
+    @ApiOperation(value="变更已报到")
+    @SaCheckPermission("studentreportrecord:detail")
+    public RT<Boolean> allSign(@Valid @RequestBody List<StudentReportSignDto> dtoList){
+        StudentReportRecord record = studentReportRecordService.getById(dtoList.get(0).getId());
+        StudentReportPlan reportPlan = studentReportPlanService.getById(record.getStudentReportPlanId());
+        LocalDateTime now = LocalDateTime.now();
+        if(reportPlan.getStatus() != 1 || (now.isAfter(reportPlan.getStartTime()) && now.isBefore(reportPlan.getEndTime()))){
+            return RT.error("不在报到时间内,无法报到");
+        }
+        return RT.ok(studentReportRecordService.allSgin(dtoList));
+    }
+
+
+    @PostMapping(value = "/update-stduyStatus")
+    @ApiOperation(value="切换就读方式")
+    @SaCheckPermission("studentreportrecord:detail")
+    public RT<Boolean> updateStduyStatus(@Valid StudentReportSignDto dto){
+        return RT.ok(studentReportRecordService.updateStduyStatus(dto));
+    }
+
+    @PostMapping(value = "/export-querty")
+    @ApiOperation(value="导出")
+    @SaCheckPermission("studentreportrecord:detail")
+    public ResponseEntity<byte[]> exportQuerty(@Valid StudentReportRecordPageDto dto){
+        List<StudentReportRecordPlanPageVo> planPageList = studentReportRecordService.getPlanPageList(dto);
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        EasyExcel.write(bot, StudentReportRecordPlanPageVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(planPageList);
+        String fileName = "exportQuerty" + ExcelTypeEnum.XLSX.getValue();
+        return RT.fileStream(bot.toByteArray(), fileName);
+    }
+
+
+
 }

+ 47 - 0
src/main/java/com/xjrsoft/module/student/dto/AddStudentChangeRecordDto.java

@@ -0,0 +1,47 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+public class AddStudentChangeRecordDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 学生id(xjr_user)
+    */
+    @ApiModelProperty("学生id(xjr_user)")
+    private Long userId;
+    /**
+    * 异动类型
+    */
+    @ApiModelProperty("异动类型")
+    private String changeType;
+    /**
+    * 异动前数据
+    */
+    @ApiModelProperty("异动前数据")
+    private String beforeData;
+    /**
+    * 异动后数据
+    */
+    @ApiModelProperty("异动后数据")
+    private String afterData;
+    /**
+    * 操作方式(1:系统 2:流程 3:人为)
+    */
+    @ApiModelProperty("操作方式(1:系统 2:流程 3:人为)")
+    private Integer operateMode;
+
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/student/dto/AddStudentReportPlanClassRelationDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+
+/**
+* @title: 学生报到计划-班级
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class AddStudentReportPlanClassRelationDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 计划id
+    */
+    @ApiModelProperty("计划id")
+    private Long studentReportPlanId;
+    /**
+    * 班级id
+    */
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+}

+ 68 - 0
src/main/java/com/xjrsoft/module/student/dto/AddStudentReportPlanDto.java

@@ -0,0 +1,68 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.List;
+
+
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class AddStudentReportPlanDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 学期id(base_semester)
+    */
+    @ApiModelProperty("学期id(base_semester)")
+    private Long semesterId;
+    /**
+    * 计划名称
+    */
+    @ApiModelProperty("计划名称")
+    private String name;
+    /**
+    * 报到开始时间
+    */
+    @ApiModelProperty("报到开始时间")
+    private Date startTime;
+    /**
+    * 报到结束时间
+    */
+    @ApiModelProperty("报到结束时间")
+    private Date endTime;
+    /**
+    * 数据修改开始时间
+    */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("数据修改开始时间")
+    private LocalDate updateStartTime;
+    /**
+    * 数据修改结束时间
+    */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("数据修改结束时间")
+    private LocalDate updateEndTime;
+    /**
+    * 状态(0:草稿 1:进行中 2:已结束)
+    */
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+
+    /**
+    * studentReportPlanClassRelation
+    */
+    @ApiModelProperty("studentReportPlanClassRelation子表")
+    private List<AddStudentReportPlanClassRelationDto> studentReportPlanClassRelationList;
+}

+ 7 - 0
src/main/java/com/xjrsoft/module/student/dto/BaseStudentUserPageDto.java

@@ -5,6 +5,9 @@ import com.xjrsoft.common.page.PageInput;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
 @Data
 @EqualsAndHashCode(callSuper = false)
 public class BaseStudentUserPageDto extends PageInput {
@@ -60,4 +63,8 @@ public class BaseStudentUserPageDto extends PageInput {
     @JsonIgnore
     private Long teacherId;
 
+
+    @JsonIgnore
+    private List<Long> classIds;
+
 }

+ 0 - 1
src/main/java/com/xjrsoft/module/student/dto/MajorGradeClassDto.java

@@ -2,7 +2,6 @@ package com.xjrsoft.module.student.dto;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-import org.simpleframework.xml.Default;
 
 /**
  * @author dzx

+ 41 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentChangeRecordPageDto.java

@@ -0,0 +1,41 @@
+package com.xjrsoft.module.student.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+
+/**
+* @title: 学生异动记录表分页查询入参
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class StudentChangeRecordPageDto extends PageInput {
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("身份证号")
+    private String credentialNumber;
+
+    @ApiModelProperty("异动类型")
+    private String changeType;
+
+    @ApiModelProperty("操作人姓名")
+    private String operateUserName;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty("操作开始时间")
+    private LocalDateTime operateTimeStart;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty("操作结束时间")
+    private LocalDateTime operateTimeEnd;
+}

+ 27 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentReportPlanPageDto.java

@@ -0,0 +1,27 @@
+package com.xjrsoft.module.student.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+* @title: 学生报到计划分页查询入参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class StudentReportPlanPageDto extends PageInput {
+
+    @ApiModelProperty("计划名称")
+    private String name;
+
+    @ApiModelProperty("学期id")
+    private Long semesterId;
+
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+}

+ 21 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentReportPlanStatusDto.java

@@ -0,0 +1,21 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 学生报到计划分页查询入参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class StudentReportPlanStatusDto{
+
+    @ApiModelProperty("主键id")
+    private Long id;
+
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+}

+ 38 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentReportRecordPageDto.java

@@ -1,9 +1,14 @@
 package com.xjrsoft.module.student.dto;
 
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.xjrsoft.common.page.PageInput;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.util.Date;
 
 
 /**
@@ -27,4 +32,37 @@ public class StudentReportRecordPageDto extends PageInput {
 
     @ApiModelProperty("班级id")
     private Long classId;
+
+    @ApiModelProperty("计划id")
+    private Long studentReportPlanId;
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("班级名称")
+    private String className;
+
+    @ApiModelProperty("身份证号")
+    private String credentialNumber;
+
+    @ApiModelProperty("学籍状态")
+    private String archivesStatus;
+
+    @ApiModelProperty("就读方式")
+    private String stduyStatus;
+
+    @ApiModelProperty("学生来源")
+    private String studentType;
+
+    @ApiModelProperty("是否已报到(1:是 0:否)")
+    private Integer isReport;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("报到时间开始")
+    private LocalDate reportTimeStart;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("报到时间结束")
+    private LocalDate reportTimeEnd;
+
 }

+ 5 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentReportRecordStatisticsDto.java

@@ -1,5 +1,6 @@
 package com.xjrsoft.module.student.dto;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.xjrsoft.common.page.PageInput;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -29,4 +30,8 @@ public class StudentReportRecordStatisticsDto extends PageInput {
 
     @ApiModelProperty("班级id")
     private Long classId;
+
+    @JsonIgnore
+    @ApiModelProperty("报到计划id")
+    private Long studentReportPlanId;
 }

+ 18 - 0
src/main/java/com/xjrsoft/module/student/dto/StudentReportSignDto.java

@@ -0,0 +1,18 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 学生报到计划分页查询入参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class StudentReportSignDto {
+
+    @ApiModelProperty("主键id")
+    private Long id;
+}

+ 24 - 0
src/main/java/com/xjrsoft/module/student/dto/UpdateStudentChangeRecordDto.java

@@ -0,0 +1,24 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+public class UpdateStudentChangeRecordDto extends AddStudentChangeRecordDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+}

+ 24 - 0
src/main/java/com/xjrsoft/module/student/dto/UpdateStudentReportPlanDto.java

@@ -0,0 +1,24 @@
+package com.xjrsoft.module.student.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class UpdateStudentReportPlanDto extends AddStudentReportPlanDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+}

+ 106 - 0
src/main/java/com/xjrsoft/module/student/entity/StudentChangeRecord.java

@@ -0,0 +1,106 @@
+package com.xjrsoft.module.student.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+@TableName("student_change_record")
+@ApiModel(value = "student_change_record", description = "学生异动记录表")
+public class StudentChangeRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @ApiModelProperty("修改日期")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记(0:未删除 1:已删除)
+    */
+    @ApiModelProperty("删除标记(0:未删除 1:已删除)")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Object deleteMark;
+    /**
+    * 有效标记(0:未启用 1:已启用)
+    */
+    @ApiModelProperty("有效标记(0:未启用 1:已启用)")
+    @TableField(fill = FieldFill.INSERT)
+    private Object enabledMark;
+    /**
+    * 学生id(xjr_user)
+    */
+    @ApiModelProperty("学生id(xjr_user)")
+    private Long userId;
+    /**
+    * 异动类型
+    */
+    @ApiModelProperty("异动类型")
+    private String changeType;
+    /**
+    * 异动前数据
+    */
+    @ApiModelProperty("异动前数据")
+    private String beforeData;
+
+    @ApiModelProperty("异动前数据Code")
+    private String beforeDataCode;
+
+    /**
+    * 异动后数据
+    */
+    @ApiModelProperty("异动后数据")
+    private String afterData;
+
+    @ApiModelProperty("异动后数据Code")
+    private String afterDataCode;
+    /**
+    * 操作方式(1:系统 2:流程 3:人为)
+    */
+    @ApiModelProperty("操作方式(1:系统 2:流程 3:人为)")
+    private Integer operateMode;
+
+
+}

+ 119 - 0
src/main/java/com/xjrsoft/module/student/entity/StudentReportPlan.java

@@ -0,0 +1,119 @@
+package com.xjrsoft.module.student.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.github.yulichang.annotation.EntityMapping;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+@TableName("student_report_plan")
+@ApiModel(value = "student_report_plan", description = "学生报到计划")
+public class StudentReportPlan implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @ApiModelProperty("修改日期")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记(0:未删除 1:已删除)
+    */
+    @ApiModelProperty("删除标记(0:未删除 1:已删除)")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+    /**
+    * 有效标记(0:未启用 1:已启用)
+    */
+    @ApiModelProperty("有效标记(0:未启用 1:已启用)")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer enabledMark;
+    /**
+    * 学期id(base_semester)
+    */
+    @ApiModelProperty("学期id(base_semester)")
+    private Long semesterId;
+    /**
+    * 计划名称
+    */
+    @ApiModelProperty("计划名称")
+    private String name;
+    /**
+    * 报到开始时间
+    */
+    @ApiModelProperty("报到开始时间")
+    private LocalDateTime startTime;
+    /**
+    * 报到结束时间
+    */
+    @ApiModelProperty("报到结束时间")
+    private LocalDateTime endTime;
+    /**
+    * 数据修改开始时间
+    */
+    @ApiModelProperty("数据修改开始时间")
+    private Date updateStartTime;
+    /**
+    * 数据修改结束时间
+    */
+    @ApiModelProperty("数据修改结束时间")
+    private Date updateEndTime;
+    /**
+    * 状态(0:草稿 1:进行中 2:已结束)
+    */
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+
+    /**
+    * studentReportPlanClassRelation
+    */
+    @ApiModelProperty("studentReportPlanClassRelation子表")
+    @TableField(exist = false)
+    @EntityMapping(thisField = "id", joinField = "studentReportPlanId")
+    private List<StudentReportPlanClassRelation> studentReportPlanClassRelationList;
+
+}

+ 43 - 0
src/main/java/com/xjrsoft/module/student/entity/StudentReportPlanClassRelation.java

@@ -0,0 +1,43 @@
+package com.xjrsoft.module.student.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+/**
+* @title: 学生报到计划-班级
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+@TableName("student_report_plan_class_relation")
+@ApiModel(value = "student_report_plan_class_relation", description = "学生报到计划-班级")
+public class StudentReportPlanClassRelation implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    @TableId
+    private Long id;
+    /**
+    * 计划id
+    */
+    @ApiModelProperty("计划id")
+    private Long studentReportPlanId;
+    /**
+    * 班级id
+    */
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+
+}

+ 3 - 0
src/main/java/com/xjrsoft/module/student/entity/StudentReportRecord.java

@@ -85,5 +85,8 @@ public class StudentReportRecord implements Serializable {
     @ApiModelProperty("所属学期")
     private Long baseSemesterId;
 
+    @ApiModelProperty("报到计划id")
+    private Long studentReportPlanId;
+
 
 }

+ 2 - 1
src/main/java/com/xjrsoft/module/student/mapper/BaseStudentMapper.java

@@ -9,6 +9,7 @@ import com.xjrsoft.module.student.vo.BaseStudentUserPageVo;
 import com.xjrsoft.module.student.vo.StudentInfoVo;
 import com.xjrsoft.module.student.vo.StudentPersonalInfoVo;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -35,5 +36,5 @@ public interface BaseStudentMapper extends MPJBaseMapper<BaseStudent> {
 
     Page<BaseStudentUserPageVo> getStudentPage(Page<BaseStudentUserPageVo> page, BaseStudentUserPageDto dto);
 
-    List<BaseStudentUserPageVo> getStudentList(BaseStudentUserPageDto dto);
+    List<BaseStudentUserPageVo> getStudentList(@Param("dto") BaseStudentUserPageDto dto);
 }

+ 21 - 0
src/main/java/com/xjrsoft/module/student/mapper/StudentChangeRecordMapper.java

@@ -0,0 +1,21 @@
+package com.xjrsoft.module.student.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.student.dto.StudentChangeRecordPageDto;
+import com.xjrsoft.module.student.entity.StudentChangeRecord;
+import com.xjrsoft.module.student.vo.StudentChangeRecordPageVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Mapper
+public interface StudentChangeRecordMapper extends MPJBaseMapper<StudentChangeRecord> {
+
+    Page<StudentChangeRecordPageVo> getPage(Page<StudentChangeRecordPageVo> page, @Param("dto") StudentChangeRecordPageDto dto);
+}

+ 16 - 0
src/main/java/com/xjrsoft/module/student/mapper/StudentReportPlanClassRelationMapper.java

@@ -0,0 +1,16 @@
+package com.xjrsoft.module.student.mapper;
+
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.student.entity.StudentReportPlanClassRelation;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 学生报到计划-班级
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Mapper
+public interface StudentReportPlanClassRelationMapper extends MPJBaseMapper<StudentReportPlanClassRelation> {
+
+}

+ 27 - 0
src/main/java/com/xjrsoft/module/student/mapper/StudentReportPlanMapper.java

@@ -0,0 +1,27 @@
+package com.xjrsoft.module.student.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.student.dto.StudentReportPlanPageDto;
+import com.xjrsoft.module.student.entity.StudentReportPlan;
+import com.xjrsoft.module.student.vo.StudentReportPlanPageVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Mapper
+public interface StudentReportPlanMapper extends MPJBaseMapper<StudentReportPlan> {
+
+    Page<StudentReportPlanPageVo> getPage(Page<StudentReportPlanPageVo> page, @Param("dto") StudentReportPlanPageDto dto);
+
+
+    List<BaseClass> validateClass(@Param("id") Long id, @Param("classIds") List<Long> classIds);
+}

+ 5 - 0
src/main/java/com/xjrsoft/module/student/mapper/StudentReportRecordMapper.java

@@ -6,6 +6,7 @@ import com.xjrsoft.module.student.dto.StudentReportRecordPageDto;
 import com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto;
 import com.xjrsoft.module.student.entity.StudentReportRecord;
 import com.xjrsoft.module.student.vo.StudentReportRecordPageVo;
+import com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsVo;
 import org.apache.ibatis.annotations.Mapper;
@@ -28,4 +29,8 @@ public interface StudentReportRecordMapper extends MPJBaseMapper<StudentReportRe
 
     Page<StudentReportRecordPageVo> getMobilePage(Page<StudentReportRecordPageVo> page, @Param("dto") StudentReportRecordPageDto dto);
 
+    Page<StudentReportRecordPlanPageVo> getPlanPage(Page<StudentReportRecordPlanPageVo> page, @Param("dto") StudentReportRecordPageDto dto);
+
+    List<StudentReportRecordPlanPageVo> getPlanPageList(@Param("dto") StudentReportRecordPageDto dto);
+
 }

+ 30 - 0
src/main/java/com/xjrsoft/module/student/service/IStudentChangeRecordService.java

@@ -0,0 +1,30 @@
+package com.xjrsoft.module.student.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.room.entity.WfRoomApplicant;
+import com.xjrsoft.module.student.dto.StudentChangeRecordPageDto;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
+import com.xjrsoft.module.student.entity.StudentChangeRecord;
+import com.xjrsoft.module.student.vo.StudentChangeRecordPageVo;
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+
+public interface IStudentChangeRecordService extends MPJBaseService<StudentChangeRecord> {
+
+    Boolean insertDataByChangeClass(Long formId);
+
+    Boolean insertDataByTemporaryChangeClass(Long formId);
+
+    Boolean insertDataByWfRoomApplicant(WfRoomApplicant wfRoomApplicant, BaseStudentSchoolRoll schoolRoll);
+
+    Boolean insertData(String beforeData, String beforeDataCode, String afterData, String afterDataCode, Long userId, Long createUserId, String changeType, Integer operateMode);
+
+    Page<StudentChangeRecordPageVo> getPage(Page<StudentChangeRecordPageVo> page, StudentChangeRecordPageDto dto);
+
+}

+ 1 - 0
src/main/java/com/xjrsoft/module/student/service/IStudentManagerService.java

@@ -68,4 +68,5 @@ public interface IStudentManagerService extends MPJBaseService<BaseStudentUser>
 
      List<BaseDepMajorGradeClassStudenTreeVo> deptMajorGradeClassTree(MajorGradeClassDto dto);
 
+
 }

+ 51 - 0
src/main/java/com/xjrsoft/module/student/service/IStudentReportPlanService.java

@@ -0,0 +1,51 @@
+package com.xjrsoft.module.student.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.student.dto.StudentReportPlanPageDto;
+import com.xjrsoft.module.student.entity.StudentReportPlan;
+import com.xjrsoft.module.student.vo.StudentReportPlanPageVo;
+
+import java.util.List;
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+
+public interface IStudentReportPlanService extends MPJBaseService<StudentReportPlan> {
+    /**
+    * 新增
+    *
+    * @param studentReportPlan
+    * @return
+    */
+    Boolean add(StudentReportPlan studentReportPlan);
+
+    /**
+    * 更新
+    *
+    * @param studentReportPlan
+    * @return
+    */
+    Boolean update(StudentReportPlan studentReportPlan);
+
+    /**
+    * 删除
+    *
+    * @param ids
+    * @return
+    */
+    Boolean delete(List<Long> ids);
+
+    Page<StudentReportPlanPageVo> getPage(Page<StudentReportPlanPageVo> page, StudentReportPlanPageDto dto);
+
+    List<BaseClass> validateClass(Long id, List<Long> classIds);
+
+    Boolean release(StudentReportPlan studentReportPlan);
+
+    Long getEffectivePlanId(Long teacherId);
+}

+ 16 - 0
src/main/java/com/xjrsoft/module/student/service/IStudentReportRecordService.java

@@ -4,10 +4,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.student.dto.StudentReportRecordPageDto;
 import com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto;
+import com.xjrsoft.module.student.dto.StudentReportSignDto;
 import com.xjrsoft.module.student.entity.StudentReportRecord;
 import com.xjrsoft.module.student.vo.StudentReportRecordPageVo;
+import com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsVo;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -29,4 +32,17 @@ public interface IStudentReportRecordService extends MPJBaseService<StudentRepor
     Boolean removeByUserId(List<Long> ids);
 
     Page<StudentReportRecordPageVo> getMobilePage(Page<StudentReportRecordPageVo> page, StudentReportRecordPageDto dto);
+
+
+    Boolean sgin(StudentReportSignDto dto);
+
+
+    Page<StudentReportRecordPlanPageVo> getPlanPage(Page<StudentReportRecordPlanPageVo> page, StudentReportRecordPageDto dto);
+
+    List<StudentReportRecordPlanPageVo> getPlanPageList(StudentReportRecordPageDto dto);
+
+
+    Boolean allSgin(List<StudentReportSignDto> dtoList);
+
+    Boolean updateStduyStatus(StudentReportSignDto dto);
 }

+ 19 - 0
src/main/java/com/xjrsoft/module/student/service/impl/SchoolRollStudentServiceImpl.java

@@ -1,5 +1,6 @@
 package com.xjrsoft.module.student.service.impl;
 
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -7,12 +8,14 @@ import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.xjrsoft.common.enums.ArchivesStatusEnum;
 import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.common.enums.SchoolChangeType;
+import com.xjrsoft.common.enums.StudentChangeTypeEnum;
 import com.xjrsoft.module.student.dto.SchoolRollStudentPageDto;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.entity.SchoolRollStudent;
 import com.xjrsoft.module.student.mapper.BaseStudentSchoolRollMapper;
 import com.xjrsoft.module.student.mapper.SchoolRollStudentMapper;
 import com.xjrsoft.module.student.service.ISchoolRollStudentService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.student.vo.SchoolRollStudentPageVo;
 import com.xjrsoft.module.student.vo.SchoolRollStudentVo;
 import com.xjrsoft.module.teacher.entity.XjrUser;
@@ -33,6 +36,8 @@ public class SchoolRollStudentServiceImpl extends MPJBaseServiceImpl<SchoolRollS
     private final XjrUserMapper xjrUserMapper;
     private final BaseStudentSchoolRollMapper baseStudentSchoolRollMapper;
 
+    private final IStudentChangeRecordService changeRecordService;
+
 
     @Override
     public Boolean dataHandle(Long dataId) {
@@ -79,6 +84,20 @@ public class SchoolRollStudentServiceImpl extends MPJBaseServiceImpl<SchoolRollS
             Wrappers.lambdaQuery(BaseStudentSchoolRoll.class).eq(BaseStudentSchoolRoll::getUserId, schoolRollStudent.getStudentId())
         );
         if(ObjectUtil.isNotNull(studentSchoolRoll)){
+
+            //记录异动
+            changeRecordService.insertData(
+                    studentSchoolRoll.getArchivesStatus(),
+                    ArchivesStatusEnum.fromCode(studentSchoolRoll.getArchivesStatus()),
+                    ArchivesStatusEnum.FB2902.getCode(),
+                    ArchivesStatusEnum.FB2902.getValue(),
+                    studentSchoolRoll.getUserId(),
+                    StpUtil.getLoginIdAsLong(),
+                    StudentChangeTypeEnum.ArchivesStatus.getCode(),
+                    2
+            );
+
+
             studentSchoolRoll.setArchivesStatus(ArchivesStatusEnum.FB2902.getCode());
             baseStudentSchoolRollMapper.updateById(studentSchoolRoll);
         }

+ 156 - 0
src/main/java/com/xjrsoft/module/student/service/impl/StudentChangeRecordServiceImpl.java

@@ -0,0 +1,156 @@
+package com.xjrsoft.module.student.service.impl;
+
+import cn.hutool.db.Entity;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.common.enums.RoomApplicantTypeEnum;
+import com.xjrsoft.common.enums.StudentChangeTypeEnum;
+import com.xjrsoft.common.enums.StudyStatusEnum;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.base.service.IBaseClassService;
+import com.xjrsoft.module.room.entity.WfRoomApplicant;
+import com.xjrsoft.module.student.dto.StudentChangeRecordPageDto;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
+import com.xjrsoft.module.student.entity.StudentChangeClass;
+import com.xjrsoft.module.student.entity.StudentChangeRecord;
+import com.xjrsoft.module.student.mapper.StudentChangeClassMapper;
+import com.xjrsoft.module.student.mapper.StudentChangeRecordMapper;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
+import com.xjrsoft.module.student.vo.StudentChangeRecordPageVo;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+* @title: 学生异动记录表
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class StudentChangeRecordServiceImpl extends MPJBaseServiceImpl<StudentChangeRecordMapper, StudentChangeRecord> implements IStudentChangeRecordService {
+
+    private final StudentChangeClassMapper studentChangeClassMapper;
+    private final IBaseClassService classService;
+    /**
+     * 记录转班异动数据
+     * @param formId 转班流程表的id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertDataByChangeClass(Long formId) {
+        StudentChangeClass changeClass = studentChangeClassMapper.selectById(formId);
+
+        BaseClass afterClass = classService.getById(changeClass.getAfterClassId());
+        BaseClass beforeClass = classService.getById(changeClass.getBeforeClassId());
+
+        StudentChangeRecord record = new StudentChangeRecord() {{
+            setAfterData(afterClass.getName());
+            setAfterDataCode(changeClass.getAfterClassId().toString());
+            setBeforeData(beforeClass.getName());
+            setBeforeDataCode(changeClass.getBeforeClassId().toString());
+            setChangeType(StudentChangeTypeEnum.ChangeClass.getCode());
+            setUserId(changeClass.getStudentUserId());
+            setCreateDate(new Date());
+            setCreateUserId(changeClass.getCreateUserId());
+            setOperateMode(2);
+        }};
+
+        return this.save(record);
+    }
+
+    /**
+     * 临时转班异动数据记录
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertDataByTemporaryChangeClass(Long formId) {
+        String tableName = "temporary_change_class";
+        Entity entity = Entity.create(tableName);
+        entity.set("id", formId);
+        Map<String, Object> objectMap = SqlRunnerAdapter.db().dynamicSelectOne(tableName, entity);
+
+        BaseClass afterClass = classService.getById(objectMap.get("after_class_id").toString());
+        BaseClass beforeClass = classService.getById(objectMap.get("before_class_id").toString());
+
+        StudentChangeRecord record = new StudentChangeRecord() {{
+            setAfterData(afterClass.getName());
+            setAfterDataCode(afterClass.getId().toString());
+            setBeforeData(beforeClass.getName());
+            setBeforeDataCode(beforeClass.getId().toString());
+            setChangeType(StudentChangeTypeEnum.ChangeClass.getCode());
+            setUserId(Long.parseLong(objectMap.get("student_user_id").toString()));
+            setCreateDate(new Date());
+            setCreateUserId(Long.parseLong(objectMap.get("create_user_id").toString()));
+            setOperateMode(2);
+        }};
+
+        return this.save(record);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertDataByWfRoomApplicant(WfRoomApplicant wfRoomApplicant, BaseStudentSchoolRoll schoolRoll) {
+
+        StudentChangeRecord record = new StudentChangeRecord() {{
+
+            if(RoomApplicantTypeEnum.ToBeBoarder.getCode().equals(wfRoomApplicant.getRecedeType())){
+                setAfterData(StudyStatusEnum.InResidence.getValue());
+                setAfterDataCode(StudyStatusEnum.InResidence.getCode());
+            }else if(RoomApplicantTypeEnum.ToBeDayPupil.getCode().equals(wfRoomApplicant.getRecedeType())){
+                setAfterData(StudyStatusEnum.AttendDaySchool.getValue());
+                setAfterDataCode(StudyStatusEnum.AttendDaySchool.getCode());
+            }
+
+            setBeforeData(schoolRoll.getStduyStatus());
+            setBeforeDataCode(StudyStatusEnum.fromCode(schoolRoll.getStduyStatus()));
+            setChangeType(StudentChangeTypeEnum.StduyStatus.getCode());
+            setUserId(schoolRoll.getUserId());
+            setCreateDate(new Date());
+            setCreateUserId(wfRoomApplicant.getCreateUserId());
+            setOperateMode(2);
+        }};
+
+        return this.save(record);
+    }
+
+    /**
+     *
+     * @param beforeData 变更之前的数据
+     * @param beforeDataCode 变更之前的数据code
+     * @param afterData 变更之后的数据
+     * @param afterDataCode 变更之后的数据code
+     * @param userId 学生id
+     * @param createUserId 操作人id
+     * @param changeType 变更类型
+     * @param operateMode 操作方式
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertData(String beforeData, String beforeDataCode, String afterData, String afterDataCode, Long userId, Long createUserId, String changeType, Integer operateMode) {
+        StudentChangeRecord record = new StudentChangeRecord() {{
+            setAfterData(afterData);
+            setAfterDataCode(afterDataCode);
+            setBeforeData(beforeData);
+            setBeforeDataCode(beforeDataCode);
+            setChangeType(changeType);
+            setUserId(userId);
+            setCreateDate(new Date());
+            setCreateUserId(createUserId);
+            setOperateMode(operateMode);
+        }};
+
+        return this.save(record);
+    }
+
+    @Override
+    public Page<StudentChangeRecordPageVo> getPage(Page<StudentChangeRecordPageVo> page, StudentChangeRecordPageDto dto) {
+        return this.baseMapper.getPage(page, dto);
+    }
+
+}

+ 10 - 6
src/main/java/com/xjrsoft/module/student/service/impl/StudentManagerServiceImpl.java

@@ -52,6 +52,7 @@ import com.xjrsoft.module.student.entity.BaseStudentFamilyMember;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.entity.BaseStudentSubsidize;
 import com.xjrsoft.module.student.entity.BaseStudentUser;
+import com.xjrsoft.module.student.entity.StudentChangeRecord;
 import com.xjrsoft.module.student.mapper.BaseStudentFamilyMapper;
 import com.xjrsoft.module.student.mapper.BaseStudentFamilyMemberMapper;
 import com.xjrsoft.module.student.mapper.BaseStudentMapper;
@@ -608,6 +609,9 @@ public class StudentManagerServiceImpl extends MPJBaseServiceImpl<BaseStudentUse
         List<BaseStudentFamily> insertFamilyList = new ArrayList();
         List<BaseStudentContact> insertContactList = new ArrayList();
 
+        //异动记录
+        List<StudentChangeRecord> changeRecordList = new ArrayList();
+
         long createUserId = StpUtil.getLoginIdAsLong();
 //        long createUserId = 1000000000000000000L;
         int row = 3;
@@ -867,23 +871,23 @@ public class StudentManagerServiceImpl extends MPJBaseServiceImpl<BaseStudentUse
                 schoolRoll.setStudyYear(Double.parseDouble(dataMaps.get(52).toString()));//学制
             }
             if(dataMaps.get(53) != null && !"".equals(dataMaps.get(53).toString())){
-                schoolRoll.setClassId(classMap.get(dataMaps.get(53).toString()));//班级
+                //schoolRoll.setClassId(classMap.get(dataMaps.get(53).toString()));//班级
             }
             if(dataMaps.get(54) != null && !"".equals(dataMaps.get(54).toString())){
                 schoolRoll.setStudentSource(dictionary.get("student_type" + dataMaps.get(54).toString()));//学生来源
             }
             if(dataMaps.get(55) != null && !"".equals(dataMaps.get(55).toString())){
-                schoolRoll.setStudentType(dictionary.get("student_type" + dataMaps.get(55).toString()));//学生类别
+                //schoolRoll.setStudentType(dictionary.get("student_type" + dataMaps.get(55).toString()));//学生类别
             }
             if(dataMaps.get(56) != null && !"".equals(dataMaps.get(56).toString())){
-                schoolRoll.setArchivesStatus(dictionary.get("archives_status" + dataMaps.get(56).toString()));//学籍状态
+                //schoolRoll.setArchivesStatus(dictionary.get("archives_status" + dataMaps.get(56).toString()));//学籍状态
             }
             if(dataMaps.get(57) != null && !"".equals(dataMaps.get(57).toString())){
-                schoolRoll.setLearnStatus(dictionary.get("roll_modality" + dataMaps.get(57).toString()));//学习形式
-                schoolRoll.setRollModality(dictionary.get("roll_modality" + dataMaps.get(57).toString()));//学习形式
+                //schoolRoll.setLearnStatus(dictionary.get("roll_modality" + dataMaps.get(57).toString()));//学习形式
+                //schoolRoll.setRollModality(dictionary.get("roll_modality" + dataMaps.get(57).toString()));//学习形式
             }
             if(dataMaps.get(58) != null && !"".equals(dataMaps.get(58).toString())){
-                schoolRoll.setStduyStatus(dictionary.get("stduy_status" + dataMaps.get(58).toString()));//就读方式
+                //schoolRoll.setStduyStatus(dictionary.get("stduy_status" + dataMaps.get(58).toString()));//就读方式
             }
             if(dataMaps.get(59) != null && !"".equals(dataMaps.get(59).toString())){
                 schoolRoll.setChooseStatus(dictionary.get("choose_status" + dataMaps.get(59).toString()));//分流状态

+ 213 - 0
src/main/java/com/xjrsoft/module/student/service/impl/StudentReportPlanServiceImpl.java

@@ -0,0 +1,213 @@
+package com.xjrsoft.module.student.service.impl;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.student.dto.BaseStudentUserPageDto;
+import com.xjrsoft.module.student.dto.StudentReportPlanPageDto;
+import com.xjrsoft.module.student.entity.BaseStudent;
+import com.xjrsoft.module.student.entity.StudentReportPlan;
+import com.xjrsoft.module.student.entity.StudentReportPlanClassRelation;
+import com.xjrsoft.module.student.entity.StudentReportRecord;
+import com.xjrsoft.module.student.mapper.StudentReportPlanClassRelationMapper;
+import com.xjrsoft.module.student.mapper.StudentReportPlanMapper;
+import com.xjrsoft.module.student.service.IBaseStudentService;
+import com.xjrsoft.module.student.service.IStudentReportPlanService;
+import com.xjrsoft.module.student.service.IStudentReportRecordService;
+import com.xjrsoft.module.student.vo.BaseStudentUserPageVo;
+import com.xjrsoft.module.student.vo.StudentReportPlanPageVo;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+* @title: 学生报到计划
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class StudentReportPlanServiceImpl extends MPJBaseServiceImpl<StudentReportPlanMapper, StudentReportPlan> implements IStudentReportPlanService {
+    private final StudentReportPlanMapper planMapper;
+
+    private final StudentReportPlanClassRelationMapper relationMapper;
+
+    private final IBaseStudentService studentService;
+
+    private final IStudentReportRecordService reportRecordService;
+
+    private final IUserService userService;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(StudentReportPlan studentReportPlan) {
+        studentReportPlan.setDeleteMark(DeleteMark.NODELETE.getCode());
+        studentReportPlan.setEnabledMark(EnabledMark.ENABLED.getCode());
+        studentReportPlan.setCreateDate(new Date());
+        planMapper.insert(studentReportPlan);
+        for (StudentReportPlanClassRelation studentReportPlanClassRelation : studentReportPlan.getStudentReportPlanClassRelationList()) {
+            studentReportPlanClassRelation.setStudentReportPlanId(studentReportPlan.getId());
+            relationMapper.insert(studentReportPlanClassRelation);
+        }
+
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(StudentReportPlan studentReportPlan) {
+        planMapper.updateById(studentReportPlan);
+        //********************************* StudentReportPlanClassRelation  增删改  开始 *******************************************/
+        {
+            // 查出所有子级的id
+            List<StudentReportPlanClassRelation> studentReportPlanClassRelationList = relationMapper.selectList(Wrappers.lambdaQuery(StudentReportPlanClassRelation.class).eq(StudentReportPlanClassRelation::getStudentReportPlanId, studentReportPlan.getId()).select(StudentReportPlanClassRelation::getId));
+            List<Long> studentReportPlanClassRelationIds = studentReportPlanClassRelationList.stream().map(StudentReportPlanClassRelation::getId).collect(Collectors.toList());
+            //原有子表单 没有被删除的主键
+            List<Long> studentReportPlanClassRelationOldIds = studentReportPlan.getStudentReportPlanClassRelationList().stream().map(StudentReportPlanClassRelation::getId).filter(Objects::nonNull).collect(Collectors.toList());
+            //找到需要删除的id
+            List<Long> studentReportPlanClassRelationRemoveIds = studentReportPlanClassRelationIds.stream().filter(item -> !studentReportPlanClassRelationOldIds.contains(item)).collect(Collectors.toList());
+
+            for (StudentReportPlanClassRelation studentReportPlanClassRelation : studentReportPlan.getStudentReportPlanClassRelationList()) {
+                //如果不等于空则修改
+                if (studentReportPlanClassRelation.getId() != null) {
+                    relationMapper.updateById(studentReportPlanClassRelation);
+                }
+                //如果等于空 则新增
+                else {
+                    //已经不存在的id 删除
+                    studentReportPlanClassRelation.setStudentReportPlanId(studentReportPlan.getId());
+                    relationMapper.insert(studentReportPlanClassRelation);
+                }
+            }
+            //已经不存在的id 删除
+            if(studentReportPlanClassRelationRemoveIds.size() > 0){
+                relationMapper.deleteBatchIds(studentReportPlanClassRelationRemoveIds);
+            }
+        }
+        //********************************* StudentReportPlanClassRelation  增删改  结束 *******************************************/
+
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delete(List<Long> ids) {
+        planMapper.deleteBatchIds(ids);
+        relationMapper.delete(Wrappers.lambdaQuery(StudentReportPlanClassRelation.class).in(StudentReportPlanClassRelation::getStudentReportPlanId, ids));
+
+        return true;
+    }
+
+    @Override
+    public Page<StudentReportPlanPageVo> getPage(Page<StudentReportPlanPageVo> page, StudentReportPlanPageDto dto) {
+        return this.baseMapper.getPage(page, dto);
+    }
+
+    @Override
+    public List<BaseClass> validateClass(Long id, List<Long> classIds) {
+        return this.baseMapper.validateClass(id, classIds);
+    }
+
+    /**
+     * 发布
+     * 发布之后,将学生初始化到报到记录表中
+     * 发布之后,将学生给禁用掉
+     * @param studentReportPlan
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean release(StudentReportPlan studentReportPlan) {
+        List<Long> classIds = studentReportPlan.getStudentReportPlanClassRelationList().stream().map(StudentReportPlanClassRelation::getClassId).collect(Collectors.toList());
+        //1、查询选择的学生
+        List<BaseStudentUserPageVo> studentList = studentService.getStudentList(new BaseStudentUserPageDto() {{
+            setClassIds(classIds);
+        }});
+
+        Date createDate = new Date();
+        List<StudentReportRecord> insertList = new ArrayList<>();
+        for (BaseStudentUserPageVo student : studentList) {
+            insertList.add(
+                    new StudentReportRecord(){{
+                        setCreateDate(createDate);
+                        setCreateUserId(StpUtil.getLoginIdAsLong());
+                        setUserId(Long.parseLong(student.getId()));
+                        setBaseSemesterId(studentReportPlan.getSemesterId());
+                        setStudentReportPlanId(studentReportPlan.getId());
+                    }}
+            );
+        }
+
+        if(!insertList.isEmpty()){
+            reportRecordService.remove(
+                    new QueryWrapper<StudentReportRecord>().lambda()
+                            .eq(StudentReportRecord::getStudentReportPlanId, studentReportPlan.getId())
+            );
+
+            reportRecordService.saveBatch(insertList);
+            Set<String> studentUserIds = studentList.stream().map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
+            //发布后,将学生的状态改为不正常
+            List<BaseStudent> baseStudents = studentService.list(
+                    new QueryWrapper<BaseStudent>().lambda()
+                            .in(BaseStudent::getUserId, studentUserIds)
+            );
+
+            for (BaseStudent baseStudent : baseStudents) {
+                baseStudent.setIsNormal(0);
+            }
+
+            studentService.updateBatchById(baseStudents);
+
+            //修改用户的状态
+            List<User> userList = userService.listByIds(studentUserIds);
+
+            for (User user : userList) {
+                user.setEnabledMark(EnabledMark.DISABLED.getCode());
+            }
+
+            userService.updateBatchById(userList);
+        }
+        return true;
+    }
+
+    /**
+     * 查询有效的计划id
+     * @param teacherId 班主任id
+     * @return 计划id
+     */
+    @Override
+    public Long getEffectivePlanId(Long teacherId) {
+        LocalDateTime now = LocalDateTime.now();
+        List<StudentReportPlan> list = this.selectJoinList(StudentReportPlan.class,
+                new MPJLambdaWrapper<StudentReportPlan>()
+                        .leftJoin(StudentReportPlanClassRelation.class, StudentReportPlanClassRelation::getStudentReportPlanId, StudentReportPlan::getId)
+                        .leftJoin(BaseClass.class, BaseClass::getId, StudentReportPlanClassRelation::getClassId)
+                        .eq(teacherId != null, BaseClass::getTeacherId, teacherId)
+                        .eq(StudentReportPlan::getEnabledMark, EnabledMark.ENABLED.getCode())
+                        .le(StudentReportPlan::getStartTime, now)
+                        .ge(StudentReportPlan::getEndTime, now)
+                        .orderByDesc(StudentReportPlan::getId)
+        );
+        if(!list.isEmpty()){
+           return list.get(0).getId();
+        }
+        return null;
+    }
+}

+ 118 - 0
src/main/java/com/xjrsoft/module/student/service/impl/StudentReportRecordServiceImpl.java

@@ -1,19 +1,35 @@
 package com.xjrsoft.module.student.service.impl;
 
+import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
+import com.xjrsoft.common.enums.StudentChangeTypeEnum;
+import com.xjrsoft.common.enums.StudyStatusEnum;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
 import com.xjrsoft.module.student.dto.StudentReportRecordPageDto;
 import com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto;
+import com.xjrsoft.module.student.dto.StudentReportSignDto;
+import com.xjrsoft.module.student.entity.BaseStudent;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.student.entity.StudentReportRecord;
 import com.xjrsoft.module.student.mapper.StudentReportRecordMapper;
+import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
+import com.xjrsoft.module.student.service.IBaseStudentService;
+import com.xjrsoft.module.student.service.IStudentChangeRecordService;
 import com.xjrsoft.module.student.service.IStudentReportRecordService;
 import com.xjrsoft.module.student.vo.StudentReportRecordPageVo;
+import com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo;
 import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsVo;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -25,6 +41,11 @@ import java.util.List;
 @Service
 @AllArgsConstructor
 public class StudentReportRecordServiceImpl extends MPJBaseServiceImpl<StudentReportRecordMapper, StudentReportRecord> implements IStudentReportRecordService {
+
+    private final IBaseStudentService studentService;
+    private final IUserService userService;
+    private final IBaseStudentSchoolRollService rollService;
+    private final IStudentChangeRecordService changeRecordService;
     @Override
     public StudentReportRecordStatisticsVo getClassStatistics(StudentReportRecordStatisticsDto dto) {
         return this.baseMapper.getClassStatistics(dto);
@@ -47,4 +68,101 @@ public class StudentReportRecordServiceImpl extends MPJBaseServiceImpl<StudentRe
     public Page<StudentReportRecordPageVo> getMobilePage(Page<StudentReportRecordPageVo> page, StudentReportRecordPageDto dto) {
         return this.baseMapper.getMobilePage(page, dto);
     }
+
+    /**
+     * 签到,签到后,修改学生的状态信息
+     * @param dto
+     * @return
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean sgin(StudentReportSignDto dto) {
+        StudentReportRecord record = this.getById(dto.getId());
+        record.setModifyDate(new Date());
+        record.setUserId(StpUtil.getLoginIdAsLong());
+        record.setReportTime(new Date());
+        this.updateById(record);
+
+        BaseStudent student = studentService.getOne(
+                new QueryWrapper<BaseStudent>().lambda()
+                        .eq(BaseStudent::getUserId, record.getUserId())
+                        .eq(BaseStudent::getDeleteMark, DeleteMark.NODELETE.getCode())
+        );
+        student.setIsNormal(1);
+        studentService.updateById(student);
+
+        User user = userService.getById(record.getUserId());
+        user.setEnabledMark(EnabledMark.ENABLED.getCode());
+        userService.updateById(user);
+        return true;
+    }
+
+    @Override
+    public Page<StudentReportRecordPlanPageVo> getPlanPage(Page<StudentReportRecordPlanPageVo> page, StudentReportRecordPageDto dto) {
+        return this.baseMapper.getPlanPage(page, dto);
+    }
+
+    @Override
+    public List<StudentReportRecordPlanPageVo> getPlanPageList(StudentReportRecordPageDto dto) {
+        return this.baseMapper.getPlanPageList(dto);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean allSgin(List<StudentReportSignDto> dtoList) {
+        for (StudentReportSignDto dto : dtoList) {
+            StudentReportRecord record = this.getById(dto.getId());
+            record.setModifyDate(new Date());
+            record.setUserId(StpUtil.getLoginIdAsLong());
+            record.setReportTime(new Date());
+            this.updateById(record);
+
+            BaseStudent student = studentService.getOne(
+                    new QueryWrapper<BaseStudent>().lambda()
+                            .eq(BaseStudent::getUserId, record.getUserId())
+                            .eq(BaseStudent::getDeleteMark, DeleteMark.NODELETE.getCode())
+            );
+            student.setIsNormal(1);
+            studentService.updateById(student);
+
+            User user = userService.getById(record.getUserId());
+            user.setEnabledMark(EnabledMark.ENABLED.getCode());
+            userService.updateById(user);
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateStduyStatus(StudentReportSignDto dto) {
+        StudentReportRecord record = this.getById(dto.getId());
+        BaseStudentSchoolRoll roll = rollService.getOne(
+                new QueryWrapper<BaseStudentSchoolRoll>().lambda()
+                        .eq(BaseStudentSchoolRoll::getUserId, record.getUserId())
+                        .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
+        );
+
+        String beforeDataCode = roll.getStduyStatus();
+        String beforeData = StudyStatusEnum.fromCode(beforeDataCode);
+
+
+        if(StudyStatusEnum.InResidence.getCode().equals(roll.getStduyStatus())){
+            roll.setStduyStatus(StudyStatusEnum.AttendDaySchool.getCode());
+        }else if(StudyStatusEnum.AttendDaySchool.getCode().equals(roll.getStduyStatus())){
+            roll.setStduyStatus(StudyStatusEnum.InResidence.getCode());
+        }
+        rollService.updateById(roll);
+
+        String afterDataCode = roll.getStduyStatus();
+        String afterData = StudyStatusEnum.fromCode(afterDataCode);
+
+        changeRecordService.insertData(
+                beforeDataCode, beforeData,
+                afterDataCode, afterData,
+                StpUtil.getLoginIdAsLong(), StpUtil.getLoginIdAsLong(),
+                StudentChangeTypeEnum.StduyStatus.getCode(), 3
+        );
+
+        return true;
+    }
 }

+ 0 - 2
src/main/java/com/xjrsoft/module/student/vo/BaseStudentAssessmentInspectionMobileVo.java

@@ -1,7 +1,5 @@
 package com.xjrsoft.module.student.vo;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.xjrsoft.module.student.entity.BaseStudentAssessmentStudentRelation;
 import com.xjrsoft.module.system.entity.File;
 import io.swagger.annotations.ApiModelProperty;

+ 72 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentChangeRecordPageVo.java

@@ -0,0 +1,72 @@
+package com.xjrsoft.module.student.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+* @title: 学生异动记录表分页列表出参
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+public class StudentChangeRecordPageVo {
+
+    /**
+    * 主键
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("主键")
+    @ApiModelProperty("主键")
+    private String id;
+    /**
+    * 创建时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("操作时间")
+    @ApiModelProperty("操作时间")
+    private Date operateDate;
+    /**
+    * 学生id(xjr_user)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("姓名")
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("身份证号")
+    private String credentialNumber;
+
+    @ApiModelProperty("操作人姓名")
+    private String operateUserName;
+
+    @ApiModelProperty("性别")
+    private String gender;
+
+    /**
+    * 异动类型
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("异动类型")
+    @ApiModelProperty("异动类型")
+    private String changeType;
+    /**
+    * 异动前数据
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("异动前数据")
+    @ApiModelProperty("异动前数据")
+    private String beforeData;
+    /**
+    * 异动后数据
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("异动后数据")
+    @ApiModelProperty("异动后数据")
+    private String afterData;
+
+}

+ 48 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentChangeRecordVo.java

@@ -0,0 +1,48 @@
+package com.xjrsoft.module.student.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+* @title: 学生异动记录表表单出参
+* @Author dzx
+* @Date: 2025-01-20
+* @Version 1.0
+*/
+@Data
+public class StudentChangeRecordVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 学生id(xjr_user)
+    */
+    @ApiModelProperty("学生id(xjr_user)")
+    private Long userId;
+    /**
+    * 异动类型
+    */
+    @ApiModelProperty("异动类型")
+    private String changeType;
+    /**
+    * 异动前数据
+    */
+    @ApiModelProperty("异动前数据")
+    private String beforeData;
+    /**
+    * 异动后数据
+    */
+    @ApiModelProperty("异动后数据")
+    private String afterData;
+    /**
+    * 操作方式(1:系统 2:流程 3:人为)
+    */
+    @ApiModelProperty("操作方式(1:系统 2:流程 3:人为)")
+    private Integer operateMode;
+
+
+
+}

+ 36 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanClassRelationVo.java

@@ -0,0 +1,36 @@
+package com.xjrsoft.module.student.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+* @title: 学生报到计划-班级表单出参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class StudentReportPlanClassRelationVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 计划id
+    */
+    @ApiModelProperty("计划id")
+    private Long studentReportPlanId;
+    /**
+    * 班级id
+    */
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+    @ApiModelProperty("班级名称")
+    private String className;
+
+
+
+}

+ 122 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanPageVo.java

@@ -0,0 +1,122 @@
+package com.xjrsoft.module.student.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+* @title: 学生报到计划分页列表出参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class StudentReportPlanPageVo {
+
+    /**
+    * 主键
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("主键")
+    @ApiModelProperty("主键")
+    private String id;
+    /**
+    * 创建人
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("创建人")
+    @ApiModelProperty("创建人")
+    private String createUserName;
+    /**
+    * 创建时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("创建时间")
+    @ApiModelProperty("创建时间")
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("修改人id")
+    @ApiModelProperty("修改人id")
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("修改日期")
+    @ApiModelProperty("修改日期")
+    private Date modifyDate;
+    /**
+    * 删除标记(0:未删除 1:已删除)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("删除标记(0:未删除 1:已删除)")
+    @ApiModelProperty("删除标记(0:未删除 1:已删除)")
+    private Object deleteMark;
+    /**
+    * 有效标记(0:未启用 1:已启用)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("有效标记(0:未启用 1:已启用)")
+    @ApiModelProperty("有效标记(0:未启用 1:已启用)")
+    private Object enabledMark;
+    /**
+    * 学期id(base_semester)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("学期id(base_semester)")
+    @ApiModelProperty("学期id(base_semester)")
+    private Long semesterId;
+
+    @ApiModelProperty("所属学期")
+    private String semesterName;
+
+    /**
+    * 计划名称
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("计划名称")
+    @ApiModelProperty("计划名称")
+    private String name;
+    /**
+    * 报到开始时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("报到开始时间")
+    @ApiModelProperty("报到开始时间")
+    private Date startTime;
+    /**
+    * 报到结束时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("报到结束时间")
+    @ApiModelProperty("报到结束时间")
+    private Date endTime;
+    /**
+    * 数据修改开始时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("数据修改开始时间")
+    @ApiModelProperty("数据修改开始时间")
+    private Date updateStartTime;
+    /**
+    * 数据修改结束时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("数据修改结束时间")
+    @ApiModelProperty("数据修改结束时间")
+    private Date updateEndTime;
+    /**
+    * 状态(0:草稿 1:进行中 2:已结束)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanTreeVo.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.student.vo;
+
+import com.xjrsoft.common.model.tree.ITreeNode;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author dzx
+ * @date 2024年6月27日
+ */
+@Data
+public class StudentReportPlanTreeVo implements ITreeNode<StudentReportPlanTreeVo, Long>, Serializable {
+
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("name")
+    private String name;
+
+    @ApiModelProperty("disabled")
+    private Long parentId;
+
+    @ApiModelProperty("children")
+    private List<StudentReportPlanTreeVo> children;
+
+    @ApiModelProperty("状态(1:进行中,2:已结束)")
+    private Integer status;
+
+}

+ 66 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentReportPlanVo.java

@@ -0,0 +1,66 @@
+package com.xjrsoft.module.student.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+* @title: 学生报到计划表单出参
+* @Author dzx
+* @Date: 2025-01-21
+* @Version 1.0
+*/
+@Data
+public class StudentReportPlanVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 学期id(base_semester)
+    */
+    @ApiModelProperty("学期id(base_semester)")
+    private Long semesterId;
+    /**
+    * 计划名称
+    */
+    @ApiModelProperty("计划名称")
+    private String name;
+    /**
+    * 报到开始时间
+    */
+    @ApiModelProperty("报到开始时间")
+    private Date startTime;
+    /**
+    * 报到结束时间
+    */
+    @ApiModelProperty("报到结束时间")
+    private Date endTime;
+    /**
+    * 数据修改开始时间
+    */
+    @ApiModelProperty("数据修改开始时间")
+    private Date updateStartTime;
+    /**
+    * 数据修改结束时间
+    */
+    @ApiModelProperty("数据修改结束时间")
+    private Date updateEndTime;
+    /**
+    * 状态(0:草稿 1:进行中 2:已结束)
+    */
+    @ApiModelProperty("状态(0:草稿 1:进行中 2:已结束)")
+    private Integer status;
+
+
+    /**
+    * studentReportPlanClassRelation
+    */
+    @ApiModelProperty("studentReportPlanClassRelation子表")
+    private List<StudentReportPlanClassRelationVo> studentReportPlanClassRelationList;
+
+}

+ 77 - 0
src/main/java/com/xjrsoft/module/student/vo/StudentReportRecordPlanPageVo.java

@@ -0,0 +1,77 @@
+package com.xjrsoft.module.student.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+* @title: 学生报到记录表分页列表出参
+* @Author dzx
+* @Date: 2024-08-28
+* @Version 1.0
+*/
+@Data
+public class StudentReportRecordPlanPageVo {
+
+    @ExcelIgnore
+    @ApiModelProperty("学生id")
+    private Long userId;
+
+    @ExcelIgnore
+    @ApiModelProperty("主键id")
+    private Long id;
+
+    @ExcelProperty("年级")
+    @ApiModelProperty("年级")
+    private String gradeName;
+
+
+    @ExcelProperty("班级")
+    @ApiModelProperty("班级")
+    private String className;
+
+    @ExcelProperty("班主任")
+    @ApiModelProperty("班主任")
+    private String teacherName;
+
+    @ExcelProperty("学生姓名")
+    @ApiModelProperty("学生姓名")
+    private String name;
+
+    @ExcelProperty("性别")
+    @ApiModelProperty("性别")
+    private String gender;
+
+    @ExcelProperty("身份证号")
+    @ApiModelProperty("身份证号")
+    private String credentialNumber;
+
+    @ExcelProperty("手机号")
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    @ExcelProperty("学生来源")
+    @ApiModelProperty("学生来源")
+    private String studentTypeCn;
+
+    @ExcelProperty("就读方式")
+    @ApiModelProperty("就读方式")
+    private String stduyStatusCn;
+
+    @ExcelProperty("学籍状态")
+    @ApiModelProperty("学籍状态")
+    private String archivesStatusCn;
+
+    @ExcelIgnore
+    @ApiModelProperty("是否已报到(1:是 0:否)")
+    private Integer isReport;
+
+    @ExcelProperty("报到时间")
+    @ApiModelProperty("报到时间")
+    private Date reportTime;
+
+}

+ 0 - 1
src/main/java/com/xjrsoft/module/textbook/controller/SubjectGroupCourseController.java

@@ -77,7 +77,6 @@ public class SubjectGroupCourseController {
         return RT.ok(BeanUtil.toBean(subjectGroupCourse, SubjectGroupCourseVo.class));
     }
 
-
     @PostMapping
     @ApiOperation(value = "新增学科组课程管理")
     @SaCheckPermission("subjectgroupcourse:add")

+ 35 - 29
src/main/java/com/xjrsoft/module/textbook/controller/TextbookSubscriptionController.java

@@ -11,14 +11,9 @@ import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
-import com.xjrsoft.module.base.entity.BaseClass;
-import com.xjrsoft.module.base.entity.BaseGrade;
-import com.xjrsoft.module.base.service.IBaseClassService;
-import com.xjrsoft.module.student.entity.BaseClassMajorSet;
-import com.xjrsoft.module.teacher.entity.XjrUser;
 import com.xjrsoft.module.textbook.dto.*;
 import com.xjrsoft.module.textbook.entity.TextbookSubscription;
-import com.xjrsoft.module.textbook.entity.TextbookSubscriptionClass;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItem;
 import com.xjrsoft.module.textbook.service.ITextbookSubscriptionService;
 import com.xjrsoft.module.textbook.vo.*;
 import io.swagger.annotations.Api;
@@ -49,8 +44,6 @@ public class TextbookSubscriptionController {
 
     private final ITextbookSubscriptionService textbookSubscriptionService;
 
-    private final IBaseClassService baseClassService;
-
     @GetMapping(value = "/page")
     @ApiOperation(value="教材教辅征订记录列表(分页)")
     @SaCheckPermission("textbooksubscription:detail")
@@ -69,12 +62,29 @@ public class TextbookSubscriptionController {
         queryWrapper
                     .orderByDesc(TextbookSubscription::getId)
                     .select(TextbookSubscription.class,x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionListVo.class).contains(x.getProperty()));
-
         List<TextbookSubscription> list = textbookSubscriptionService.list(queryWrapper);
         List<TextbookSubscriptionListVo> listVos = BeanUtil.copyToList(list, TextbookSubscriptionListVo.class);
         return RT.ok(listVos);
     }
 
+    @GetMapping(value = "/history-list")
+    @ApiOperation(value="教材教辅征订历史列表(不分页)")
+    @SaCheckPermission("wftextbooksubscription:detail")
+    public RT<List<TextbookSubscriptionHistoryListVo>> historyList(@Valid TextbookSubscriptionHistoryListDto dto){
+        MPJLambdaWrapper<TextbookSubscription> queryWrapper = new MPJLambdaWrapper<>();
+        queryWrapper
+                .selectAs(TextbookSubscriptionItem::getStudentNum, TextbookSubscriptionHistoryListVo::getStudentSubscriptionNumber)
+                .selectAs(TextbookSubscriptionItem::getTeacherNum, TextbookSubscriptionHistoryListVo::getTeacherSubscriptionNumber)
+                .selectAs(TextbookSubscription::getCreateDate, TextbookSubscriptionHistoryListVo::getCreateDate)
+                .rightJoin(TextbookSubscriptionItem.class, TextbookSubscriptionItem::getTextbookSubscriptionId, TextbookSubscription::getId)
+                .eq(TextbookSubscriptionItem::getTextbookId, dto.getTextbookId())
+                .eq(TextbookSubscription::getBaseSemesterId, dto.getBaseSemesterId())
+                .ne(TextbookSubscription::getStatus, 0)
+        ;
+        List<TextbookSubscriptionHistoryListVo> list = textbookSubscriptionService.selectJoinList(TextbookSubscriptionHistoryListVo.class, queryWrapper);
+        return RT.ok(list);
+    }
+
     @GetMapping(value = "/instockroom-list")
     @ApiOperation(value = "教材教辅征订入库用页面")
     @SaCheckPermission("textbooksubscription:detail")
@@ -95,20 +105,9 @@ public class TextbookSubscriptionController {
     @ApiOperation(value="征订班级列表(分页)")
     @SaCheckPermission("textbooksubscription:detail")
     public RT<PageOutput<BaseclassPageVo>> baseclassPage(@Valid BaseclassPageDto dto){
-        MPJLambdaWrapper<BaseClass> baseClassMPJLambdaWrapper = new MPJLambdaWrapper<>();
-        baseClassMPJLambdaWrapper
-                .selectAs(BaseGrade::getName, BaseclassPageVo::getGradeIdCn)
-                .selectAs(XjrUser::getName, BaseclassPageVo::getTeacherIdCn)
-                .selectAs(BaseClassMajorSet::getTotalStudent, BaseclassPageVo::getTotalStudent)
-                .select(BaseClass.class,x -> VoToColumnUtil.fieldsToColumns(BaseclassPageVo.class).contains(x.getProperty()))
-                .innerJoin(TextbookSubscriptionClass.class, TextbookSubscriptionClass::getBaseClassId, BaseClass::getId)
-                .leftJoin(BaseGrade.class, BaseGrade::getId, BaseClass::getGradeId)
-                .leftJoin(XjrUser.class, XjrUser::getId, BaseClass::getTeacherId)
-                .leftJoin(BaseClassMajorSet.class, BaseClassMajorSet::getClassId, BaseClass::getId)
-                .eq(TextbookSubscriptionClass::getTextbookSubscriptionId, dto.getId())
-        ;
-        IPage<BaseclassPageVo> baseclassPageVos = baseClassService.selectJoinListPage(ConventPage.getPage(dto), BaseclassPageVo.class, baseClassMPJLambdaWrapper);
-        PageOutput<BaseclassPageVo> pageOutput = ConventPage.getPageOutput(baseclassPageVos, BaseclassPageVo.class);
+
+        IPage<BaseclassPageVo> page = textbookSubscriptionService.baseclassPage(dto);
+        PageOutput<BaseclassPageVo> pageOutput = ConventPage.getPageOutput(page, BaseclassPageVo.class);
         return RT.ok(pageOutput);
     }
 
@@ -157,7 +156,7 @@ public class TextbookSubscriptionController {
     public RT<Boolean> add(@Valid @RequestBody AddTextbookSubscriptionDto dto){
         TextbookSubscription textbookSubscription = BeanUtil.toBean(dto, TextbookSubscription.class);
         boolean isSuccess = textbookSubscriptionService.add(textbookSubscription);
-    return RT.ok(isSuccess);
+        return RT.ok(isSuccess);
     }
 
     @PutMapping
@@ -170,6 +169,13 @@ public class TextbookSubscriptionController {
 
     }
 
+    @PutMapping("/alteration")
+    @ApiOperation(value = "变更")
+    @SaCheckPermission("wftextbooksubscription:edit")
+    public RT<Boolean> alteration(@Valid @RequestBody UpdateTextbookSubscriptionItemDto dto){
+        return RT.ok(textbookSubscriptionService.alteration(dto));
+    }
+
     @PutMapping(value = "/change-status")
     @ApiOperation(value = "修改征订状态")
     @SaCheckPermission("textbooksubscription:edit")
@@ -216,12 +222,12 @@ public class TextbookSubscriptionController {
         return RT.fileStream(bot.toByteArray(), "TextbookSubscription" + ExcelTypeEnum.XLSX.getValue());
     }
 
-//    @PostMapping("/textbook-subscription-export-query")
-//    @ApiOperation(value = "教材征订条件导出")
-//    public ResponseEntity<byte[]> textbookSubscriptionExportQuery(@Valid @RequestBody TextbookSubscriptionExportQueryListDto dto) {
-    @GetMapping("/textbook-subscription-export-query")
+    @PostMapping("/textbook-subscription-export-query")
     @ApiOperation(value = "教材征订条件导出")
-    public ResponseEntity<byte[]> textbookSubscriptionExportQuery(@Valid TextbookSubscriptionExportQueryListDto dto) {
+    public ResponseEntity<byte[]> textbookSubscriptionExportQuery(@Valid @RequestBody TextbookSubscriptionExportQueryListDto dto) {
+//    @GetMapping("/textbook-subscription-export-query")
+//    @ApiOperation(value = "教材征订条件导出")
+//    public ResponseEntity<byte[]> textbookSubscriptionExportQuery(@Valid TextbookSubscriptionExportQueryListDto dto) {
         List<TextbookSubscriptionExportQueryListVo> customerList = textbookSubscriptionService.textbookSubscriptionExportQuery(dto);
         ByteArrayOutputStream bot = new ByteArrayOutputStream();
         EasyExcel.write(bot, TextbookSubscriptionExportQueryListVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(customerList);

+ 112 - 0
src/main/java/com/xjrsoft/module/textbook/controller/TextbookSubscriptionItemHistoryController.java

@@ -0,0 +1,112 @@
+package com.xjrsoft.module.textbook.controller;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.base.entity.BaseCourseSubject;
+import com.xjrsoft.module.system.entity.DictionaryDetail;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+import com.xjrsoft.module.textbook.dto.AddTextbookSubscriptionItemHistoryDto;
+import com.xjrsoft.module.textbook.dto.UpdateTextbookSubscriptionItemHistoryDto;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.alibaba.excel.EasyExcel;
+import com.xjrsoft.module.textbook.entity.Textbook;
+import org.springframework.web.multipart.MultipartFile;
+import java.io.IOException;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import org.springframework.http.ResponseEntity;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+
+import com.xjrsoft.module.textbook.dto.TextbookSubscriptionItemHistoryPageDto;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItemHistory;
+import com.xjrsoft.module.textbook.service.ITextbookSubscriptionItemHistoryService;
+import com.xjrsoft.module.textbook.vo.TextbookSubscriptionItemHistoryPageVo;
+
+import com.xjrsoft.module.textbook.vo.TextbookSubscriptionItemHistoryVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/textbook" + "/textbookSubscriptionItemHistory")
+@Api(value = "/textbook"  + "/textbookSubscriptionItemHistory",tags = "教材教辅征订项变更历史代码")
+@AllArgsConstructor
+public class TextbookSubscriptionItemHistoryController {
+
+
+    private final ITextbookSubscriptionItemHistoryService textbookSubscriptionItemHistoryService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="教材教辅征订项变更历史列表(分页)")
+    @SaCheckPermission("textbooksubscriptionitemhistory:detail")
+    public RT<PageOutput<TextbookSubscriptionItemHistoryPageVo>> page(@Valid TextbookSubscriptionItemHistoryPageDto dto){
+        MPJLambdaWrapper<TextbookSubscriptionItemHistory> mpjLambdaWrapper = new MPJLambdaWrapper<>();
+        mpjLambdaWrapper
+                .disableSubLogicDel()
+                .select(TextbookSubscriptionItemHistory::getId)
+
+                .select(TextbookSubscriptionItemHistory.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionItemHistoryPageVo.class).contains(x.getProperty()))
+
+                .leftJoin(Textbook.class, Textbook::getId, TextbookSubscriptionItemHistory::getOldTextbookId,
+                        wrapper -> wrapper
+                                .selectAs(Textbook::getIssn, TextbookSubscriptionItemHistoryPageVo::getOldIssn)
+                                .selectAs(Textbook::getBookName, TextbookSubscriptionItemHistoryPageVo::getOldBookName)
+                                .selectAs(Textbook::getPublishingHouse, TextbookSubscriptionItemHistoryPageVo::getOldPublishingHouse)
+                                .selectAs(Textbook::getEditorInChief, TextbookSubscriptionItemHistoryPageVo::getOldEditorInChief)
+                                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
+                                        ext -> ext.selectAs(DictionaryDetail::getName, TextbookSubscriptionItemHistoryPageVo::getOldTextbookTypeCn))
+                                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, Textbook::getCourseSubjectId,
+                                ext -> ext.selectAs(BaseCourseSubject::getName, TextbookSubscriptionItemHistoryPageVo::getOldCourseName))
+                )
+
+                .leftJoin(Textbook.class, Textbook::getId, TextbookSubscriptionItemHistory::getNewTextbookId,
+                        wrapper -> wrapper
+                                .selectAs(Textbook::getIssn, TextbookSubscriptionItemHistoryPageVo::getNewIssn)
+                                .selectAs(Textbook::getBookName, TextbookSubscriptionItemHistoryPageVo::getNewBookName)
+                                .selectAs(Textbook::getPublishingHouse, TextbookSubscriptionItemHistoryPageVo::getNewPublishingHouse)
+                                .selectAs(Textbook::getEditorInChief, TextbookSubscriptionItemHistoryPageVo::getNewEditorInChief)
+                                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
+                                        ext -> ext.selectAs(DictionaryDetail::getName, TextbookSubscriptionItemHistoryPageVo::getNewTextbookTypeCn))
+                                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, Textbook::getCourseSubjectId,
+                                        ext -> ext.selectAs(BaseCourseSubject::getName, TextbookSubscriptionItemHistoryPageVo::getNewCourseName))
+                )
+
+
+                .leftJoin(XjrUser.class, XjrUser::getId, TextbookSubscriptionItemHistory::getCreateUserId,
+                        wrapper -> wrapper
+                                .selectAs(XjrUser::getName, TextbookSubscriptionItemHistoryPageVo::getCreateUserIdCn)
+                )
+                .eq(dto.getTextbookSubscriptionItemId() != null && dto.getTextbookSubscriptionItemId() > 0, TextbookSubscriptionItemHistory::getTextbookSubscriptionItemId, dto.getTextbookSubscriptionItemId())
+                .eq(dto.getTextbookSubscriptionId() != null && dto.getTextbookSubscriptionId() > 0, TextbookSubscriptionItemHistory::getTextbookSubscriptionId, dto.getTextbookSubscriptionId())
+                .eq(dto.getTextbookType() != null && !dto.getTextbookType().isEmpty(), Textbook::getTextbookType, dto.getTextbookType())
+                .like(dto.getBookName() != null && !dto.getBookName().isEmpty(), Textbook::getBookName, dto.getBookName())
+                .like(dto.getCourseSubjectIdCn() != null && !dto.getCourseSubjectIdCn().isEmpty(), BaseCourseSubject::getName, dto.getCourseSubjectIdCn())
+                .orderByAsc("t.textbook_subscription_item_id, t.history_version")
+        ;
+        IPage<TextbookSubscriptionItemHistoryPageVo> page = textbookSubscriptionItemHistoryService.selectJoinListPage(ConventPage.getPage(dto), TextbookSubscriptionItemHistoryPageVo.class, mpjLambdaWrapper);
+        PageOutput<TextbookSubscriptionItemHistoryPageVo> pageOutput = ConventPage.getPageOutput(page, TextbookSubscriptionItemHistoryPageVo.class);
+        return RT.ok(pageOutput);
+    }
+}

+ 5 - 1
src/main/java/com/xjrsoft/module/textbook/dto/AddTextbookSubscriptionItemDto.java

@@ -74,5 +74,9 @@ public class AddTextbookSubscriptionItemDto implements Serializable {
     */
     @ApiModelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,)")
     private Integer alterationType;
-
+    /**
+     * 按班级征订征订的班级主键(base_class)
+     */
+    @ApiModelProperty("按班级征订征订的班级主键(base_class)")
+    private String classIds;
 }

+ 123 - 0
src/main/java/com/xjrsoft/module/textbook/dto/AddTextbookSubscriptionItemHistoryDto.java

@@ -0,0 +1,123 @@
+package com.xjrsoft.module.textbook.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+public class AddTextbookSubscriptionItemHistoryDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 教材教辅征订编号
+    */
+    @ApiModelProperty("教材教辅征订编号")
+    private Long textbookSubscriptionId;
+    /**
+    * 教材教辅征订项编号
+    */
+    @ApiModelProperty("教材教辅征订项编号")
+    private Long textbookSubscriptionItemId;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long oldTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer oldStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer oldTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double oldDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal oldPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer oldInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer oldOutStockNum;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long newTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer newStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer newTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double newDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal newPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer newInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer newOutStockNum;
+    /**
+    * 当前征订项变更历史记录版本
+    */
+    @ApiModelProperty("当前征订项变更历史记录版本")
+    private Integer historyVersion;
+    /**
+    * 变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)
+    */
+    @ApiModelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)")
+    private Integer alterationType;
+
+}

+ 14 - 3
src/main/java/com/xjrsoft/module/textbook/dto/BaseclassPageDto.java

@@ -6,6 +6,9 @@ import com.xjrsoft.common.page.PageInput;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
 
 /**
 * @title: 教材管理分页查询入参
@@ -16,11 +19,19 @@ import lombok.Data;
 @Data
 public class BaseclassPageDto extends PageInput {
     /**
-     * 主键编号
+     * 教材征订记录主键编号
      */
     @ContentStyle(dataFormat = 49)
-    @ExcelProperty("主键编号")
-    @ApiModelProperty("主键编号")
+    @ExcelProperty("教材征订记录主键编号")
+    @ApiModelProperty("教材征订记录主键编号")
+    @NotBlank(message = "征订记录主键为必要字段")
     private String id;
+    /**
+     * 教材征订项主键编号
+     */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材征订项主键编号")
+    @ApiModelProperty("教材征订项主键编号")
+    private String textbookSubscriptionItemId;
 
 }

+ 10 - 4
src/main/java/com/xjrsoft/module/textbook/dto/TextbookInstockroomDto.java

@@ -24,11 +24,17 @@ public class TextbookInstockroomDto {
      */
     @ApiModelProperty("教材教辅征订项编号")
     private Long textbookSubscriptionItemId;
+
     /**
-     * 国际标准刊
+     * 教材编
      */
-    @ApiModelProperty(value = "国际标准刊号",hidden = true)
-    private String issn;
+    @ApiModelProperty("教材编号")
+    private String textbookId;
+    /**
+     * 定价(元)
+     */
+    @ApiModelProperty("定价(元)")
+    private BigDecimal price;
     /**
      * 实际折扣
      */
@@ -38,7 +44,7 @@ public class TextbookInstockroomDto {
      * 实际价格(元)
      */
     @ApiModelProperty("实际价格(元)")
-    private BigDecimal price;
+    private BigDecimal subtotal;
     /**
      * 本次入库数量
      */

+ 49 - 0
src/main/java/com/xjrsoft/module/textbook/dto/TextbookSubscriptionItemHistoryPageDto.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.textbook.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+* @title: 教材教辅征订项变更历史分页查询入参
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TextbookSubscriptionItemHistoryPageDto extends PageInput {
+    /**
+     * 教材教辅征订编号
+     */
+    @ApiModelProperty("教材教辅征订编号")
+    private Long textbookSubscriptionId;
+    /**
+     * 教材教辅征订项编号
+     */
+    @ApiModelProperty("教材教辅征订项编号")
+    private Long textbookSubscriptionItemId;
+    /**
+     * 教材分类(xjr_dictionary_item[textbook_type])
+     */
+    @ApiModelProperty("教材分类(xjr_dictionary_item[textbook_type])")
+    private String textbookType;
+    /**
+     * 书名
+     */
+    @ApiModelProperty("书名")
+    private String bookName;
+
+    @ApiModelProperty("课程名称")
+    private String courseSubjectIdCn;
+}

+ 3 - 3
src/main/java/com/xjrsoft/module/textbook/dto/TextbookSubscriptionListDto.java

@@ -17,7 +17,7 @@ import java.util.List;
 * @Version 1.0
 */
 @Data
-public class TextbookSubscriptionListDto extends PageInput {
+public class TextbookSubscriptionListDto{
     /**
      * 使用班级
      */
@@ -29,6 +29,6 @@ public class TextbookSubscriptionListDto extends PageInput {
     @ApiModelProperty("学期id")
     public Long baseSemesterId;
 
-    @ApiModelProperty(value = "班级ids", hidden = true)
-    public List<String> classIdList;
+    @ApiModelProperty("学期id")
+    public Long textbookSubscriptionId;
 }

+ 61 - 0
src/main/java/com/xjrsoft/module/textbook/dto/UpdateTextbookSubscriptionItemDto.java

@@ -0,0 +1,61 @@
+package com.xjrsoft.module.textbook.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+
+/**
+* @title: 教材征订记录详情表
+* @Author dzx
+* @Date: 2024-12-16
+* @Version 1.0
+*/
+@Data
+public class UpdateTextbookSubscriptionItemDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long textbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer studentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer teacherNum;
+    /**
+     * 实际折扣
+     */
+    @ApiModelProperty("实际折扣")
+    private Double discount;
+    /**
+     * 实际价格(元)
+     */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal price;
+    /**
+     * 当前征订任务征订项入库数量
+     */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer inStockNum;
+    /**
+     * 当前征订任务征订项出库数量
+     */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer outStockNum;
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/textbook/dto/UpdateTextbookSubscriptionItemHistoryDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.textbook.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.util.List;
+import java.util.Date;
+
+
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+public class UpdateTextbookSubscriptionItemHistoryDto extends AddTextbookSubscriptionItemHistoryDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+}

+ 10 - 1
src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItem.java

@@ -98,6 +98,11 @@ public class TextbookSubscriptionItem implements Serializable {
     */
     @ApiModelProperty("教师用书征订数量")
     private Integer teacherNum;
+    /**
+     * 在本次征订中本征订项的教材使用的班级数量
+     */
+    @ApiModelProperty("在本次征订中本征订项的教材使用的班级数量")
+    private Integer useClassNum;
     /**
     * 实际折扣
     */
@@ -123,6 +128,10 @@ public class TextbookSubscriptionItem implements Serializable {
     */
     @ApiModelProperty("变更类型(0:未变更,1:变更征订数量,2:变更课程)")
     private Integer alterationType;
-
+    /**
+     * 按班级征订征订的班级主键(base_class)
+     */
+    @ApiModelProperty("按班级征订征订的班级主键(base_class)")
+    private String classIds;
 
 }

+ 98 - 0
src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItemClass.java

@@ -0,0 +1,98 @@
+package com.xjrsoft.module.textbook.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.github.yulichang.annotation.EntityMapping;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+/**
+* @title: 教材征订记录详情与班级关联表
+* @Author phoenix
+* @Date: 2025-01-22
+* @Version 1.0
+*/
+@Data
+@TableName("textbook_subscription_item_class")
+@ApiModel(value = "textbook_subscription_item_class", description = "教材征订记录详情与班级关联表")
+public class TextbookSubscriptionItemClass implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人
+    */
+    @ApiModelProperty("修改人")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改时间
+    */
+    @ApiModelProperty("修改时间")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+    /**
+    * 有效标志
+    */
+    @ApiModelProperty("有效标志")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer enabledMark;
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 备注
+    */
+    @ApiModelProperty("备注")
+    private String remark;
+    /**
+    * 教材征订记录详情表id(textbook_subscription)
+    */
+    @ApiModelProperty("教材征订记录详情表id(textbook_subscription)")
+    private Long textbookSubscriptionItemId;
+    /**
+    * 按班级征订中征订的班级主键(base_class)
+    */
+    @ApiModelProperty("按班级征订中征订的班级主键(base_class)")
+    private Long baseClassId;
+
+
+}

+ 173 - 0
src/main/java/com/xjrsoft/module/textbook/entity/TextbookSubscriptionItemHistory.java

@@ -0,0 +1,173 @@
+package com.xjrsoft.module.textbook.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.github.yulichang.annotation.EntityMapping;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+@TableName("textbook_subscription_item_history")
+@ApiModel(value = "textbook_subscription_item_history", description = "教材教辅征订项变更历史")
+public class TextbookSubscriptionItemHistory implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人
+    */
+    @ApiModelProperty("修改人")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改时间
+    */
+    @ApiModelProperty("修改时间")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+    /**
+    * 有效标志
+    */
+    @ApiModelProperty("有效标志")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer enabledMark;
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 教材教辅征订编号
+    */
+    @ApiModelProperty("教材教辅征订编号")
+    private Long textbookSubscriptionId;
+    /**
+    * 教材教辅征订项编号
+    */
+    @ApiModelProperty("教材教辅征订项编号")
+    private Long textbookSubscriptionItemId;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long oldTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer oldStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer oldTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double oldDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal oldPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer oldInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer oldOutStockNum;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long newTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer newStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer newTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double newDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal newPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer newInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer newOutStockNum;
+    /**
+    * 当前征订项变更历史记录版本
+    */
+    @ApiModelProperty("当前征订项变更历史记录版本")
+    private Integer historyVersion;
+    /**
+    * 变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)
+    */
+    @ApiModelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)")
+    private Integer alterationType;
+
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/textbook/mapper/TextbookSubscriptionItemClassMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.textbook.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItemClass;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 教材征订记录详情与班级关联表
+* @Author phoenix
+* @Date: 2025-01-22
+* @Version 1.0
+*/
+@Mapper
+public interface TextbookSubscriptionItemClassMapper extends MPJBaseMapper<TextbookSubscriptionItemClass> {
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/textbook/mapper/TextbookSubscriptionItemHistoryMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.textbook.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItemHistory;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Mapper
+public interface TextbookSubscriptionItemHistoryMapper extends MPJBaseMapper<TextbookSubscriptionItemHistory> {
+
+}

+ 1 - 1
src/main/java/com/xjrsoft/module/textbook/service/ITextbookService.java

@@ -128,7 +128,7 @@ public interface ITextbookService extends MPJBaseService<Textbook> {
 
 //    Boolean excelImport(InputStream inputStream);
 
-    IPage<TextbookSubscriptionListVo> getSubscriptionPageByClass(TextbookSubscriptionListDto dto);
+//    IPage<TextbookSubscriptionListVo> getSubscriptionPageByClass(TextbookSubscriptionListDto dto);
 
     List<TextbookSubscriptionListVo> getSubscriptionListByClass(TextbookSubscriptionListDto dto);
 

+ 17 - 0
src/main/java/com/xjrsoft/module/textbook/service/ITextbookSubscriptionItemHistoryService.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.textbook.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItemHistory;
+import lombok.Data;
+import java.util.List;
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+
+public interface ITextbookSubscriptionItemHistoryService extends MPJBaseService<TextbookSubscriptionItemHistory> {
+}

+ 8 - 0
src/main/java/com/xjrsoft/module/textbook/service/ITextbookSubscriptionService.java

@@ -40,6 +40,8 @@ public interface ITextbookSubscriptionService extends MPJBaseService<TextbookSub
 
     IPage<TextbookSubscriptionItemPageVo> itemPage(TextbookSubscriptionItemPageDto dto);
 
+    IPage<BaseclassPageVo> baseclassPage(BaseclassPageDto dto);
+
     List<SubscriptionItemListDistributeVo> itemListConfirmDistribute(SubscriptionItemListDistributeDto dto);
 
     /**
@@ -67,6 +69,12 @@ public interface ITextbookSubscriptionService extends MPJBaseService<TextbookSub
     */
     Boolean update(TextbookSubscription textbookSubscription);
 
+    /**
+     * 变更
+     */
+    Boolean alteration(UpdateTextbookSubscriptionItemDto dto);
+
+
     Boolean changeStatus(UpdateWfTextbookSubscriptionDto dto);
 
     /**

+ 193 - 118
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookServiceImpl.java

@@ -1,6 +1,5 @@
 package com.xjrsoft.module.textbook.service.impl;
 
-import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.ExcelWriter;
@@ -14,7 +13,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.enums.*;
@@ -23,10 +21,7 @@ import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.common.utils.excel.ExcelFillCellMergePrevColUtil;
 import com.xjrsoft.common.utils.excel.ExcelMergeUtil;
-import com.xjrsoft.module.base.entity.BaseClass;
-import com.xjrsoft.module.base.entity.BaseClassCourse;
-import com.xjrsoft.module.base.entity.BaseCourseSubject;
-import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.base.entity.*;
 import com.xjrsoft.module.base.mapper.BaseClassCourseMapper;
 import com.xjrsoft.module.base.mapper.BaseCourseSubjectMapper;
 import com.xjrsoft.module.base.mapper.BaseSemesterMapper;
@@ -40,7 +35,6 @@ import com.xjrsoft.module.textbook.dto.*;
 import com.xjrsoft.module.textbook.entity.*;
 import com.xjrsoft.module.textbook.mapper.*;
 import com.xjrsoft.module.textbook.service.ITextbookService;
-import com.xjrsoft.module.textbook.service.ITextbookWarehouseRecordService;
 import com.xjrsoft.module.textbook.service.IWfExerciseBookService;
 import com.xjrsoft.module.textbook.vo.*;
 import com.xjrsoft.module.veb.util.ImportExcelUtil;
@@ -63,7 +57,6 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 import static com.xjrsoft.module.veb.util.ImportExcelUtil.*;
-import static com.xjrsoft.module.veb.util.ImportExcelUtil.validateAndSetString2LongField;
 
 /**
  * @title: 教材管理
@@ -84,8 +77,6 @@ public class TextbookServiceImpl extends MPJBaseServiceImpl<TextbookMapper, Text
 
     private final IBaseClassService baseClassService;
 
-    private final ITextbookWarehouseRecordService textbookClassWarehouseService;
-
     private final TextbookIssueRecordMapper textbookIssueRecordMapper;
 
     private final TextbookStudentClaimMapper textbookStudentClaimMapper;
@@ -288,7 +279,6 @@ public class TextbookServiceImpl extends MPJBaseServiceImpl<TextbookMapper, Text
         return textbookTextbookMapper.selectJoinList(TextbookListVo.class, textbookMPJLambdaWrapper);
     }
 
-
    /* @Override
     @Transactional
     public Boolean dataHandleAddTextbookNode(Long dataId) {
@@ -959,116 +949,138 @@ public class TextbookServiceImpl extends MPJBaseServiceImpl<TextbookMapper, Text
 //        })).sheet().headRowNumber(3).doRead();
 //
 //        return true;
+//    }
+
+//    @Override
+//    public IPage<TextbookSubscriptionListVo> getSubscriptionPageByClass(TextbookSubscriptionListDto dto) {
+//        if(StringUtils.isBlank(dto.getClassIds())){
+//            throw new MyException("请选择需要征订教材的班级");
+//        }
+//        String[] classIdArr =  dto.getClassIds().split(",");
+//        List<String> classIdList = Arrays.asList(classIdArr);
+//        if(ObjectUtils.isEmpty(classIdList)){
+//            throw new MyException("请选择需要征订教材的班级");
+//        }
+//
+//        // 找到可以使用多个学期且已经征订的教材
+//        // 找到可以使用多个学期且已经征订的教材
+//        MPJLambdaWrapper<TextbookSubscriptionItem> subscribedTextbook = new MPJLambdaWrapper<>();
+//        subscribedTextbook
+//                .distinct()
+//                .select(BaseClassCourse::getId)
+//                .innerJoin(TextbookSubscriptionItemClass.class,
+//                        wrapper -> wrapper
+//                                .eq(TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, TextbookSubscriptionItem::getId)
+//                                .in(TextbookSubscriptionItemClass::getBaseClassId, classIdList)
+//                )
+//
+//                .innerJoin(BaseClassAdminCourse.class, BaseClassAdminCourse::getClassId, TextbookSubscriptionItemClass::getBaseClassId)
+//                .innerJoin(BaseClassCourse.class,
+//                        wrapper -> wrapper
+//                                .eq(BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+//                                .eq(BaseClassCourse::getTextbookId, TextbookSubscriptionItem::getTextbookId)
+//                )
+//
+//                .innerJoin(Textbook.class, Textbook::getId, TextbookSubscriptionItem::getTextbookId)
+//                .gt(Textbook::getUseType, 1)
+//        ;
+//        List<BaseClassCourse> baseClassCourses = textbookSubscriptionItemMapper.selectJoinList(BaseClassCourse.class, subscribedTextbook);
+//
+//        List<Long> baseClassCourseIds = baseClassCourses.stream()
+//                .map(BaseClassCourse::getId)
+//                .collect(Collectors.toList());
+//
+//        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
+//        baseClassCourseMPJLambdaWrapper
+//                .disableSubLogicDel()
+//                .distinct()
+//                .selectAs(BaseClassCourse::getCourseId, TextbookSubscriptionListVo::getCourseSubjectId)
+//                .selectAs(BaseClassCourse::getTextbookId, TextbookSubscriptionListVo::getTextbookId)
+//                .selectAs(BaseCourseSubject::getName, TextbookSubscriptionListVo::getCourseName)
+//                .select(Textbook.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionListVo.class).contains(x.getProperty()))
+//                .innerJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
+//                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
+//                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
+//                wrapper -> wrapper
+//                        .selectAs(DictionaryDetail::getName, TextbookSubscriptionListVo::getTextbookTypeCn)
+//                )
+//                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
+//                .in(BaseClassCourse::getClassId, classIdList)
+//                .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
+//                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+//                .eq(Textbook::getDeleteMark, DeleteMark.NODELETE.getCode())
+//                ;
+//        IPage<TextbookSubscriptionListVo> textbookSubscriptionListVoIPage = baseClassCourseMapper.selectJoinPage(ConventPage.getPage(dto), TextbookSubscriptionListVo.class, baseClassCourseMPJLambdaWrapper);
+////        IPage<TextbookSubscriptionListVo> page = this.baseMapper.getSubscriptionPageByClass(new Page<>(dto.getLimit(), dto.getSize()), dto);
+//
+//        // 处理每本教材使用的人数
+//        if(!classIdList.isEmpty()) {
+//            for(TextbookSubscriptionListVo t : textbookSubscriptionListVoIPage.getRecords()){
+//                MPJLambdaWrapper<BaseClassCourse> countNum = new MPJLambdaWrapper<>();
+//                countNum
+//                        .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getClassId, BaseClassCourse::getClassId)
+//                        .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+//                        .eq(BaseClassCourse::getTextbookId, t.getTextbookId())
+//                        .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
+//                        .in(BaseClassCourse::getClassId, classIdList)
+//                        .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
+//                        .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+//                ;
+//                Long num = baseClassCourseMapper.selectCount(countNum);
+//                t.setStudentSubscriptionNumber(num.intValue());
+//
+//                t.setClassIds(dto.getClassIds());
+//            }
+//        }
+//
+//        return textbookSubscriptionListVoIPage;
 //    }
 
     @Override
-    public IPage<TextbookSubscriptionListVo> getSubscriptionPageByClass(TextbookSubscriptionListDto dto) {
-        List<String> classIdList = new ArrayList<>();
-        if(dto.getClassIds() != null && !"".equals(dto.getClassIds())){
-            String[] classIdArr =  dto.getClassIds().split(",");
-            classIdList = Arrays.asList(classIdArr);
+    public List<TextbookSubscriptionListVo> getSubscriptionListByClass(TextbookSubscriptionListDto dto) {
+        if(StringUtils.isBlank(dto.getClassIds())){
+            throw new MyException("请选择需要征订教材的班级");
+        }
+        String[] classIdArr =  dto.getClassIds().split(",");
+        List<String> classIdList = Arrays.asList(classIdArr);
+        if(ObjectUtils.isEmpty(classIdList)){
+            throw new MyException("请选择需要征订教材的班级");
         }
-        dto.setClassIdList(classIdList);
 
         // 找到可以使用多个学期且已经征订的教材
-        MPJLambdaWrapper<BaseClassCourse> subscribedTextbook = new MPJLambdaWrapper<>();
+        MPJLambdaWrapper<TextbookSubscriptionItem> subscribedTextbook = new MPJLambdaWrapper<>();
         subscribedTextbook
                 .distinct()
                 .select(BaseClassCourse::getId)
-                .innerJoin(TextbookSubscriptionClass.class, TextbookSubscriptionClass::getBaseClassId, BaseClassCourse::getClassId)
-                .innerJoin(TextbookSubscriptionItem.class, wrapper -> wrapper
-                        .eq(TextbookSubscriptionItem::getTextbookSubscriptionId, TextbookSubscriptionClass::getTextbookSubscriptionId)
-                        .eq(TextbookSubscriptionItem::getTextbookId, BaseClassCourse::getTextbookId)
+                .innerJoin(TextbookSubscription.class, TextbookSubscription::getId, TextbookSubscriptionItem::getTextbookSubscriptionId,
+                        wrapper -> wrapper
+                                .ne(TextbookSubscription::getStatus, 0)
                         )
 
-                .innerJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
-                .gt(Textbook::getUseType, 1)
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .in(BaseClassCourse::getClassId, dto.getClassIdList())
-        ;
-        List<BaseClassCourse> baseClassCourses = baseClassCourseMapper.selectJoinList(BaseClassCourse.class, subscribedTextbook);
-
-        List<Long> baseClassCourseIds = baseClassCourses.stream()
-                .map(BaseClassCourse::getId)
-                .collect(Collectors.toList());
-
-        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
-        baseClassCourseMPJLambdaWrapper
-                .disableSubLogicDel()
-                .distinct()
-                .selectAs(BaseClassCourse::getCourseId, TextbookSubscriptionListVo::getCourseSubjectId)
-                .selectAs(BaseClassCourse::getTextbookId, TextbookSubscriptionListVo::getTextbookId)
-                .selectAs(BaseCourseSubject::getName, TextbookSubscriptionListVo::getCourseName)
-                .select(Textbook.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionListVo.class).contains(x.getProperty()))
-                .innerJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
-                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
-                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
-                wrapper -> wrapper
-                        .selectAs(DictionaryDetail::getName, TextbookSubscriptionListVo::getTextbookTypeCn)
+                .innerJoin(TextbookSubscriptionItemClass.class,
+                        wrapper -> wrapper
+                                .eq(TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, TextbookSubscriptionItem::getId)
+                                .in(TextbookSubscriptionItemClass::getBaseClassId, classIdList)
                 )
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .in(BaseClassCourse::getClassId, dto.getClassIdList())
-                .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
-                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-                .eq(Textbook::getDeleteMark, DeleteMark.NODELETE.getCode())
-                ;
-        IPage<TextbookSubscriptionListVo> textbookSubscriptionListVoIPage = baseClassCourseMapper.selectJoinPage(ConventPage.getPage(dto), TextbookSubscriptionListVo.class, baseClassCourseMPJLambdaWrapper);
-//        IPage<TextbookSubscriptionListVo> page = this.baseMapper.getSubscriptionPageByClass(new Page<>(dto.getLimit(), dto.getSize()), dto);
-
-        // 处理每本教材使用的人数
-        if(!classIdList.isEmpty()) {
-            for(TextbookSubscriptionListVo t : textbookSubscriptionListVoIPage.getRecords()){
-                MPJLambdaWrapper<BaseClassCourse> countNum = new MPJLambdaWrapper<>();
-                countNum
-                        .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getClassId, BaseClassCourse::getClassId)
-                        .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
-                        .eq(BaseClassCourse::getTextbookId, t.getTextbookId())
-                        .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                        .in(BaseClassCourse::getClassId, dto.getClassIdList())
-                        .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
-                        .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-                ;
-                Long num = baseClassCourseMapper.selectCount(countNum);
-                t.setStudentSubscriptionNumber(num.intValue());
-
-                t.setClassIds(dto.getClassIds());
-            }
-        }
-
-        return textbookSubscriptionListVoIPage;
-    }
 
-    @Override
-    public List<TextbookSubscriptionListVo> getSubscriptionListByClass(TextbookSubscriptionListDto dto) {
-        List<String> classIdList = new ArrayList<>();
-        if(dto.getClassIds() != null && !"".equals(dto.getClassIds())){
-            String[] classIdArr =  dto.getClassIds().split(",");
-            classIdList = Arrays.asList(classIdArr);
-        }
-        dto.setClassIdList(classIdList);
-
-        // 找到可以使用多个学期且已经征订的教材
-        MPJLambdaWrapper<BaseClassCourse> subscribedTextbook = new MPJLambdaWrapper<>();
-        subscribedTextbook
-                .distinct()
-                .select(BaseClassCourse::getId)
-                .innerJoin(TextbookSubscriptionClass.class, TextbookSubscriptionClass::getBaseClassId, BaseClassCourse::getClassId)
-                .innerJoin(TextbookSubscriptionItem.class, wrapper -> wrapper
-                        .eq(TextbookSubscriptionItem::getTextbookSubscriptionId, TextbookSubscriptionClass::getTextbookSubscriptionId)
-                        .eq(TextbookSubscriptionItem::getTextbookId, BaseClassCourse::getTextbookId)
+                .innerJoin(BaseClassAdminCourse.class, BaseClassAdminCourse::getClassId, TextbookSubscriptionItemClass::getBaseClassId)
+                .innerJoin(BaseClassCourse.class,
+                        wrapper -> wrapper
+                                .eq(BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+                                .eq(BaseClassCourse::getTextbookId, TextbookSubscriptionItem::getTextbookId)
                 )
 
-                .innerJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
+                .innerJoin(Textbook.class, Textbook::getId, TextbookSubscriptionItem::getTextbookId)
+                .ne(ObjectUtils.isNotEmpty(dto.getTextbookSubscriptionId()), TextbookSubscriptionItem::getTextbookSubscriptionId, dto.getTextbookSubscriptionId())
                 .gt(Textbook::getUseType, 1)
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .in(BaseClassCourse::getClassId, dto.getClassIdList())
         ;
-        List<BaseClassCourse> baseClassCourses = baseClassCourseMapper.selectJoinList(BaseClassCourse.class, subscribedTextbook);
+        List<BaseClassCourse> baseClassCourses = textbookSubscriptionItemMapper.selectJoinList(BaseClassCourse.class, subscribedTextbook);
 
         List<Long> baseClassCourseIds = baseClassCourses.stream()
                 .map(BaseClassCourse::getId)
                 .collect(Collectors.toList());
 
+        // 需要征订的教材
         MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
         baseClassCourseMPJLambdaWrapper
                 .disableSubLogicDel()
@@ -1077,39 +1089,102 @@ public class TextbookServiceImpl extends MPJBaseServiceImpl<TextbookMapper, Text
                 .selectAs(BaseClassCourse::getTextbookId, TextbookSubscriptionListVo::getTextbookId)
                 .selectAs(BaseCourseSubject::getName, TextbookSubscriptionListVo::getCourseName)
                 .select(Textbook.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionListVo.class).contains(x.getProperty()))
+
+                .innerJoin(BaseClassAdminCourse.class, BaseClassAdminCourse::getId, BaseClassCourse::getClassId)
+
                 .innerJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
+
                 .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
                 .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Textbook::getTextbookType,
                         wrapper -> wrapper
                                 .selectAs(DictionaryDetail::getName, TextbookSubscriptionListVo::getTextbookTypeCn)
                 )
-                .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                .in(BaseClassCourse::getClassId, dto.getClassIdList())
+
+                .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                .in(BaseClassAdminCourse::getClassId, classIdList)
                 .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
-                .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+                .eq(BaseClassAdminCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
                 .eq(Textbook::getDeleteMark, DeleteMark.NODELETE.getCode())
         ;
         List<TextbookSubscriptionListVo> textbookSubscriptionListVoList = baseClassCourseMapper.selectJoinList(TextbookSubscriptionListVo.class, baseClassCourseMPJLambdaWrapper);
-//        IPage<TextbookSubscriptionListVo> page = this.baseMapper.getSubscriptionPageByClass(new Page<>(dto.getLimit(), dto.getSize()), dto);
+
+        List<String> textbookIds = textbookSubscriptionListVoList.stream()
+                .map(TextbookSubscriptionListVo::getTextbookId)
+                .distinct() // 去重操作
+                .collect(Collectors.toList());
 
         // 处理每本教材使用的人数
-        if(!classIdList.isEmpty()) {
-            for(TextbookSubscriptionListVo t : textbookSubscriptionListVoList){
-                MPJLambdaWrapper<BaseClassCourse> countNum = new MPJLambdaWrapper<>();
-                countNum
-                        .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getClassId, BaseClassCourse::getClassId)
-                        .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
-                        .eq(BaseClassCourse::getTextbookId, t.getTextbookId())
-                        .eq(BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
-                        .in(BaseClassCourse::getClassId, dto.getClassIdList())
-                        .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
-                        .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
-                ;
-                Long num = baseClassCourseMapper.selectCount(countNum);
-                t.setStudentSubscriptionNumber(num.intValue());
+        if(ObjectUtils.isNotEmpty(textbookIds)){
+            MPJLambdaWrapper<BaseClassCourse> countNum = new MPJLambdaWrapper<>();
+            countNum
+                    .selectAs(BaseClassCourse::getTextbookId, TextbookSubscriptionListVo::getTextbookId)
+                    .selectAs(BaseClassAdminCourse::getClassId, TextbookSubscriptionListVo::getClassIds)
+                    .selectCount(BaseStudentSchoolRoll::getId, TextbookSubscriptionListVo::getStudentSubscriptionNumber)
+
+                    .innerJoin(BaseClassAdminCourse.class, BaseClassAdminCourse::getId, BaseClassCourse::getClassId)
+
+                    .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getClassId, BaseClassAdminCourse::getClassId)
+
+                    .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+                    .in(BaseClassCourse::getTextbookId, textbookIds)
+                    .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                    .in(BaseClassAdminCourse::getClassId, classIdList)
+                    .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
+                    .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+                    .groupBy(BaseClassCourse::getTextbookId)
+                    .groupBy(BaseClassAdminCourse::getClassId)
+            ;
+
+            List<TextbookSubscriptionListVo> countStuNumList = baseClassCourseMapper.selectJoinList(TextbookSubscriptionListVo.class, countNum);
+
+            Map<String, List<TextbookSubscriptionListVo>> countStuNumMap = countStuNumList.stream()
+                    .collect(Collectors.groupingBy(TextbookSubscriptionListVo::getTextbookId));
+
+            if(ObjectUtils.isNotEmpty(countStuNumMap)){
+                StringBuilder classIds;
+                int sum;
+                for(TextbookSubscriptionListVo t : textbookSubscriptionListVoList){
+                    List<TextbookSubscriptionListVo> textbookSubscriptionListVos = countStuNumMap.get(t.getTextbookId());
+                    if(ObjectUtils.isNotEmpty(textbookSubscriptionListVos)){
+                        sum = 0;
+                        classIds = new StringBuilder();
+                        for (TextbookSubscriptionListVo textbookSubscriptionListVo : textbookSubscriptionListVos){
+                            sum += ObjectUtils.isNotEmpty(textbookSubscriptionListVo.getStudentSubscriptionNumber()) ? textbookSubscriptionListVo.getStudentSubscriptionNumber() : 0;
+                            if(ObjectUtils.isNotEmpty(textbookSubscriptionListVo.getClassIds())){
+                                classIds.append(textbookSubscriptionListVo.getClassIds());
+                                classIds.append(",");
+                            }
+                        }
+
+                        if (classIds.length() > 0) { // 确保 StringBuilder 不为空,以避免 StringIndexOutOfBoundsException
+                            classIds.deleteCharAt(classIds.length() - 1);
+                        }
 
-                t.setClassIds(dto.getClassIds());
+                        t.setStudentSubscriptionNumber(sum);
+                        t.setUseClassNum(textbookSubscriptionListVos.size());
+                        t.setClassIds(classIds.toString());
+                    }
+                }
             }
+//        for(TextbookSubscriptionListVo t : textbookSubscriptionListVoList){
+//            MPJLambdaWrapper<BaseClassAdminCourse> countNum = new MPJLambdaWrapper<>();
+//            countNum
+//                    .innerJoin(BaseClassCourse.class, BaseClassCourse::getClassId, BaseClassAdminCourse::getId)
+//
+//                    .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getClassId, BaseClassAdminCourse::getClassId)
+//
+//                    .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+//                    .eq(BaseClassCourse::getTextbookId, t.getTextbookId())
+//                    .eq(BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+//                    .in(BaseClassAdminCourse::getClassId, dto.getClassIdList())
+//                    .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
+//                    .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+//            ;
+//            Long num = baseClassCourseMapper.selectCount(countNum);
+//            t.setStudentSubscriptionNumber(num.intValue());
+//
+//            t.setClassIds(dto.getClassIds());
+//
         }
 
         return textbookSubscriptionListVoList;

+ 25 - 0
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookSubscriptionItemHistoryServiceImpl.java

@@ -0,0 +1,25 @@
+package com.xjrsoft.module.textbook.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.module.textbook.entity.TextbookSubscriptionItemHistory;
+import com.xjrsoft.module.textbook.mapper.TextbookSubscriptionItemHistoryMapper;
+import com.xjrsoft.module.textbook.service.ITextbookSubscriptionItemHistoryService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+
+/**
+* @title: 教材教辅征订项变更历史
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class TextbookSubscriptionItemHistoryServiceImpl extends MPJBaseServiceImpl<TextbookSubscriptionItemHistoryMapper, TextbookSubscriptionItemHistory> implements ITextbookSubscriptionItemHistoryService {
+}

+ 288 - 71
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookSubscriptionServiceImpl.java

@@ -1,5 +1,6 @@
 package com.xjrsoft.module.textbook.service.impl;
 
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.excel.EasyExcel;
@@ -14,25 +15,28 @@ import com.xjrsoft.common.enums.WarehouseModeEnum;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.entity.BaseCourseSubject;
+import com.xjrsoft.module.base.entity.BaseGrade;
 import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.student.entity.BaseClassMajorSet;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
+import com.xjrsoft.module.teacher.entity.XjrUser;
 import com.xjrsoft.module.textbook.dto.*;
 import com.xjrsoft.module.textbook.entity.*;
-import com.xjrsoft.module.textbook.mapper.TextbookSubscriptionClassMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookSubscriptionItemMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookSubscriptionMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookWarehouseRecordMapper;
+import com.xjrsoft.module.textbook.mapper.*;
 import com.xjrsoft.module.textbook.service.ITextbookSubscriptionService;
 import com.xjrsoft.module.textbook.vo.*;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.InputStream;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
@@ -55,8 +59,12 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
 
     private final TextbookSubscriptionClassMapper textbookSubscriptionClassMapper;
 
+    private final TextbookSubscriptionItemClassMapper textbookSubscriptionItemClassMapper;
+
     private final TextbookWarehouseRecordMapper textbookWarehouseRecordMapper;
 
+    private final TextbookSubscriptionItemHistoryMapper textbookSubscriptionItemHistoryMapper;
+
     @Override
     public IPage<TextbookSubscriptionPageVo> pageRubAndHand(TextbookSubscriptionPageDto dto) {
         MPJLambdaWrapper<TextbookSubscription> queryWrapper = new MPJLambdaWrapper<>();
@@ -95,8 +103,8 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                         wrapper -> wrapper
                                 .selectAs(DictionaryDetail::getName, TextbookInstockroomListVo::getTextbookTypeCn)
                 )
-                .eq(TextbookSubscriptionItem::getTextbookSubscriptionId, dto.getTextbookSubscriptionId())
 
+                .eq(TextbookSubscriptionItem::getTextbookSubscriptionId, dto.getTextbookSubscriptionId())
                 .orderByAsc(TextbookSubscriptionItem::getInStockNum)
         ;
 
@@ -105,18 +113,14 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
 
     @Override
     public List<TextbookInstockroomOnceListVo> everyInstockroomList(TextbookInstockroomOnceListDto dto) {
-        MPJLambdaWrapper<TextbookSubscriptionItem> queryWrapper = new MPJLambdaWrapper<>();
+        MPJLambdaWrapper<TextbookWarehouseRecord> queryWrapper = new MPJLambdaWrapper<>();
         queryWrapper
                 .select(TextbookSubscriptionItem::getId)
+                .selectAs(TextbookWarehouseRecord::getWarehouseNumber, TextbookInstockroomOnceListVo::getOnceInStockNum)
+                .selectAs(TextbookWarehouseRecord::getCreateDate, TextbookInstockroomOnceListVo::getCreateDate)
+                .selectAs(TextbookWarehouseRecord::getCreateUserId, TextbookInstockroomOnceListVo::getCreateUserId)
                 .select(Textbook.class, x -> VoToColumnUtil.fieldsToColumns(TextbookInstockroomOnceListVo.class).contains(x.getProperty()))
-                .select(TextbookSubscriptionItem.class, x -> VoToColumnUtil.fieldsToColumns(TextbookInstockroomOnceListVo.class).contains(x.getProperty()))
                 .leftJoin(Textbook.class, Textbook::getId, TextbookSubscriptionItem::getTextbookId)
-                .leftJoin(TextbookWarehouseRecord.class, TextbookWarehouseRecord::getDataItemId, TextbookSubscriptionItem::getId,
-                        wrapper -> wrapper
-                                .selectAs(TextbookWarehouseRecord::getWarehouseNumber, TextbookInstockroomOnceListVo::getOnceInStockNum)
-                                .selectAs(TextbookWarehouseRecord::getCreateDate, TextbookInstockroomOnceListVo::getCreateDate)
-                                .selectAs(TextbookWarehouseRecord::getCreateUserId, TextbookInstockroomOnceListVo::getCreateUserId)
-                )
                 .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, Textbook::getCourseSubjectId,
                         wrapper -> wrapper
                                 .selectAs(BaseCourseSubject::getName, TextbookInstockroomOnceListVo::getCourseName)
@@ -129,7 +133,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 .orderByAsc(TextbookSubscriptionItem::getInStockNum)
         ;
 
-        return textbookSubscriptionTextbookSubscriptionItemMapper.selectJoinList(TextbookInstockroomOnceListVo.class, queryWrapper);
+        return textbookWarehouseRecordMapper.selectJoinList(TextbookInstockroomOnceListVo.class, queryWrapper);
     }
 
     @Override
@@ -180,15 +184,19 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
         int stuNum = 0;
         int teaNum = 0;
         BigDecimal totalPrice = BigDecimal.valueOf(0);
+        BigDecimal currentPrice;
+        BigDecimal currentTotalPrice;
         for (TextbookSubscriptionItem textbookSubscriptionItem : textbookSubscriptionItemList) {
             stuNum += textbookSubscriptionItem.getStudentNum();
             teaNum += textbookSubscriptionItem.getTeacherNum();
 
-            totalPrice.add(textbookSubscriptionItem.getPrice()
-                            .multiply(BigDecimal.valueOf(textbookSubscriptionItem.getDiscount()))
-                            .divide(BigDecimal.valueOf(10))
-                            .multiply(BigDecimal.valueOf(textbookSubscriptionItem.getTeacherNum() + textbookSubscriptionItem.getStudentNum())));
+            BigDecimal discount = BigDecimal.valueOf(textbookSubscriptionItem.getDiscount()).divide(BigDecimal.valueOf(10), 2, RoundingMode.DOWN);
+
+            currentPrice = textbookSubscriptionItem.getPrice().multiply(discount);
 
+            currentTotalPrice = currentPrice.multiply(BigDecimal.valueOf(textbookSubscriptionItem.getTeacherNum() + textbookSubscriptionItem.getStudentNum()));
+
+            totalPrice = totalPrice.add(currentTotalPrice);
         }
         TextbookSubscriptionDetailVo textbookSubscriptionDetailVo = new TextbookSubscriptionDetailVo();
         textbookSubscriptionDetailVo.setId(String.valueOf(id));
@@ -226,6 +234,38 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
         return page;
     }
 
+    @Override
+    public IPage<BaseclassPageVo> baseclassPage(BaseclassPageDto dto) {
+        // 查询征订记录总的征订班级
+        MPJLambdaWrapper<TextbookSubscriptionItem> baseClassMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        baseClassMPJLambdaWrapper
+                .disableSubLogicDel()
+                .distinct()
+                .selectAs(BaseGrade::getName, BaseclassPageVo::getGradeIdCn)
+                .selectAs(XjrUser::getName, BaseclassPageVo::getTeacherIdCn)
+                .select(" (select" +
+                        "         count(a.id)" +
+                        "     from base_student_school_roll a" +
+                        "         where a.class_id = t1.base_class_id" +
+                        "         and a.archives_status = 'FB2901'" +
+                        "         and a.delete_mark = 0" +
+                        "    ) as total_student")
+                .select(BaseClass.class, x -> VoToColumnUtil.fieldsToColumns(BaseclassPageVo.class).contains(x.getProperty()))
+
+                .innerJoin(TextbookSubscriptionItemClass.class, TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, TextbookSubscriptionItem::getId)
+
+                .leftJoin(BaseClass.class, BaseClass::getId, TextbookSubscriptionItemClass::getBaseClassId)
+                .leftJoin(BaseGrade.class, BaseGrade::getId, BaseClass::getGradeId)
+                .leftJoin(XjrUser.class, XjrUser::getId, BaseClass::getTeacherId)
+
+                .eq(ObjectUtils.isNotEmpty(dto.getId()), TextbookSubscriptionItem::getTextbookSubscriptionId, dto.getId())
+                .eq(ObjectUtils.isNotEmpty(dto.getTextbookSubscriptionItemId()), TextbookSubscriptionItem::getId, dto.getTextbookSubscriptionItemId())
+                .eq(TextbookSubscriptionClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+        ;
+
+        return textbookSubscriptionTextbookSubscriptionItemMapper.selectJoinPage(ConventPage.getPage(dto), BaseclassPageVo.class, baseClassMPJLambdaWrapper);
+    }
+
     @Override
     public List<SubscriptionItemListDistributeVo> itemListConfirmDistribute(SubscriptionItemListDistributeDto dto) {
         MPJLambdaWrapper<TextbookSubscriptionItem> textbookSubscriptionItemMPJLambdaWrapper = new MPJLambdaWrapper<>();
@@ -247,32 +287,55 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
         // 处理征订表
         int sum = 0;
         for (TextbookSubscriptionItem textbookSubscriptionItem : textbookSubscription.getTextbookSubscriptionItemList()) {
-            textbookSubscriptionItem.setStudentNum(ObjectUtil.isNull(textbookSubscriptionItem.getStudentNum()) ? 0 : textbookSubscriptionItem.getStudentNum());
-            textbookSubscriptionItem.setTeacherNum(ObjectUtil.isNull(textbookSubscriptionItem.getTeacherNum()) ? 0 : textbookSubscriptionItem.getTeacherNum());
+            textbookSubscriptionItem.setStudentNum(ObjectUtils.isEmpty(textbookSubscriptionItem.getStudentNum()) ? 0 : textbookSubscriptionItem.getStudentNum());
+            textbookSubscriptionItem.setTeacherNum(ObjectUtils.isEmpty(textbookSubscriptionItem.getTeacherNum()) ? 0 : textbookSubscriptionItem.getTeacherNum());
 
             sum += textbookSubscriptionItem.getStudentNum() + textbookSubscriptionItem.getTeacherNum();
         }
+        textbookSubscription.setSum(sum);
+        textbookSubscription.setCreateDate(new Date());
         textbookSubscriptionTextbookSubscriptionMapper.insert(textbookSubscription);
 
-        // 处理征订和班级关联表
-        if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
-                && textbookSubscription.getSubscriptionMethod() == 1
-                && StringUtils.isNotBlank(textbookSubscription.getBaseClassIds())
-        ) {
-            String[] classIdArr = textbookSubscription.getBaseClassIds().split(",");
-            List<String> classIdList = Arrays.asList(classIdArr);
-            for (String str : classIdList) {
-                TextbookSubscriptionClass textbookSubscriptionClass = new TextbookSubscriptionClass();
-                textbookSubscriptionClass.setTextbookSubscriptionId(textbookSubscription.getId());
-                textbookSubscriptionClass.setBaseClassId(Long.parseLong(str));
-                textbookSubscriptionClassMapper.insert(textbookSubscriptionClass);
+//        // 处理征订和班级关联表
+//        if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
+//                && textbookSubscription.getSubscriptionMethod() == 1
+//                && StringUtils.isNotBlank(textbookSubscription.getBaseClassIds())
+//        ) {
+//            String[] classIdArr = textbookSubscription.getBaseClassIds().split(",");
+//            TextbookSubscriptionClass textbookSubscriptionClass;
+//            for (String str : classIdArr) {
+//                textbookSubscriptionClass = new TextbookSubscriptionClass();
+//                textbookSubscriptionClass.setTextbookSubscriptionId(textbookSubscription.getId());
+//                textbookSubscriptionClass.setBaseClassId(Long.parseLong(str));
+//                textbookSubscriptionClass.setCreateDate(new Date());
+//                textbookSubscriptionClassMapper.insert(textbookSubscriptionClass);
+//            }
+//        }
+
+        // 处理征订项
+        TextbookSubscriptionItemClass textbookSubscriptionItemClass;
+        for (TextbookSubscriptionItem textbookSubscriptionItem : textbookSubscription.getTextbookSubscriptionItemList()) {
+            String[] classIdArr = new String[0];
+            if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
+                    && textbookSubscription.getSubscriptionMethod() == 1
+                    && ObjectUtils.isNotEmpty(textbookSubscriptionItem.getClassIds())
+            ) {
+                classIdArr = textbookSubscriptionItem.getClassIds().split(",");
             }
-        }
 
-        // 处理征订表子表
-        for (TextbookSubscriptionItem textbookSubscriptionItem : textbookSubscription.getTextbookSubscriptionItemList()) {
+            textbookSubscriptionItem.setUseClassNum(classIdArr.length);
             textbookSubscriptionItem.setTextbookSubscriptionId(textbookSubscription.getId());
+            textbookSubscriptionItem.setCreateDate(new Date());
             textbookSubscriptionTextbookSubscriptionItemMapper.insert(textbookSubscriptionItem);
+
+            // 处理征订项和班级关联表
+            for (String str : classIdArr) {
+                textbookSubscriptionItemClass = new TextbookSubscriptionItemClass();
+                textbookSubscriptionItemClass.setTextbookSubscriptionItemId(textbookSubscriptionItem.getId());
+                textbookSubscriptionItemClass.setBaseClassId(Long.parseLong(str));
+                textbookSubscriptionItemClass.setCreateDate(new Date());
+                textbookSubscriptionItemClassMapper.insert(textbookSubscriptionItemClass);
+            }
         }
         return true;
     }
@@ -286,7 +349,9 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
 
         List<Long> textbookSubscriptionItemIds = new ArrayList<>();
         for (TextbookInstockroomDto dto : dtos) {
-            textbookSubscriptionItemIds.add(dto.getTextbookSubscriptionItemId());
+            if(ObjectUtils.isNotEmpty(dto.getTextbookSubscriptionItemId())){
+                textbookSubscriptionItemIds.add(dto.getTextbookSubscriptionItemId());
+            }
         }
 
         if (textbookSubscriptionItemIds.isEmpty()) {
@@ -310,24 +375,28 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
 
         Map<Long, TextbookSubscriptionItem> itemByIdMap = new HashMap<>();
         for (TextbookSubscriptionItem el : textbookSubscriptionItemList) {
-            itemByIdMap.put(el.getId(), el);
+            if(ObjectUtils.isNotEmpty(el.getId()) && !itemByIdMap.containsKey(el.getId())){
+                itemByIdMap.put(el.getId(), el);
+            }
         }
 
+        TextbookSubscriptionItem old = null;
         for (TextbookInstockroomDto dto : dtos) {
-            TextbookSubscriptionItem old = null;
-            if (dto.getTextbookSubscriptionItemId() != null && dto.getTextbookSubscriptionItemId() > 0) {
+            if (ObjectUtils.isNotEmpty(dto.getTextbookSubscriptionItemId())) {
                 old = itemByIdMap.get(dto.getTextbookSubscriptionItemId());
             }
 
-            if (old == null) {
+            if (ObjectUtils.isEmpty(old)) {
                 continue;
             }
 
             TextbookSubscriptionItem updateItem = new TextbookSubscriptionItem();
             updateItem.setId(old.getId());
             updateItem.setDiscount(dto.getDiscount());
-            updateItem.setPrice(dto.getPrice());
+            updateItem.setPrice(old.getPrice().multiply(BigDecimal.valueOf(dto.getDiscount() / 10)));
             updateItem.setInStockNum(old.getInStockNum() + dto.getInNum());
+            updateItem.setModifyDate(new Date());
+            updateItem.setModifyUserId(StpUtil.getLoginIdAsLong());
             textbookSubscriptionTextbookSubscriptionItemMapper.updateById(updateItem);
 
             //新增入库记录
@@ -336,9 +405,16 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
             textbookWarehouseRecord.setDataId(dto.getTextbookSubscriptionId());
             textbookWarehouseRecord.setDataItemId(dto.getTextbookSubscriptionItemId());
             textbookWarehouseRecord.setWarehouseNumber(dto.getInNum());
+            textbookWarehouseRecord.setPrice(old.getPrice());
+            textbookWarehouseRecord.setDiscount(dto.getDiscount());
+            textbookWarehouseRecord.setSubtotal(old.getPrice().multiply(BigDecimal.valueOf(dto.getDiscount() / 10)));
+            textbookWarehouseRecord.setTotalPrice(textbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(dto.getInNum())));
             textbookWarehouseRecord.setWarehouseMode(WarehouseModeEnum.WmManual.getCode());
+            updateItem.setCreateDate(new Date());
+            updateItem.setCreateUserId(StpUtil.getLoginIdAsLong());
             textbookWarehouseRecordMapper.insert(textbookWarehouseRecord);
         }
+
         return true;
     }
 
@@ -416,7 +492,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean update(TextbookSubscription textbookSubscription) {
-        textbookSubscriptionTextbookSubscriptionMapper.updateById(textbookSubscription);
+        int sum = 0;
         //********************************* TextbookSubscriptionItem  增删改  开始 *******************************************/
         {
             // 查出所有子级的id
@@ -427,56 +503,181 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
             List<Long> textbookSubscriptionItemIds = textbookSubscriptionItemList.stream()
                     .map(TextbookSubscriptionItem::getId)
                     .collect(Collectors.toList());
-            //原有子表单 没有被删除的主键
+            // 原有子表单 没有被删除的主键
             List<Long> textbookSubscriptionItemOldIds = textbookSubscription.getTextbookSubscriptionItemList().stream()
                     .map(TextbookSubscriptionItem::getId)
                     .filter(Objects::nonNull)
                     .collect(Collectors.toList());
-            //找到需要删除的id
+            // 找到需要删除的id
             List<Long> textbookSubscriptionItemRemoveIds = textbookSubscriptionItemIds.stream()
                     .filter(item -> !textbookSubscriptionItemOldIds.contains(item))
                     .collect(Collectors.toList());
 
+            TextbookSubscriptionItemClass textbookSubscriptionItemClass;
             for (TextbookSubscriptionItem textbookSubscriptionItem : textbookSubscription.getTextbookSubscriptionItemList()) {
-                //如果不等于空则修改
+                // 如果不等于空则修改
                 if (textbookSubscriptionItem.getId() != null) {
                     textbookSubscriptionTextbookSubscriptionItemMapper.updateById(textbookSubscriptionItem);
-                }
-                //如果等于空 则新增
-                else {
-                    //已经不存在的id 删除
+                } else {
+                    // 如果等于空 则新增
+                    // 新增的时候应该处理班级关联
+                    String[] classIdArr = new String[0];
+                    if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
+                            && textbookSubscription.getSubscriptionMethod() == 1
+                            && ObjectUtils.isNotEmpty(textbookSubscriptionItem.getClassIds())
+                    ) {
+                        classIdArr = textbookSubscriptionItem.getClassIds().split(",");
+                    }
+
+                    textbookSubscriptionItem.setUseClassNum(classIdArr.length);
                     textbookSubscriptionItem.setTextbookSubscriptionId(textbookSubscription.getId());
+                    textbookSubscriptionItem.setCreateDate(new Date());
                     textbookSubscriptionTextbookSubscriptionItemMapper.insert(textbookSubscriptionItem);
+
+                    // 处理征订项和班级关联表
+                    for (String str : classIdArr) {
+                        textbookSubscriptionItemClass = new TextbookSubscriptionItemClass();
+                        textbookSubscriptionItemClass.setTextbookSubscriptionItemId(textbookSubscriptionItem.getId());
+                        textbookSubscriptionItemClass.setBaseClassId(Long.parseLong(str));
+                        textbookSubscriptionItemClass.setCreateDate(new Date());
+                        textbookSubscriptionItemClassMapper.insert(textbookSubscriptionItemClass);
+                    }
                 }
+                textbookSubscriptionItem.setStudentNum(ObjectUtils.isEmpty(textbookSubscriptionItem.getStudentNum()) ? 0 : textbookSubscriptionItem.getStudentNum());
+                textbookSubscriptionItem.setTeacherNum(ObjectUtils.isEmpty(textbookSubscriptionItem.getTeacherNum()) ? 0 : textbookSubscriptionItem.getTeacherNum());
+
+                sum += textbookSubscriptionItem.getStudentNum() + textbookSubscriptionItem.getTeacherNum();
             }
-            //已经不存在的id 删除
-            if (textbookSubscriptionItemRemoveIds.size() > 0) {
+            // 已经不存在的id 删除
+            if (ObjectUtils.isNotEmpty(textbookSubscriptionItemRemoveIds.isEmpty())) {
+                LambdaUpdateWrapper<TextbookSubscriptionItemClass> textbookSubscriptionItemClassLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                textbookSubscriptionItemClassLambdaUpdateWrapper
+                        .in(TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, textbookSubscriptionItemRemoveIds)
+                        .eq(TextbookSubscriptionItemClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        ;
+                textbookSubscriptionItemClassMapper.delete(textbookSubscriptionItemClassLambdaUpdateWrapper);
                 textbookSubscriptionTextbookSubscriptionItemMapper.deleteBatchIds(textbookSubscriptionItemRemoveIds);
             }
         }
         //********************************* TextbookSubscriptionItem  增删改  结束 *******************************************/
 
         //********************************* TextbookSubscriptionClass  增删改  开始 *******************************************/
-        LambdaUpdateWrapper<TextbookSubscriptionClass> textbookSubscriptionClassLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
-        textbookSubscriptionClassLambdaUpdateWrapper
-                .eq(TextbookSubscriptionClass::getTextbookSubscriptionId, textbookSubscription.getId())
+//        LambdaUpdateWrapper<TextbookSubscriptionClass> textbookSubscriptionClassLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+//        textbookSubscriptionClassLambdaUpdateWrapper
+//                .eq(TextbookSubscriptionClass::getTextbookSubscriptionId, textbookSubscription.getId())
+//        ;
+//        textbookSubscriptionClassMapper.delete(textbookSubscriptionClassLambdaUpdateWrapper);
+//
+//        if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
+//                && textbookSubscription.getSubscriptionMethod() == 1
+//                && StringUtils.isNotBlank(textbookSubscription.getBaseClassIds())
+//        ) {
+//            String[] classIdArr = textbookSubscription.getBaseClassIds().split(",");
+//            for (String str : classIdArr) {
+//                TextbookSubscriptionClass textbookSubscriptionClass = new TextbookSubscriptionClass();
+//                textbookSubscriptionClass.setTextbookSubscriptionId(textbookSubscription.getId());
+//                textbookSubscriptionClass.setBaseClassId(Long.parseLong(str));
+//                textbookSubscriptionClass.setCreateDate(new Date());
+//                textbookSubscriptionClassMapper.insert(textbookSubscriptionClass);
+//            }
+//        }
+        //********************************* TextbookSubscriptionClass  增删改  结束 *******************************************/
+
+        textbookSubscription.setSum(sum);
+        textbookSubscriptionTextbookSubscriptionMapper.updateById(textbookSubscription);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean alteration(UpdateTextbookSubscriptionItemDto dto) {
+        TextbookSubscriptionItem old = textbookSubscriptionTextbookSubscriptionItemMapper.selectById(dto.getId());
+        if(old == null){
+            throw new MyException("征订项已经被修改,刷新重试");
+        }
+
+        MPJLambdaWrapper<TextbookSubscription> textbookSubscriptionMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        textbookSubscriptionMPJLambdaWrapper
+                .select(TextbookSubscription.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscription.class).contains(x.getProperty()))
+                .eq(TextbookSubscriptionItem::getId, dto.getId())
+                .innerJoin(TextbookSubscriptionItem.class, TextbookSubscriptionItem::getTextbookSubscriptionId, TextbookSubscription::getId)
         ;
-        textbookSubscriptionClassMapper.delete(textbookSubscriptionClassLambdaUpdateWrapper);
-
-        if (ObjectUtils.isNotEmpty(textbookSubscription.getSubscriptionMethod())
-                && textbookSubscription.getSubscriptionMethod() == 1
-                && StringUtils.isNotBlank(textbookSubscription.getBaseClassIds())
-        ) {
-            String[] classIdArr = textbookSubscription.getBaseClassIds().split(",");
-            List<String> classIdList = Arrays.asList(classIdArr);
-            for (String str : classIdList) {
-                TextbookSubscriptionClass textbookSubscriptionClass = new TextbookSubscriptionClass();
-                textbookSubscriptionClass.setTextbookSubscriptionId(textbookSubscription.getId());
-                textbookSubscriptionClass.setBaseClassId(Long.parseLong(str));
-                textbookSubscriptionClassMapper.insert(textbookSubscriptionClass);
+
+        TextbookSubscription textbookSubscription = this.selectJoinOne(TextbookSubscription.class, textbookSubscriptionMPJLambdaWrapper);
+
+        // 判断变更状态
+        int alterationType = 0;
+        TextbookSubscription updateTotalNum = new TextbookSubscription();
+        if(!old.getStudentNum().equals(dto.getStudentNum())
+                || !old.getTeacherNum().equals(dto.getTeacherNum())
+        ){
+            alterationType = 1;
+            if(ObjectUtils.isNotEmpty(textbookSubscription)){
+                updateTotalNum.setId(textbookSubscription.getId());
+                updateTotalNum.setSum(textbookSubscription.getSum() + (dto.getStudentNum() - old.getStudentNum()) + (dto.getTeacherNum() - old.getTeacherNum()));
+                this.updateById(updateTotalNum);
             }
         }
-        //********************************* TextbookSubscriptionClass  增删改  结束 *******************************************/
+
+        if(!old.getTextbookId().equals(dto.getTextbookId())){
+            alterationType = 2;
+            if(ObjectUtils.isNotEmpty(textbookSubscription)){
+                updateTotalNum.setId(textbookSubscription.getId());
+                updateTotalNum.setSum(textbookSubscription.getSum() - (old.getTeacherNum() + old.getStudentNum()) + (dto.getTeacherNum() + dto.getStudentNum()));
+                this.updateById(updateTotalNum);
+            }
+        }
+
+        // 将历史记录保存到历史变更记录表
+        // 当前征订项的变更历史最后一次记录
+        LambdaQueryWrapper<TextbookSubscriptionItemHistory> textbookSubscriptionItemHistoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        textbookSubscriptionItemHistoryLambdaQueryWrapper
+                .eq(TextbookSubscriptionItemHistory::getTextbookSubscriptionItemId, old.getId())
+                .orderByDesc(TextbookSubscriptionItemHistory::getHistoryVersion)
+                .last("limit 1")
+        ;
+        TextbookSubscriptionItemHistory lastOne = textbookSubscriptionItemHistoryMapper.selectOne(textbookSubscriptionItemHistoryLambdaQueryWrapper);
+
+        // 将变更前的数据记录在历史表中
+        TextbookSubscriptionItemHistory textbookSubscriptionItemHistory = new TextbookSubscriptionItemHistory();
+        // 变更前
+        textbookSubscriptionItemHistory.setOldTextbookId(old.getTextbookId());
+        textbookSubscriptionItemHistory.setOldStudentNum(old.getStudentNum());
+        textbookSubscriptionItemHistory.setOldTeacherNum(old.getTeacherNum());
+        textbookSubscriptionItemHistory.setOldDiscount(old.getDiscount());
+        textbookSubscriptionItemHistory.setOldPrice(old.getPrice());
+        textbookSubscriptionItemHistory.setOldInStockNum(old.getInStockNum());
+        textbookSubscriptionItemHistory.setOldOutStockNum(old.getOutStockNum());
+
+        // 变更后
+        textbookSubscriptionItemHistory.setNewTextbookId(dto.getTextbookId());
+        textbookSubscriptionItemHistory.setNewStudentNum(dto.getStudentNum());
+        textbookSubscriptionItemHistory.setNewTeacherNum(dto.getTeacherNum());
+        textbookSubscriptionItemHistory.setNewDiscount(dto.getDiscount());
+        textbookSubscriptionItemHistory.setNewPrice(dto.getPrice());
+        textbookSubscriptionItemHistory.setNewInStockNum(dto.getInStockNum());
+        textbookSubscriptionItemHistory.setNewOutStockNum(dto.getOutStockNum());
+
+        textbookSubscriptionItemHistory.setTextbookSubscriptionId(old.getTextbookSubscriptionId());
+        textbookSubscriptionItemHistory.setTextbookSubscriptionItemId(old.getId());
+        textbookSubscriptionItemHistory.setCreateDate(new Date());
+        textbookSubscriptionItemHistory.setCreateUserId(StpUtil.getLoginIdAsLong());
+        if(ObjectUtils.isNotEmpty(lastOne)){
+            textbookSubscriptionItemHistory.setHistoryVersion(lastOne.getHistoryVersion() + 1);
+        } else {
+            textbookSubscriptionItemHistory.setHistoryVersion(1);
+        }
+        textbookSubscriptionItemHistory.setAlterationType(alterationType);
+        textbookSubscriptionItemHistoryMapper.insert(textbookSubscriptionItemHistory);
+
+        // 变更征订总数量
+
+
+        //变更当前记录
+        TextbookSubscriptionItem updateItem = new TextbookSubscriptionItem();
+        BeanUtils.copyProperties(dto, updateItem);
+        updateItem.setAlterationType(alterationType);
+        textbookSubscriptionTextbookSubscriptionItemMapper.updateById(updateItem);
 
         return true;
     }
@@ -499,9 +700,25 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean delete(List<Long> ids) {
-        textbookSubscriptionTextbookSubscriptionMapper.deleteBatchIds(ids);
-        textbookSubscriptionTextbookSubscriptionItemMapper.delete(Wrappers.lambdaQuery(TextbookSubscriptionItem.class).in(TextbookSubscriptionItem::getTextbookSubscriptionId, ids));
-        textbookSubscriptionClassMapper.delete(Wrappers.lambdaQuery(TextbookSubscriptionClass.class).in(TextbookSubscriptionClass::getTextbookSubscriptionId, ids));
+        LambdaQueryWrapper<TextbookSubscriptionItem> textbookSubscriptionItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        textbookSubscriptionItemLambdaQueryWrapper
+                .in(TextbookSubscriptionItem::getTextbookSubscriptionId, ids)
+                ;
+        List<TextbookSubscriptionItem> textbookSubscriptionItemList = textbookSubscriptionTextbookSubscriptionItemMapper.selectList(textbookSubscriptionItemLambdaQueryWrapper);
+
+        List<Long> textbookSubscriptionItemIds = textbookSubscriptionItemList.stream()
+                                .map(TextbookSubscriptionItem::getId)
+                                .collect(Collectors.toList());
+
+        if(ObjectUtils.isNotEmpty(textbookSubscriptionItemIds)){
+            textbookSubscriptionItemClassMapper.delete(Wrappers.lambdaQuery(TextbookSubscriptionItemClass.class).in(TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, textbookSubscriptionItemIds));
+        }
+
+        if(ObjectUtils.isNotEmpty(ids)) {
+            textbookSubscriptionTextbookSubscriptionItemMapper.delete(Wrappers.lambdaQuery(TextbookSubscriptionItem.class).in(TextbookSubscriptionItem::getTextbookSubscriptionId, ids));
+            textbookSubscriptionClassMapper.delete(Wrappers.lambdaQuery(TextbookSubscriptionClass.class).in(TextbookSubscriptionClass::getTextbookSubscriptionId, ids));
+            textbookSubscriptionTextbookSubscriptionMapper.deleteBatchIds(ids);
+        }
         return true;
     }
 

+ 29 - 29
src/main/java/com/xjrsoft/module/textbook/service/impl/WfTextbookSubscriptionServiceImpl.java

@@ -387,7 +387,7 @@ public class WfTextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<WfText
         for (TextbookInstockroomImportDto item : dataList){
             textbookInstockroomDtoList.add(new TextbookInstockroomDto(){{
                 setTextbookSubscriptionId(wfTextbookSubscriptionId);
-                setIssn(item.getIssn());
+//                setIssn(item.getIssn());
                 setInNum(item.getInNum());
             }});
         }
@@ -430,34 +430,34 @@ public class WfTextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<WfText
 
         Date now = new Date();
         Long loginId = StpUtil.getLoginIdAsLong();
-        for (TextbookInstockroomDto dto : dtos) {
-            WfTextbookSubscriptionItem old;
-            if(dto.getTextbookSubscriptionItemId() != null && dto.getTextbookSubscriptionItemId() > 0){
-                old = itemByIdMap.get(dto.getTextbookSubscriptionItemId());
-            } else {
-                old = itemByIssnMap.get(dto.getIssn());
-            }
-
-            if(old == null){
-                continue;
-            }
-
-            WfTextbookSubscriptionItem updateItem = new WfTextbookSubscriptionItem();
-            updateItem.setId(old.getId());
-            updateItem.setInStockroomNum(old.getInStockroomNum() + dto.getInNum());
-            updateItem.setModifyDate(now);
-            updateItem.setModifyUserId(loginId);
-            wfTextbookSubscriptionWfTextbookSubscriptionItemMapper.updateById(updateItem);
-
-            //新增入库记录
-//            textbookService.deliverWarehouse(new AddTextbookWarehouseRecordDto() {{
-//                setTextbookId(old.getTextbookId());
-//                setWarehouseNumber(dto.getInNum());
-//                setSource("wm_manual");
-//            }});
-//            successNum++;
-            instockroomNum += dto.getInNum();
-        }
+//        for (TextbookInstockroomDto dto : dtos) {
+//            WfTextbookSubscriptionItem old;
+//            if(dto.getTextbookSubscriptionItemId() != null && dto.getTextbookSubscriptionItemId() > 0){
+//                old = itemByIdMap.get(dto.getTextbookSubscriptionItemId());
+//            } else {
+//                old = itemByIssnMap.get(dto.getIssn());
+//            }
+//
+//            if(old == null){
+//                continue;
+//            }
+//
+//            WfTextbookSubscriptionItem updateItem = new WfTextbookSubscriptionItem();
+//            updateItem.setId(old.getId());
+//            updateItem.setInStockroomNum(old.getInStockroomNum() + dto.getInNum());
+//            updateItem.setModifyDate(now);
+//            updateItem.setModifyUserId(loginId);
+//            wfTextbookSubscriptionWfTextbookSubscriptionItemMapper.updateById(updateItem);
+//
+//            //新增入库记录
+////            textbookService.deliverWarehouse(new AddTextbookWarehouseRecordDto() {{
+////                setTextbookId(old.getTextbookId());
+////                setWarehouseNumber(dto.getInNum());
+////                setSource("wm_manual");
+////            }});
+////            successNum++;
+//            instockroomNum += dto.getInNum();
+//        }
         result.put("allNum", dtos.size());
         result.put("successNum", successNum);
         result.put("instockroomNum", instockroomNum);

+ 218 - 0
src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemHistoryPageVo.java

@@ -0,0 +1,218 @@
+package com.xjrsoft.module.textbook.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import com.xjrsoft.common.annotation.Trans;
+import com.xjrsoft.common.enums.TransType;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+* @title: 教材教辅征订项变更历史分页列表出参
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+public class TextbookSubscriptionItemHistoryPageVo {
+
+    /**
+    * 主键编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("主键编号")
+    @ApiModelProperty("主键编号")
+    private String id;
+    /**
+    * 创建人
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("创建人")
+    @ApiModelProperty("创建人")
+    private Long createUserId;
+    /**
+     * 创建人
+     */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("创建人")
+    @ApiModelProperty("创建人")
+    private String createUserIdCn;
+    /**
+    * 创建时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("创建时间")
+    @ApiModelProperty("创建时间")
+    private Date createDate;
+    /**
+    * 教材教辅征订编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材教辅征订编号")
+    @ApiModelProperty("教材教辅征订编号")
+    private Long textbookSubscriptionId;
+    /**
+    * 教材教辅征订项编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材教辅征订项编号")
+    @ApiModelProperty("教材教辅征订项编号")
+    private Long textbookSubscriptionItemId;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材表主键(textbook)")
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long oldTextbookId;
+
+    @ApiModelProperty("国际标准刊号")
+    private String oldIssn;
+
+    @ApiModelProperty("书名")
+    private String oldBookName;
+
+    @ApiModelProperty("出版社")
+    private String oldPublishingHouse;
+
+    @ApiModelProperty("主编")
+    private String oldEditorInChief;
+
+    @ApiModelProperty("课程名称")
+    private String oldCourseName;
+
+    @ApiModelProperty("教材类型")
+    private String oldTextbookTypeCn;
+
+    /**
+    * 学生用书征订数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("学生用书征订数量")
+    @ApiModelProperty("学生用书征订数量")
+    private Integer oldStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教师用书征订数量")
+    @ApiModelProperty("教师用书征订数量")
+    private Integer oldTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("实际折扣")
+    @ApiModelProperty("实际折扣")
+    private Double oldDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("实际价格(元)")
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal oldPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("当前征订任务征订项入库数量")
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer oldInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("当前征订任务征订项出库数量")
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer oldOutStockNum;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材表主键(textbook)")
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long newTextbookId;
+
+    @ApiModelProperty("国际标准刊号")
+    private String newIssn;
+
+    @ApiModelProperty("书名")
+    private String newBookName;
+
+    @ApiModelProperty("出版社")
+    private String newPublishingHouse;
+
+    @ApiModelProperty("主编")
+    private String newEditorInChief;
+
+    @ApiModelProperty("课程名称")
+    private String newCourseName;
+
+    @ApiModelProperty("教材类型")
+    private String newTextbookTypeCn;
+    /**
+    * 学生用书征订数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("学生用书征订数量")
+    @ApiModelProperty("学生用书征订数量")
+    private Integer newStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教师用书征订数量")
+    @ApiModelProperty("教师用书征订数量")
+    private Integer newTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("实际折扣")
+    @ApiModelProperty("实际折扣")
+    private Double newDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("实际价格(元)")
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal newPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("当前征订任务征订项入库数量")
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer newInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("当前征订任务征订项出库数量")
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer newOutStockNum;
+    /**
+    * 当前征订项变更历史记录版本
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("当前征订项变更历史记录版本")
+    @ApiModelProperty("当前征订项变更历史记录版本")
+    private Integer historyVersion;
+    /**
+    * 变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)")
+    @ApiModelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)")
+    private Integer alterationType;
+
+}

+ 124 - 0
src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemHistoryVo.java

@@ -0,0 +1,124 @@
+package com.xjrsoft.module.textbook.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+/**
+* @title: 教材教辅征订项变更历史表单出参
+* @Author phoenix
+* @Date: 2025-01-23
+* @Version 1.0
+*/
+@Data
+public class TextbookSubscriptionItemHistoryVo {
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+    /**
+    * 序号
+    */
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+    /**
+    * 教材教辅征订编号
+    */
+    @ApiModelProperty("教材教辅征订编号")
+    private Long textbookSubscriptionId;
+    /**
+    * 教材教辅征订项编号
+    */
+    @ApiModelProperty("教材教辅征订项编号")
+    private Long textbookSubscriptionItemId;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long oldTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer oldStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer oldTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double oldDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal oldPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer oldInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer oldOutStockNum;
+    /**
+    * 教材表主键(textbook)
+    */
+    @ApiModelProperty("教材表主键(textbook)")
+    private Long newTextbookId;
+    /**
+    * 学生用书征订数量
+    */
+    @ApiModelProperty("学生用书征订数量")
+    private Integer newStudentNum;
+    /**
+    * 教师用书征订数量
+    */
+    @ApiModelProperty("教师用书征订数量")
+    private Integer newTeacherNum;
+    /**
+    * 实际折扣
+    */
+    @ApiModelProperty("实际折扣")
+    private Double newDiscount;
+    /**
+    * 实际价格(元)
+    */
+    @ApiModelProperty("实际价格(元)")
+    private BigDecimal newPrice;
+    /**
+    * 当前征订任务征订项入库数量
+    */
+    @ApiModelProperty("当前征订任务征订项入库数量")
+    private Integer newInStockNum;
+    /**
+    * 当前征订任务征订项出库数量
+    */
+    @ApiModelProperty("当前征订任务征订项出库数量")
+    private Integer newOutStockNum;
+    /**
+    * 当前征订项变更历史记录版本
+    */
+    @ApiModelProperty("当前征订项变更历史记录版本")
+    private Integer historyVersion;
+    /**
+    * 变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)
+    */
+    @ApiModelProperty("变更类型(0:未变更,1:学生用书征订数量,2:教师用书征订数量,3:变更课程,4:学生用书征订数量和教师用书征订数量)")
+    private Integer alterationType;
+
+
+
+}

+ 7 - 0
src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionItemPageVo.java

@@ -113,6 +113,13 @@ public class TextbookSubscriptionItemPageVo {
     @ExcelProperty("教师用书征订数量")
     @ApiModelProperty("教师用书征订数量")
     private Integer teacherNum;
+
+    /**
+     * 在本次征订中本征订项的教材使用的班级数量
+     */
+    @ApiModelProperty("在本次征订中本征订项的教材使用的班级数量")
+    private Integer useClassNum;
+
     /**
     * 实际折扣
     */

+ 5 - 0
src/main/java/com/xjrsoft/module/textbook/vo/TextbookSubscriptionListVo.java

@@ -91,6 +91,11 @@ public class TextbookSubscriptionListVo {
      */
     @ApiModelProperty("学生用书征订数量")
     private Integer studentSubscriptionNumber;
+    /**
+     * 在本次征订中本征订项的教材使用的班级数量
+     */
+    @ApiModelProperty("在本次征订中本征订项的教材使用的班级数量")
+    private Integer useClassNum;
 
     /**
      * 使用班级

+ 38 - 34
src/main/resources/mapper/base/BaseClassCourse.xml

@@ -5,41 +5,47 @@
 <mapper namespace="com.xjrsoft.module.base.mapper.BaseClassCourseMapper">
     <select id="getPage" parameterType="com.xjrsoft.module.base.dto.BaseClassCoursePageDto" resultType="com.xjrsoft.module.base.vo.BaseClassCoursePageVo">
         SELECT
-        t.id AS class_id,
-        t.name AS class_name,
+        t.id as id,
+        t.class_id AS class_id,
+        t9.name AS class_name,
         t1.name AS teacher_name,
         t3.name AS major_name,
         t4.name AS dept_name,
         GROUP_CONCAT(DISTINCT t6.name SEPARATOR '、') AS course_name,
         GROUP_CONCAT(DISTINCT t7.book_name SEPARATOR '、') AS textbook_name,
-        SUM(t8.price) AS amount,
-        SUM(t8.discount_price) AS count
-        FROM base_class t
-        LEFT JOIN xjr_user t1 ON t1.id = t.teacher_id
-        LEFT JOIN base_class_major_set t2 ON t2.class_id = t.id
+        SUM(t7.price) AS amount,
+        SUM(t7.discount_price) AS count
+        FROM base_class_admin_course t
+        inner JOIN base_class t9 ON t9.id = t.class_id
+
+        LEFT JOIN xjr_user t1 ON t1.id = t9.teacher_id
+
+        LEFT JOIN base_class_major_set t2 ON t2.class_id = t.class_id
         LEFT JOIN base_major_set t3 ON t3.id = t2.major_set_id
-        LEFT JOIN xjr_department t4 ON t4.id = t.org_id
-        LEFT JOIN base_class_course t5 ON t5.class_id = t.id AND t5.delete_mark = 0
-        LEFT JOIN base_course_subject t6 ON t6.id = t5.course_id AND t6.delete_mark = 0
-        LEFT JOIN textbook t7 ON t7.id = t5.textbook_id AND t7.delete_mark = 0
-        LEFT JOIN textbook t8 ON t8.id = t5.textbook_id AND t8.delete_mark = 0
+
+        LEFT JOIN xjr_department t4 ON t4.id = t9.org_id
+
+        LEFT JOIN base_class_course t5 ON t5.class_id = t.id and t5.delete_mark = 0
+        LEFT JOIN base_course_subject t6 ON t6.id = t5.course_id
+
+        LEFT JOIN textbook t7 ON t7.id = t5.textbook_id
         WHERE t.delete_mark = 0
         <if test="dto.semester != null">
-            AND t5.base_semester_id = #{dto.semester}
+            AND t.base_semester_id = #{dto.semester}
         </if>
         <if test="dto.className != null and dto.className != ''">
-            AND t.name LIKE CONCAT('%', #{dto.className}, '%')
+            AND t9.name LIKE CONCAT('%', #{dto.className}, '%')
         </if>
         <if test="dto.deptId != null">
-            AND t4.id = #{dto.deptId}
+            AND t9.org_id = #{dto.deptId}
         </if>
-        GROUP BY t.id, t.name, t1.name, t3.name, t4.name
+        GROUP BY t.id, t.class_id, t9.name, t1.name, t3.name, t4.name
         <choose>
             <when test="dto.courseSet == 1">
-                HAVING LENGTH(course_name) > 0
+                HAVING course_name is not null
             </when>
             <when test="dto.courseSet == 2">
-                HAVING LENGTH(course_name) = 0
+                HAVING course_name is null
             </when>
         </choose>
     </select>
@@ -74,21 +80,22 @@
 
     <select id="getSelectedCourseBook" resultType="com.xjrsoft.module.base.entity.CourseBookInfo">
         select
-            distinct
-            t.course_id as courseId,
-            t2.name as courseName,
-            t1.book_name as bookName,
-            t.textbook_id as bookId,
-            concat(t.course_id, '_', t.textbook_id) AS id,
-            t1.issn,
-            t1.editor_in_chief,
-            t1.version
-        from base_class_course t
-        left join textbook t1 on t1.id = t.textbook_id
-        left join base_course_subject t2 on t.course_id = t2.id
+        distinct
+        t3.course_id as courseId,
+        t2.name as courseName,
+        t1.book_name as bookName,
+        t3.textbook_id as bookId,
+        concat(t3.course_id, '_', t3.textbook_id) AS id,
+        t1.issn,
+        t1.editor_in_chief,
+        t1.version
+        from tl.base_class_admin_course t
+        left join base_class_course t3 on t3.class_id = t.id
+        left join textbook t1 on t1.id = t3.textbook_id
+        left join base_course_subject t2 on t3.course_id = t2.id
         where t.delete_mark = 0
         <if test="classIds != null">
-            AND t.class_id in
+            AND t.id in
             <foreach item="classIds" collection="classIds" open="(" separator="," close=")">
                 #{classIds}
             </foreach>
@@ -96,9 +103,6 @@
         <if test="semester != null">
             and t.base_semester_id = #{semester}
         </if>
-<!--        <if test="subjectGroupId != null">-->
-<!--            AND-->
-<!--        </if>-->
     </select>
 
     <insert id="updateAddClassCourseTextbooks">

+ 7 - 1
src/main/resources/mapper/student/BaseStudentMapper.xml

@@ -130,7 +130,13 @@
         LEFT JOIN base_class t4 ON t4.id = t3.class_id
         LEFT JOIN xjr_user t5 ON t4.teacher_id = t5.id
         WHERE t1.delete_mark = 0 AND t2.delete_mark = 0
-        and t3.archives_status = 'FB2901'
+        and t3.archives_status = 'FB2901' and t2.is_normal = 1
+        <if test="dto.classIds != null and dto.classIds.size() > 0">
+            and t3.class_id in
+            <foreach item="classId" index="index" collection="dto.classIds" open="(" close=")" separator=",">
+                #{classId}
+            </foreach>
+        </if>
     </select>
 
 </mapper>

+ 31 - 0
src/main/resources/mapper/student/StudentChangeRecordMapper.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xjrsoft.module.student.mapper.StudentChangeRecordMapper">
+    <select id="getPage" parameterType="com.xjrsoft.module.student.dto.StudentChangeRecordPageDto" resultType="com.xjrsoft.module.student.vo.StudentChangeRecordPageVo">
+        SELECT t1.id,t2.name, t5.name AS gender, t2.credential_number,t1.create_date as operate_date,t4.name AS operate_user_name,
+        t3.name AS change_type, t1.after_data,t1.before_data FROM student_change_record t1
+        INNER JOIN xjr_user t2 ON t1.user_id = t2.id
+        INNER JOIN xjr_dictionary_detail t3 ON t1.change_type = t3.code AND t3.item_id = 1881186538301730818
+        LEFT JOIN xjr_user t4 ON t1.create_user_id = t4.id
+        LEFT JOIN xjr_dictionary_detail t5 ON t2.gender = t5.code AND t5.item_id = 2023000000000000004
+        WHERE t1.delete_mark = 0
+        <if test="dto.name != null and dto.name != '' ">
+            and t2.name like concat('%', #{dto.name}, '%')
+        </if>
+        <if test="dto.credentialNumber != null and dto.credentialNumber != '' ">
+            and t2.credential_number like concat('%', #{dto.credentialNumber}, '%')
+        </if>
+        <if test="dto.changeType != null and dto.changeType != '' ">
+            and t1.change_type = #{dto.changeType}
+        </if>
+        <if test="dto.operateUserName != null and dto.operateUserName != '' ">
+            and t4.name like concat('%', #{dto.operateUserName}, '%')
+        </if>
+        <if test="dto.operateTimeStart != null and dto.operateTimeEnd != null ">
+            and t1.create_date between #{dto.operateTimeStart} and #{dto.operateTimeEnd}
+        </if>
+        ORDER BY t1.id DESC
+    </select>
+</mapper>

+ 35 - 0
src/main/resources/mapper/student/StudentReportPlanMapper.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xjrsoft.module.student.mapper.StudentReportPlanMapper">
+    <select id="getPage" parameterType="com.xjrsoft.module.student.dto.StudentReportPlanPageDto" resultType="com.xjrsoft.module.student.vo.StudentReportPlanPageVo">
+        SELECT t1.id,t1.name,t3.name AS semester_name,t1.start_time,t1.end_time,
+        t1.update_end_time,t1.update_start_time,t1.status,t1.create_date,t1.semester_id,
+        t2.name AS create_user_name FROM student_report_plan t1
+        LEFT JOIN xjr_user t2 ON t1.create_user_id = t2.id
+        INNER JOIN base_semester t3 ON t1.semester_id = t3.id
+        WHERE t1.delete_mark = 0
+        <if test="dto.name != null and dto.name !=''">
+            and t1.name like concat('%', #{dto.name}, '%')
+        </if>
+        <if test="dto.semesterId != null">
+            and t1.semester_id = #{dto.semesterId}
+        </if>
+        <if test="dto.status != null">
+            and t1.status = #{dto.status}
+        </if>
+        order by t1.id desc
+    </select>
+    <select id="validateClass" resultType="com.xjrsoft.module.base.entity.BaseClass">
+        SELECT t1.* FROM base_class t1
+        INNER JOIN student_report_plan_class_relation t2 ON t1.id = t2.class_id
+        INNER JOIN student_report_plan t3 ON t2.student_report_plan_id = t3.id
+        WHERE t3.delete_mark = 0 AND NOW() BETWEEN t3.start_time AND t3.end_time
+        AND t3.id != #{id}
+        and t1.id in
+        <foreach item="classId" index="index" collection="classIds" open="(" close=")" separator=",">
+            #{classId}
+        </foreach>
+    </select>
+</mapper>

+ 121 - 0
src/main/resources/mapper/student/StudentReportRecordMapper.xml

@@ -30,6 +30,9 @@
         INNER JOIN student_report_record a3 ON a1.id = a3.user_id
         WHERE a1.delete_mark = 0 AND a2.delete_mark = 0 and a3.delete_mark = 0
         AND a2.class_id = t1.id AND a3.base_semester_id = #{dto.baseSemesterId} AND a3.report_time IS NOT NULL
+        <if test="dto.studentReportPlanId != null">
+            and a3.student_report_plan_id = #{dto.studentReportPlanId}
+        </if>
         ) AS arrived_count
         FROM base_class t1
         INNER JOIN xjr_user t2 ON t1.teacher_id = t2.id
@@ -54,6 +57,124 @@
         </if>
         ORDER BY t1.create_date DESC, t2.create_date DESC,t3.create_date DESC,t1.id
     </select>
+    <select id="getPlanPage" parameterType="com.xjrsoft.module.student.dto.StudentReportRecordPageDto" resultType="com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo">
+        SELECT t1.id, t1.user_id, t4.name AS grade_name,t5.name AS class_name,t6.name AS teacher_name,
+        t3.name,t7.name AS gender,t3.credential_number,t3.mobile,t8.name AS student_type_cn,
+        t9.name AS stduy_status_cn,t10.name AS archives_status_cn,
+        t1.report_time,IF(t1.report_time IS NULL, 0, 1) as is_report FROM student_report_record t1
+        INNER JOIN base_student_school_roll t2 ON t1.user_id = t2.user_id
+        INNER JOIN xjr_user t3 ON t3.id = t1.user_id
+        LEFT JOIN base_grade t4 ON t2.grade_id = t4.id
+        LEFT JOIN base_class t5 ON t2.class_id = t5.id
+        LEFT JOIN xjr_user t6 ON t5.teacher_id = t6.id
+        LEFT JOIN xjr_dictionary_detail t7 ON t3.gender = t7.code
+        LEFT JOIN xjr_dictionary_detail t8 ON t2.student_type = t8.code
+        LEFT JOIN xjr_dictionary_detail t9 ON t2.stduy_status = t9.code
+        LEFT JOIN xjr_dictionary_detail t10 ON t2.archives_status = t10.code
+        WHERE t1.delete_mark = 0 AND t1.enabled_mark = 1
+        and t1.student_report_plan_id = #{dto.studentReportPlanId}
+        <if test="dto.keyword != null and dto.keyword != ''">
+            and t1.name like concat('%', #{dto.keyword},'%')
+        </if>
+        <if test="dto.classId != null">
+            and t5.id = #{dto.classId}
+        </if>
+        <if test="dto.gradeId != null">
+            and t4.id = #{dto.gradeId}
+        </if>
+        <if test="dto.name != null and dto.name != ''">
+            and t3.name like concat('%', #{dto.name}, '%')
+        </if>
+        <if test="dto.className != null and dto.className != ''">
+            and t5.name like concat('%', #{dto.className}, '%')
+        </if>
+        <if test="dto.credentialNumber != null and dto.credentialNumber != ''">
+            and t3.credentialNumber like concat('%', #{dto.credentialNumber}, '%')
+        </if>
+        <if test="dto.archivesStatus != null and dto.archivesStatus != ''">
+            and t2.archives_status = #{dto.archivesStatus}
+        </if>
+        <if test="dto.stduyStatus != null and dto.stduyStatus != ''">
+            and t2.stduy_status = #{dto.stduyStatus}
+        </if>
+        <if test="dto.studentType != null and dto.studentType != ''">
+            and t2.student_type = #{dto.studentType}
+        </if>
+        <if test="dto.studentType != null and dto.studentType != ''">
+            and t2.student_type = #{dto.studentType}
+        </if>
+        <if test="dto.isReport != null">
+            <if test="dto.isReport == 1">
+                and t1.report_time is not null
+            </if>
+            <if test="dto.isReport == 0">
+                and t1.report_time is null
+            </if>
+        </if>
+        <if test="dto.reportTimeStart != null and dto.reportTimeEnd != null">
+            and t1.report_time between #{dto.reportTimeStart} and #{dto.reportTimeEnd}
+        </if>
+        ORDER BY t1.report_time IS NULL DESC, t1.report_time DESC
+    </select>
+    <select id="getPlanPageList" parameterType="com.xjrsoft.module.student.dto.StudentReportRecordPageDto" resultType="com.xjrsoft.module.student.vo.StudentReportRecordPlanPageVo">
+        SELECT t1.id, t1.user_id, t4.name AS grade_name,t5.name AS class_name,t6.name AS teacher_name,
+        t3.name,t7.name AS gender,t3.credential_number,t3.mobile,t8.name AS student_type_cn,
+        t9.name AS stduy_status_cn,t10.name AS archives_status_cn,
+        t1.report_time,IF(t1.report_time IS NULL, 0, 1) as is_report FROM student_report_record t1
+        INNER JOIN base_student_school_roll t2 ON t1.user_id = t2.user_id
+        INNER JOIN xjr_user t3 ON t3.id = t1.user_id
+        LEFT JOIN base_grade t4 ON t2.grade_id = t4.id
+        LEFT JOIN base_class t5 ON t2.class_id = t5.id
+        LEFT JOIN xjr_user t6 ON t5.teacher_id = t6.id
+        LEFT JOIN xjr_dictionary_detail t7 ON t3.gender = t7.code
+        LEFT JOIN xjr_dictionary_detail t8 ON t2.student_type = t8.code
+        LEFT JOIN xjr_dictionary_detail t9 ON t2.stduy_status = t9.code
+        LEFT JOIN xjr_dictionary_detail t10 ON t2.archives_status = t10.code
+        WHERE t1.delete_mark = 0 AND t1.enabled_mark = 1
+        and t1.student_report_plan_id = #{dto.studentReportPlanId}
+        <if test="dto.keyword != null and dto.keyword != ''">
+            and t1.name like concat('%', #{dto.keyword},'%')
+        </if>
+        <if test="dto.classId != null">
+            and t5.id = #{dto.classId}
+        </if>
+        <if test="dto.gradeId != null">
+            and t4.id = #{dto.gradeId}
+        </if>
+        <if test="dto.name != null and dto.name != ''">
+            and t3.name like concat('%', #{dto.name}, '%')
+        </if>
+        <if test="dto.className != null and dto.className != ''">
+            and t5.name like concat('%', #{dto.className}, '%')
+        </if>
+        <if test="dto.credentialNumber != null and dto.credentialNumber != ''">
+            and t3.credentialNumber like concat('%', #{dto.credentialNumber}, '%')
+        </if>
+        <if test="dto.archivesStatus != null and dto.archivesStatus != ''">
+            and t2.archives_status = #{dto.archivesStatus}
+        </if>
+        <if test="dto.stduyStatus != null and dto.stduyStatus != ''">
+            and t2.stduy_status = #{dto.stduyStatus}
+        </if>
+        <if test="dto.studentType != null and dto.studentType != ''">
+            and t2.student_type = #{dto.studentType}
+        </if>
+        <if test="dto.studentType != null and dto.studentType != ''">
+            and t2.student_type = #{dto.studentType}
+        </if>
+        <if test="dto.isReport != null">
+            <if test="dto.isReport == 1">
+                and t1.report_time is not null
+            </if>
+            <if test="dto.isReport == 0">
+                and t1.report_time is null
+            </if>
+        </if>
+        <if test="dto.reportTimeStart != null and dto.reportTimeEnd != null">
+            and t1.report_time between #{dto.reportTimeStart} and #{dto.reportTimeEnd}
+        </if>
+        ORDER BY t1.report_time IS NULL DESC, t1.report_time DESC
+    </select>
     <select id="getStatisticsDataList" parameterType="com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto"
             resultType="com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo">
         SELECT t1.name,t1.credential_number,t2.gender,t4.graduated_university,t4.stduy_status,t5.report_time ,

+ 10 - 0
src/main/resources/sqlScript/20250116_sql.sql

@@ -0,0 +1,10 @@
+ALTER TABLE `student_drop_out`   
+  ADD COLUMN `textbook_fees` VARCHAR(20) NULL   COMMENT '教材费缴费情况' AFTER `status`,
+  ADD COLUMN `homestay` VARCHAR(20) NULL   COMMENT '住宿费缴费情况' AFTER `textbook_fees`;
+
+
+ALTER TABLE `base_personnel_labour_capital`   
+  ADD COLUMN `category` INT NULL   COMMENT '类别(1:工资 2:社保)' AFTER `data_file`;
+
+ALTER TABLE `base_personnel_labour_capital`   
+  ADD COLUMN `year` INT NULL   COMMENT '社保年份' AFTER `category`;

+ 116 - 0
src/main/resources/sqlScript/20250120_sql.sql

@@ -0,0 +1,116 @@
+-- ----------------------------
+-- 2025-01-20 10:36
+-- 需要进行课程管理的班级
+-- ----------------------------
+drop table if exists base_class_admin_course;
+create table `base_class_admin_course`
+(
+    id                  bigint        not null comment '主键编号'
+        primary key,
+    create_user_id      bigint        null comment '创建人',
+    create_date         datetime      null comment '创建时间',
+    modify_user_id      bigint        null comment '修改人',
+    modify_date         datetime      null comment '修改时间',
+    delete_mark         int           not null comment '删除标记',
+    enabled_mark        int           not null comment '有效标志',
+    sort_code           int           null comment '序号',
+    remark              varchar(1000) null comment '备注',
+
+    class_id         bigint      null comment '班级id(base_class)',
+    base_semester_id bigint      null comment '学期id'
+) engine = innodb
+  default charset = utf8mb4
+  collate = utf8mb4_0900_ai_ci comment ='需要进行课程管理的班级';
+
+alter table base_class_course
+    modify class_id bigint null comment '需要进行课程管理的班级id(base_class_admin_course)(原有班级主键id字段)';
+
+alter table textbook_subscription_item
+    add use_class_num int default 0 null comment '在本次征订中本征订项的教材使用的班级数量';
+
+-- ----------------------------
+-- 2025-01-22 14:36
+-- 教材征订记录详情与班级关联表
+-- ----------------------------
+drop table if exists textbook_subscription_item_class;
+create table `textbook_subscription_item_class`
+(
+    id                       bigint        not null comment '主键编号'
+        primary key,
+    create_user_id           bigint        null comment '创建人',
+    create_date              datetime      null comment '创建时间',
+    modify_user_id           bigint        null comment '修改人',
+    modify_date              datetime      null comment '修改时间',
+    delete_mark              int           not null comment '删除标记',
+    enabled_mark             int           not null comment '有效标志',
+    sort_code                int           null comment '序号',
+    remark                   varchar(1000) null comment '备注',
+
+    textbook_subscription_item_id bigint        not null comment '教材征订记录详情表id(textbook_subscription)',
+    base_class_id            bigint        not null comment '按班级征订中征订的班级主键(base_class)'
+) engine = innodb
+  default charset = utf8mb4
+  collate = utf8mb4_0900_ai_ci comment ='教材征订记录详情与班级关联表';
+
+
+
+DROP TABLE IF EXISTS student_change_record;
+CREATE TABLE `student_change_record`  (
+  `id` BIGINT NOT NULL COMMENT '主键',
+  `create_user_id` BIGINT NULL DEFAULT NULL COMMENT '创建人',
+  `create_date` DATETIME(3) NULL DEFAULT NULL COMMENT '创建时间',
+  `modify_user_id` BIGINT NULL DEFAULT NULL COMMENT '修改人id',
+  `modify_date` DATETIME(3) NULL DEFAULT NULL COMMENT '修改日期',
+  `delete_mark` SMALLINT NULL DEFAULT NULL COMMENT '删除标记(0:未删除 1:已删除)',
+  `enabled_mark` SMALLINT NULL DEFAULT NULL COMMENT '有效标记(0:未启用 1:已启用)',
+  `user_id` BIGINT NULL DEFAULT NULL COMMENT '学生id(xjr_user)',
+  `change_type` VARCHAR(50) NULL DEFAULT NULL COMMENT '异动类型',
+  `before_data` VARCHAR(200) NULL DEFAULT NULL COMMENT '异动前数据',
+  `before_data_code` VARCHAR(200) NULL DEFAULT NULL COMMENT '异动前数据code',
+  `after_data` VARCHAR(200) NULL DEFAULT NULL COMMENT '异动后数据',
+  `after_data_code` VARCHAR(200) NULL DEFAULT NULL COMMENT '异动后数据code',
+  `operate_mode` INT NULL DEFAULT NULL COMMENT '操作方式(1:系统 2:流程 3:人为)',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '学生异动记录表';
+
+-- ---------------------------------------------------------------
+-- 学生报到计划
+-- ---------------------------------------------------------------
+DROP TABLE IF EXISTS student_report_plan;
+CREATE TABLE `student_report_plan`  (
+  `id` BIGINT NOT NULL COMMENT '主键',
+  `create_user_id` BIGINT NULL DEFAULT NULL COMMENT '创建人',
+  `create_date` DATETIME(3) NULL DEFAULT NULL COMMENT '创建时间',
+  `modify_user_id` BIGINT NULL DEFAULT NULL COMMENT '修改人id',
+  `modify_date` DATETIME(3) NULL DEFAULT NULL COMMENT '修改日期',
+  `delete_mark` SMALLINT NULL DEFAULT NULL COMMENT '删除标记(0:未删除 1:已删除)',
+  `enabled_mark` SMALLINT NULL DEFAULT NULL COMMENT '有效标记(0:未启用 1:已启用)',
+  `semester_id` BIGINT NULL DEFAULT NULL COMMENT '学期id(base_semester)',
+  `name` VARCHAR(100) NULL DEFAULT NULL COMMENT '计划名称',
+  `start_time` DATETIME NULL DEFAULT NULL COMMENT '报到开始时间',
+  `end_time` DATETIME NULL DEFAULT NULL COMMENT '报到结束时间',
+  `update_start_time` DATETIME NULL DEFAULT NULL COMMENT '数据修改开始时间',
+  `update_end_time` DATETIME NULL DEFAULT NULL COMMENT '数据修改结束时间',
+  `status` INT NULL DEFAULT 0 COMMENT '状态(0:草稿 1:进行中 2:已结束)',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '学生报到计划';
+
+
+
+-- ---------------------------------------------------------------
+-- 学生报到计划-班级
+-- ---------------------------------------------------------------
+DROP TABLE IF EXISTS student_report_plan_class_relation;
+CREATE TABLE `student_report_plan_class_relation`  (
+  `id` BIGINT NOT NULL COMMENT '主键',
+  `student_report_plan_id` BIGINT NULL DEFAULT NULL COMMENT '计划id',
+  `class_id` BIGINT NULL DEFAULT NULL COMMENT '班级id',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '学生报到计划-班级';
+
+ALTER TABLE `student_report_record`
+  ADD COLUMN `student_report_plan_id` BIGINT NULL   COMMENT '报到计划id' AFTER `base_semester_id`;
+
+alter table textbook_subscription_item
+    add class_ids varchar(1024) null comment '按班级征订当前征订项的的教材使用的班级的主键';
+

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor