Browse Source

Merge remote-tracking branch 'origin/dev' into pre

dzx 6 months ago
parent
commit
680e9e7b41
44 changed files with 1516 additions and 209 deletions
  1. 2 0
      src/main/java/com/xjrsoft/common/enums/RoleEnum.java
  2. 12 5
      src/main/java/com/xjrsoft/config/JacksonConfig.java
  3. 1 0
      src/main/java/com/xjrsoft/module/banding/service/impl/BandingTaskClassServiceImpl.java
  4. 52 0
      src/main/java/com/xjrsoft/module/base/service/impl/BaseClassMergeServiceImpl.java
  5. 1 1
      src/main/java/com/xjrsoft/module/databoard/controller/DataboardController.java
  6. 11 2
      src/main/java/com/xjrsoft/module/hikvision/controller/OutInController.java
  7. 10 3
      src/main/java/com/xjrsoft/module/oa/utils/SendMessageUtil.java
  8. 12 0
      src/main/java/com/xjrsoft/module/organization/controller/UserController.java
  9. 3 0
      src/main/java/com/xjrsoft/module/organization/vo/PendingCountDto.java
  10. 20 2
      src/main/java/com/xjrsoft/module/student/controller/BaseStudentScholarshipReleaseController.java
  11. 2 0
      src/main/java/com/xjrsoft/module/student/service/IBaseStudentScholarshipApplicantService.java
  12. 38 1
      src/main/java/com/xjrsoft/module/student/service/impl/BaseStudentScholarshipApplicantServiceImpl.java
  13. 3 0
      src/main/java/com/xjrsoft/module/student/service/impl/BaseStudentScholarshipReleaseServiceImpl.java
  14. 47 2
      src/main/java/com/xjrsoft/module/textbook/controller/TextbookStudentClaimController.java
  15. 17 0
      src/main/java/com/xjrsoft/module/textbook/dto/AllStuClaimExportQueryDto.java
  16. 29 0
      src/main/java/com/xjrsoft/module/textbook/dto/HeadTeaLookClassBookSemesterDto.java
  17. 5 1
      src/main/java/com/xjrsoft/module/textbook/dto/SubscriptionItemListDistributeDto.java
  18. 1 1
      src/main/java/com/xjrsoft/module/textbook/dto/TeacherCheckByclassDto.java
  19. 3 0
      src/main/java/com/xjrsoft/module/textbook/dto/UpdateDiscountDto.java
  20. 10 2
      src/main/java/com/xjrsoft/module/textbook/entity/TextbookDiscountAlterRecord.java
  21. 5 2
      src/main/java/com/xjrsoft/module/textbook/entity/TextbookStudentClaim.java
  22. 12 1
      src/main/java/com/xjrsoft/module/textbook/service/ITextbookStudentClaimService.java
  23. 2 1
      src/main/java/com/xjrsoft/module/textbook/service/IWfTextbookClaimService.java
  24. 22 7
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookIssueRecordServiceImpl.java
  25. 1 0
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookServiceImpl.java
  26. 90 25
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookStudentClaimServiceImpl.java
  27. 29 10
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookSubscriptionServiceImpl.java
  28. 96 26
      src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookWarehouseRecordServiceImpl.java
  29. 725 74
      src/main/java/com/xjrsoft/module/textbook/service/impl/WfTextbookClaimServiceImpl.java
  30. 100 0
      src/main/java/com/xjrsoft/module/textbook/vo/AllStuClaimExportQueryVo.java
  31. 46 2
      src/main/java/com/xjrsoft/module/textbook/vo/ClaimRecordsExportQueryVo.java
  32. 3 0
      src/main/java/com/xjrsoft/module/textbook/vo/ClassClaimTextbookIssuePrice.java
  33. 4 0
      src/main/java/com/xjrsoft/module/textbook/vo/DistributePageVo.java
  34. 16 1
      src/main/java/com/xjrsoft/module/textbook/vo/DistributeRecordVo.java
  35. 11 4
      src/main/java/com/xjrsoft/module/textbook/vo/TextbookDiscountAlterRecordListVo.java
  36. 11 5
      src/main/java/com/xjrsoft/module/textbook/vo/WfTextbookClaimItemVo.java
  37. 3 4
      src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java
  38. 1 1
      src/main/resources/application-prod.yml
  39. 8 0
      src/main/resources/mapper/oa/OfficialDocumentReceivedHandleMapper.xml
  40. 8 24
      src/main/resources/mapper/textbook/TextbookStudentClaimMapper.xml
  41. 11 0
      src/main/resources/sqlScript/20250603sql.sql
  42. 5 0
      src/main/resources/sqlScript/20250612sql.sql
  43. 24 0
      src/test/java/com/xjrsoft/module/hikvision/controller/OutInControllerTest.java
  44. 4 2
      src/test/java/com/xjrsoft/xjrsoftboot/StringTest.java

+ 2 - 0
src/main/java/com/xjrsoft/common/enums/RoleEnum.java

@@ -23,6 +23,8 @@ public enum RoleEnum {
     PARENT(4L, "家长"),
     VISITOR(5L, "访客"),
 
+    BOOKADMIN(1747874695055732738L, "教材管理员"),
+
     CLASSTE(1745630294430511106L, "班主任");
 
     final Long code;

+ 12 - 5
src/main/java/com/xjrsoft/config/JacksonConfig.java

@@ -9,10 +9,8 @@ import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.module.SimpleModule;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
 import com.xjrsoft.common.handler.EasyExcelLocalDateTimeConverter;
@@ -53,7 +51,15 @@ public class JacksonConfig {
         return builder -> {
             builder.serializerByType(Long.class, ToStringSerializer.instance);
             builder.serializerByType(Long.TYPE, ToStringSerializer.instance);
-            builder.serializerByType(BigDecimal.class, ToStringSerializer.instance);
+
+            // 自定义 BigDecimal 序列化器,使用 toPlainString()
+            builder.serializerByType(BigDecimal.class, new JsonSerializer<BigDecimal>() {
+                @Override
+                public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+                    gen.writeString(value.stripTrailingZeros().toPlainString());
+                }
+            });
+
             builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
             builder.serializerByType(INTERVALDS.class, intervalDSSerializer());
             builder.deserializerByType(LocalDateTime.class, localDateTimeDeserializer());
@@ -143,4 +149,5 @@ public class JacksonConfig {
             }
         };
     }
+
 }

+ 1 - 0
src/main/java/com/xjrsoft/module/banding/service/impl/BandingTaskClassServiceImpl.java

@@ -491,6 +491,7 @@ public class BandingTaskClassServiceImpl extends MPJBaseServiceImpl<BandingTaskC
             one.setClassroomId(baseClass.getClassroomId());
             one.setDeleteMark(DeleteMark.NODELETE.getCode());
             one.setCreateDate(new Date());
+            one.setBaseClassId(baseClass.getId());
             one.setEnabledMark(EnabledMark.ENABLED.getCode());
             one.setName(baseClass.getName());
             one.setCreateUserId(StpUtil.getLoginIdAsLong());

+ 52 - 0
src/main/java/com/xjrsoft/module/base/service/impl/BaseClassMergeServiceImpl.java

@@ -1,28 +1,39 @@
 package com.xjrsoft.module.base.service.impl;
 
 import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.ArchivesStatusEnum;
 import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.common.enums.StudentChangeTypeEnum;
 import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.base.dto.BaseClassMergeStudentPageDto;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.entity.BaseClassMerge;
 import com.xjrsoft.module.base.entity.BaseClassMergeStudent;
+import com.xjrsoft.module.base.entity.BaseSystemConfig;
 import com.xjrsoft.module.base.mapper.BaseClassMapper;
 import com.xjrsoft.module.base.mapper.BaseClassMergeMapper;
 import com.xjrsoft.module.base.mapper.BaseClassMergeStudentMapper;
 import com.xjrsoft.module.base.service.IBaseClassMergeService;
+import com.xjrsoft.module.base.service.IBaseSystemConfigService;
 import com.xjrsoft.module.base.vo.BaseClassMergeStudentVo;
 import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
+import com.xjrsoft.module.student.entity.StudentChangeClass;
 import com.xjrsoft.module.student.mapper.BaseStudentSchoolRollMapper;
+import com.xjrsoft.module.student.mapper.StudentChangeClassMapper;
 import com.xjrsoft.module.student.service.IStudentChangeRecordService;
+import com.xjrsoft.module.workflow.entity.WorkflowFormRelation;
 import lombok.AllArgsConstructor;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -47,6 +58,8 @@ public class BaseClassMergeServiceImpl extends MPJBaseServiceImpl<BaseClassMerge
     private final BaseClassMapper baseClassMapper;
     private final BaseStudentSchoolRollMapper schoolRollMapper;
     private final IStudentChangeRecordService changeRecordService;
+    private final IBaseSystemConfigService systemConfigService;
+    private final StudentChangeClassMapper studentChangeClassMapper;
 
 
     @Override
@@ -56,6 +69,45 @@ public class BaseClassMergeServiceImpl extends MPJBaseServiceImpl<BaseClassMerge
         if(collect.contains(baseClassMerge.getTargetClassId())){
             throw new MyException("原有班级中不能包含目标班级,请重新选择原有班级");
         }
+
+        BaseSystemConfig classNumberMax = systemConfigService.getOne(
+                new QueryWrapper<BaseSystemConfig>().lambda()
+                        .eq(BaseSystemConfig::getCode, "classNumberMax")
+        );
+        if(classNumberMax != null){
+            int classNumberMaxNum = Integer.parseInt(classNumberMax.getValue());
+            Integer actualStudentCount = schoolRollMapper.selectJoinCount(
+                    new MPJLambdaWrapper<BaseStudentSchoolRoll>()
+                            .distinct()
+                            .select(BaseStudentSchoolRoll::getUserId)
+                            .innerJoin(User.class, User::getId, BaseStudentSchoolRoll::getUserId)
+                            .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
+                            .eq(BaseStudentSchoolRoll::getEnabledMark, EnabledMark.ENABLED.getCode())
+                            .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+                            .eq(BaseStudentSchoolRoll::getClassId, baseClassMerge.getTargetClassId())
+            );
+
+            Integer count = studentChangeClassMapper.selectJoinCount(
+                    new MPJLambdaWrapper<StudentChangeClass>()
+                            .distinct()
+                            .select(StudentChangeClass::getStudentUserId)
+                            .innerJoin(WorkflowFormRelation.class, WorkflowFormRelation::getFormKeyValue, StudentChangeClass::getId)
+                            .eq(WorkflowFormRelation::getCurrentState, HistoricProcessInstance.STATE_ACTIVE)
+            );
+
+            String sql = "SELECT DISTINCT student_user_id FROM temporary_change_class t1" +
+                    " INNER JOIN xjr_workflow_form_relation t2 ON t1.id = CAST(t2.form_key_value AS SIGNED)" +
+                    " WHERE t1.delete_mark = 0 AND t2.current_state = 'ACTIVE'";
+            List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+
+            int classCount = actualStudentCount + count + list.size();
+            int difference  = classCount - classNumberMaxNum;
+            int absoluteValue = (difference < 0) ? -difference : difference;
+            if(baseClassMerge.getBaseClassMergeStudentList().size() > absoluteValue){
+                throw new MyException("转入班级的人数大于班级剩余空位,该班级剩余" + absoluteValue + "人");
+            }
+        }
+
         baseClassMerge.setStudentCount(baseClassMerge.getBaseClassMergeStudentList().size());
         this.baseMapper.insert(baseClassMerge);
         BaseClass baseClass = baseClassMapper.selectById(baseClassMerge.getTargetClassId());

+ 1 - 1
src/main/java/com/xjrsoft/module/databoard/controller/DataboardController.java

@@ -398,7 +398,7 @@ public class DataboardController {
             if(i == 1){
                 item = "市外";
             }else{
-                item = "内";
+                item = "内";
             }
             Double amount = 0D;
             for (Map<String, Object> objectMap : list) {

+ 11 - 2
src/main/java/com/xjrsoft/module/hikvision/controller/OutInController.java

@@ -5,6 +5,7 @@ import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.google.gson.*;
 import com.xjrsoft.common.annotation.XjrLog;
+import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.module.hikvision.dto.HikvisionCarOutinPageDto;
@@ -62,7 +63,11 @@ public class OutInController {
 
         String doPost = apiUtil.doPost(apiPath, paramJson.toString(), null);
         JsonParser parser = new JsonParser();
-        JsonObject data = parser.parse(doPost).getAsJsonObject().get("data").getAsJsonObject();
+        JsonObject resultJson = parser.parse(doPost).getAsJsonObject();
+        if(!"0".equals(resultJson.get("code").getAsString())){
+            throw new MyException(resultJson.get("msg").getAsString());
+        }
+        JsonObject data = resultJson.get("data").getAsJsonObject();
         JsonArray list = data.get("list").getAsJsonArray();
         List<HikvisionOutinPageVo> result = new ArrayList<>();
         Gson gson = new Gson();
@@ -118,7 +123,11 @@ public class OutInController {
 
         String doPost = apiUtil.doPost(apiPath, paramJson.toString(), null);
         JsonParser parser = new JsonParser();
-        JsonObject data = parser.parse(doPost).getAsJsonObject().get("data").getAsJsonObject();
+        JsonObject resultJson = parser.parse(doPost).getAsJsonObject();
+        if(!"0".equals(resultJson.get("code").getAsString())){
+            throw new MyException(resultJson.get("msg").getAsString());
+        }
+        JsonObject data = resultJson.get("data").getAsJsonObject();
         JsonArray list = data.get("list").getAsJsonArray();
         List<HikvisionCarOutinPageVo> result = new ArrayList<>();
         Gson gson = new Gson();

+ 10 - 3
src/main/java/com/xjrsoft/module/oa/utils/SendMessageUtil.java

@@ -101,9 +101,16 @@ public class SendMessageUtil {
                     put("value", param.getSchemaName());
                 }});
                 // 事项名称
-                data.put("thing2", new JSONObject() {{
-                    put("value", name);
-                }});
+                if(StrUtil.isNotEmpty(name) && name.length() > 16){
+                    data.put("thing2", new JSONObject() {{
+                        put("value", name.substring(0, 15));
+                    }});
+                }else{
+                    data.put("thing2", new JSONObject() {{
+                        put("value", name.substring(0, 15));
+                    }});
+                }
+
                 // 申请人
                 data.put("thing6", new JSONObject() {{
                     put("value", param.getStartUserName());

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

@@ -35,6 +35,9 @@ import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseGradeService;
 import com.xjrsoft.module.base.service.IWhitelistManagementService;
 import com.xjrsoft.module.hikvision.util.DataUtil;
+import com.xjrsoft.module.oa.dto.OfficialDocumentReceivedHandlePageDto;
+import com.xjrsoft.module.oa.service.IOfficialDocumentReceivedHandleService;
+import com.xjrsoft.module.oa.vo.OfficialDocumentReceivedHandlePageVo;
 import com.xjrsoft.module.organization.dto.*;
 import com.xjrsoft.module.organization.entity.*;
 import com.xjrsoft.module.organization.service.*;
@@ -125,6 +128,7 @@ public class UserController {
     private final IBaseNewStudentService baseNewStudentService;
 
     private final IWorkflowExtraService workflowExtraService;
+    private final IOfficialDocumentReceivedHandleService documentReceivedHandleService;
 
     @GetMapping(value = "/list")
     @ApiOperation(value = "用户列表(不分页)")
@@ -462,6 +466,14 @@ public class UserController {
                         .leftJoin(WorkflowSchema.class, WorkflowSchema::getId, WorkflowCirculated::getSchemaId)
         );
         pendingCountDto.setCirculatedCount(circulatedCount);
+
+        //增加查询收文承办数量
+        OfficialDocumentReceivedHandlePageDto dto = new OfficialDocumentReceivedHandlePageDto();
+        dto.setLoginUserId(StpUtil.getLoginIdAsLong());
+        dto.setIsHandle(0);
+        Page<OfficialDocumentReceivedHandlePageVo> page = documentReceivedHandleService.getPage(new Page<>(1, 15), dto);
+        pendingCountDto.setDocumentReceivedHandleCount(page.getTotal());
+
         return RT.ok(pendingCountDto);
     }
 

+ 3 - 0
src/main/java/com/xjrsoft/module/organization/vo/PendingCountDto.java

@@ -21,4 +21,7 @@ public class PendingCountDto implements Serializable {
 
     @ApiModelProperty("我的传阅数量")
     private long circulatedCount;
+
+    @ApiModelProperty("我的承办数量")
+    private long documentReceivedHandleCount;
 }

+ 20 - 2
src/main/java/com/xjrsoft/module/student/controller/BaseStudentScholarshipReleaseController.java

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.annotation.XjrLog;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
@@ -34,6 +36,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @title: 奖学金发放记录表
@@ -103,12 +106,27 @@ public class BaseStudentScholarshipReleaseController {
     @SaCheckPermission("basestudentscholarshiprelease:add")
     @XjrLog(value = "新增奖学金发放记录表", saveResponseData = true)
     public RT<Boolean> add(@Valid @RequestBody AddBaseStudentScholarshipReleaseDto dto) {
+        //查询已发放的金额
+        List<BaseStudentScholarshipRelease> releaseList = releaseService.list(
+                new QueryWrapper<BaseStudentScholarshipRelease>().lambda()
+                        .eq(BaseStudentScholarshipRelease::getBaseStudentScholarshipApplicantId, dto.getBaseStudentScholarshipApplicantId())
+                        .eq(BaseStudentScholarshipRelease::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        .eq(BaseStudentScholarshipRelease::getEnabledMark, EnabledMark.ENABLED.getCode())
+        );
+
+        double releaseAmount = releaseList.stream().mapToDouble(BaseStudentScholarshipRelease::getAmount).sum();
+
         BaseStudentScholarshipApplicant applicant = applicantService.getById(dto.getBaseStudentScholarshipApplicantId());
-        if (dto.getAmount() > applicant.getAmount()) {
-            return RT.error("发放金额不能大于获奖金额");
+        if(releaseAmount == applicant.getAmount()){
+            return RT.error("已发放足够金额,无法再发放");
+        }
+        double v = applicant.getAmount() - releaseAmount;
+        if (dto.getAmount() > v) {
+            return RT.error("发放金额不能大于" + v);
         }
         BaseStudentScholarshipRelease baseStudentScholarshipRelease = BeanUtil.toBean(dto, BaseStudentScholarshipRelease.class);
         boolean isSuccess = releaseService.save(baseStudentScholarshipRelease);
+        applicantService.updateReleaseStatus(applicant);
         return RT.ok(isSuccess);
     }
 

+ 2 - 0
src/main/java/com/xjrsoft/module/student/service/IBaseStudentScholarshipApplicantService.java

@@ -37,4 +37,6 @@ public interface IBaseStudentScholarshipApplicantService extends MPJBaseService<
     Page<BaseStudentScholarshipApplicantCategoryPageVo> getScholarshiPage(Page<BaseStudentScholarshipApplicantCategoryPageDto> page, BaseStudentScholarshipApplicantCategoryPageDto dto);
 
     List<Map<String, String>> importData(MultipartFile file) throws IOException;
+
+    Boolean updateReleaseStatus(BaseStudentScholarshipApplicant scholarshipApplicant);
 }

+ 38 - 1
src/main/java/com/xjrsoft/module/student/service/impl/BaseStudentScholarshipApplicantServiceImpl.java

@@ -15,8 +15,10 @@ import com.xjrsoft.module.organization.service.IUserService;
 import com.xjrsoft.module.student.dto.BaseStudentScholarshipApplicantCategoryPageDto;
 import com.xjrsoft.module.student.entity.BaseStudentScholarshipApplicant;
 import com.xjrsoft.module.student.entity.BaseStudentScholarshipCategory;
+import com.xjrsoft.module.student.entity.BaseStudentScholarshipRelease;
 import com.xjrsoft.module.student.mapper.BaseStudentMapper;
 import com.xjrsoft.module.student.mapper.BaseStudentScholarshipApplicantMapper;
+import com.xjrsoft.module.student.mapper.BaseStudentScholarshipReleaseMapper;
 import com.xjrsoft.module.student.service.IBaseStudentScholarshipApplicantService;
 import com.xjrsoft.module.student.service.IBaseStudentScholarshipCategoryService;
 import com.xjrsoft.module.student.vo.BaseStudentScholarshipApplicantCategoryPageVo;
@@ -25,13 +27,16 @@ import com.xjrsoft.module.student.vo.ScholarshipApplicantImportVo;
 import com.xjrsoft.module.student.vo.StudentInfoVo;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -49,6 +54,7 @@ public class BaseStudentScholarshipApplicantServiceImpl extends MPJBaseServiceIm
     private final IUserService userService;
     private final BaseStudentScholarshipApplicantMapper scholarshipApplicantMapper;
     private final BaseStudentMapper studentMapper;
+    private final BaseStudentScholarshipReleaseMapper releaseMapper;
 
     @Override
     public Page<BaseStudentScholarshipApplicantCategoryPageVo> getScholarshiPage(Page<BaseStudentScholarshipApplicantCategoryPageDto> page, BaseStudentScholarshipApplicantCategoryPageDto dto) {
@@ -110,7 +116,7 @@ public class BaseStudentScholarshipApplicantServiceImpl extends MPJBaseServiceIm
         List<Map<String, String>> errorList = new ArrayList<>();
         List<BaseStudentScholarshipApplicant> updateList = new ArrayList<>();
         for (ScholarshipApplicantImportVo importVo : dataList) {
-            List<String> errorMsg = new ArrayList<>();
+            Set<String> errorMsg = new HashSet<>();
             if (StrUtil.isEmpty(importVo.getSemesterName()) || StrUtil.isEmpty(importVo.getName()) || StrUtil.isEmpty(importVo.getCredentialNumber())
                     || StrUtil.isEmpty(importVo.getScholarshipCategoryName()) || importVo.getScholarshipLevel() == null) {
                 errorMsg.add("有未填写的列");
@@ -134,6 +140,8 @@ public class BaseStudentScholarshipApplicantServiceImpl extends MPJBaseServiceIm
                     applicant.setAmount(category.getTotalAmount());
                     applicant.setScholarshipLevel(importVo.getScholarshipLevel());
                     updateList.add(applicant);
+                }else{
+                    errorMsg.add("身份信息匹配不上");
                 }
             }
             if (!errorMsg.isEmpty()) {
@@ -152,4 +160,33 @@ public class BaseStudentScholarshipApplicantServiceImpl extends MPJBaseServiceIm
         }
         return errorList;
     }
+
+    /**
+     * 每次发放时根据已经发放的金额判断这次申请的发放状态
+     * @param scholarshipApplicant
+     * @return
+     */
+    @Override
+    @Transactional
+    public Boolean updateReleaseStatus(BaseStudentScholarshipApplicant scholarshipApplicant) {
+        List<BaseStudentScholarshipRelease> releaseList = releaseMapper.selectList(
+                new QueryWrapper<BaseStudentScholarshipRelease>().lambda()
+                        .eq(BaseStudentScholarshipRelease::getDeleteMark, DeleteMark.NODELETE.getCode())
+                        .eq(BaseStudentScholarshipRelease::getBaseStudentScholarshipApplicantId, scholarshipApplicant.getId())
+        );
+        if(releaseList.isEmpty()){
+            scholarshipApplicant.setReleaseStatus(0);
+        }
+        double sum = releaseList.stream().filter(x -> x.getAmount() != null).mapToDouble(BaseStudentScholarshipRelease::getAmount).sum();
+        if(sum == 0){
+            scholarshipApplicant.setReleaseStatus(0);
+        }else if(sum < scholarshipApplicant.getAmount()){
+            scholarshipApplicant.setReleaseStatus(1);
+        }else if(sum == scholarshipApplicant.getAmount()){
+            scholarshipApplicant.setReleaseStatus(2);
+        }
+
+        this.updateById(scholarshipApplicant);
+        return true;
+    }
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/student/service/impl/BaseStudentScholarshipReleaseServiceImpl.java

@@ -8,6 +8,7 @@ import com.xjrsoft.module.student.entity.BaseStudentScholarshipApplicant;
 import com.xjrsoft.module.student.entity.BaseStudentScholarshipRelease;
 import com.xjrsoft.module.student.mapper.BaseStudentScholarshipApplicantMapper;
 import com.xjrsoft.module.student.mapper.BaseStudentScholarshipReleaseMapper;
+import com.xjrsoft.module.student.service.IBaseStudentScholarshipApplicantService;
 import com.xjrsoft.module.student.service.IBaseStudentScholarshipReleaseService;
 import com.xjrsoft.module.student.vo.BaseStudentScholarshipReleasePageVo;
 import lombok.AllArgsConstructor;
@@ -25,6 +26,7 @@ import java.util.List;
 @AllArgsConstructor
 public class BaseStudentScholarshipReleaseServiceImpl extends MPJBaseServiceImpl<BaseStudentScholarshipReleaseMapper, BaseStudentScholarshipRelease> implements IBaseStudentScholarshipReleaseService {
     private BaseStudentScholarshipApplicantMapper applicantMapper;
+    private final IBaseStudentScholarshipApplicantService applicantService;
 
     @Override
     public Page<BaseStudentScholarshipReleasePageVo> getPage(Page<BaseStudentScholarshipReleasePageVo> page, BaseStudentScholarshipReleasePageDto dto) {
@@ -39,6 +41,7 @@ public class BaseStudentScholarshipReleaseServiceImpl extends MPJBaseServiceImpl
             updateWrapper.eq("id", applicant.getId());
             updateWrapper.setSql("review_status = 0");
             applicantMapper.update(applicant, updateWrapper);
+            applicantService.updateReleaseStatus(applicant);
         }
 
         return this.removeBatchByIds(ids);

+ 47 - 2
src/main/java/com/xjrsoft/module/textbook/controller/TextbookStudentClaimController.java

@@ -1,17 +1,22 @@
 package com.xjrsoft.module.textbook.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.annotation.XjrLog;
+import com.xjrsoft.common.enums.DeleteMark;
 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.BaseCourseSubject;
 import com.xjrsoft.module.base.entity.CourseSubjectDetail;
+import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
 import com.xjrsoft.module.textbook.dto.*;
 import com.xjrsoft.module.textbook.entity.Textbook;
@@ -21,9 +26,14 @@ import com.xjrsoft.module.textbook.vo.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
@@ -39,13 +49,35 @@ import java.util.List;
 public class TextbookStudentClaimController {
 
     private final ITextbookStudentClaimService textbookStudentClaimService;
+    private final IBaseClassService baseClassService;
 
     @GetMapping(value = "/head-tea-look-class-book-semester")
     @ApiOperation(value = "班主任查看班级教材学期页面")
     @SaCheckPermission("textbookstudentclaim:detail")
     @XjrLog(value = "班主任查看班级教材学期页面")
-    public RT<List<HeadTeaLookClassBookSemesterVo>> headTeaLookClassBookSemester() {
-        return RT.ok(textbookStudentClaimService.headTeaLookClassBookSemester());
+    public RT<PageOutput<HeadTeaLookClassBookSemesterVo>> headTeaLookClassBookSemester(@Valid HeadTeaLookClassBookSemesterDto dto) {
+        IPage<HeadTeaLookClassBookSemesterVo> page = textbookStudentClaimService.headTeaLookClassBookSemester(dto);
+        PageOutput<HeadTeaLookClassBookSemesterVo> pageOutput = ConventPage.getPageOutput(page, HeadTeaLookClassBookSemesterVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/class-list")
+    @ApiOperation(value = "获取班主任管理的班级")
+    @SaCheckPermission("textbookstudentclaim:detail")
+    @XjrLog(value = "获取班主任管理的班级")
+    public RT<List<BaseClass>> classList() {
+        // 教材管理员获取所有班级,班主任只获取当前管理班级
+        LambdaQueryWrapper<BaseClass> baseClassLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        baseClassLambdaQueryWrapper
+                .eq(BaseClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+                ;
+        if(!StpUtil.hasRole("BOOKAdmin")) {
+            baseClassLambdaQueryWrapper
+                    .eq(BaseClass::getTeacherId, StpUtil.getLoginIdAsLong());
+        }
+
+        List<BaseClass> baseClasses = baseClassService.list(baseClassLambdaQueryWrapper);
+        return RT.ok(baseClasses);
     }
 
     @GetMapping(value = "/head-tea-look-class-book")
@@ -217,4 +249,17 @@ public class TextbookStudentClaimController {
     public RT<Boolean> delete(@Valid @RequestBody List<Long> ids) {
         return RT.ok(textbookStudentClaimService.removeBatchByIds(ids));
     }
+
+    @PostMapping("/all-stu-claim-export-query")
+    @ApiOperation(value = "某一学期全校学生领取记录条件导出")
+    @XjrLog(value = "某一学期全校学生领取记录条件导出")
+    public ResponseEntity<byte[]> allStuClaimExportQuery(@Valid @RequestBody AllStuClaimExportQueryDto dto) throws IOException {
+//    @GetMapping("/all-stu-claim-export-query")
+//    @ApiOperation(value = "全校学生领取记录条件导出")
+//    public ResponseEntity<byte[]> allStuClaimExportQuery(@Valid AllStuClaimExportQueryDto dto) throws IOException {
+        ByteArrayOutputStream bot = textbookStudentClaimService.allStuClaimExportQuery(dto);
+        String fileName = "某一学期全校学生领取记录条件导出";
+        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
+        return RT.fileStream(bot.toByteArray(), fileName + ExcelTypeEnum.XLSX.getValue());
+    }
 }

+ 17 - 0
src/main/java/com/xjrsoft/module/textbook/dto/AllStuClaimExportQueryDto.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.textbook.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class AllStuClaimExportQueryDto {
+
+    @ApiModelProperty("学期主键编号")
+    private String baseSemesterId;
+
+    @ApiModelProperty("班级主键编号")
+    private String classId;
+
+    @ApiModelProperty("学生主键编号")
+    private String userId;
+}

+ 29 - 0
src/main/java/com/xjrsoft/module/textbook/dto/HeadTeaLookClassBookSemesterDto.java

@@ -0,0 +1,29 @@
+package com.xjrsoft.module.textbook.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+ * @title: 班主任查看班级教材学期页面入参
+ * @Author szs
+ * @Date: 2025-06-11
+ * @Version 1.0
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class HeadTeaLookClassBookSemesterDto extends PageInput {
+    @ApiModelProperty("学期主键编号")
+    private String baseSemesterId;
+
+    @ApiModelProperty("学期主键编号")
+    private String baseSemesterIdCn;
+
+    @ApiModelProperty("班级主键编号")
+    private String baseClassId;
+
+    @ApiModelProperty("班级主键编号")
+    private String baseClassIdCn;
+}

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

@@ -20,5 +20,9 @@ public class SubscriptionItemListDistributeDto {
      */
     @ApiModelProperty("教材管理编号")
     private Long textbookId;
-
+    /**
+     * 班级管理编号
+     */
+    @ApiModelProperty("班级管理编号")
+    private Long classId;
 }

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

@@ -25,7 +25,7 @@ public class TeacherCheckByclassDto extends PageInput {
      * 班级编号
      */
     @ApiModelProperty(value = "班级编号")
-    private List<Long> classIdList;
+    private Long classId;
     /**
      * 领取情况(1=全部数据,2=该教材全部领取,3=该教材部分未领取)
      */

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

@@ -18,4 +18,7 @@ public class UpdateDiscountDto {
 
     @ApiModelProperty("新的折扣")
     private Double discount;
+
+    @ApiModelProperty("新的入库数量")
+    private int warehouseNumber;
 }

+ 10 - 2
src/main/java/com/xjrsoft/module/textbook/entity/TextbookDiscountAlterRecord.java

@@ -96,6 +96,14 @@ public class TextbookDiscountAlterRecord implements Serializable {
      */
     @ApiModelProperty("新的折扣")
     private Double newDiscount;
-
-
+    /**
+     * 旧的入库数量
+     */
+    @ApiModelProperty("旧的入库数量")
+    private Integer oldWarehouseNum;
+    /**
+     * 新的入库数量
+     */
+    @ApiModelProperty("新的入库数量")
+    private Integer newWarehouseNum;
 }

+ 5 - 2
src/main/java/com/xjrsoft/module/textbook/entity/TextbookStudentClaim.java

@@ -91,6 +91,11 @@ public class TextbookStudentClaim implements Serializable {
      */
     @ApiModelProperty("教材管理编号")
     private Long textbookId;
+    /**
+     * 关联入库主键
+     */
+    @ApiModelProperty("关联入库主键")
+    private Long textbookWarehouseRecordId;
     /**
      * 教材确认领取的价格
      */
@@ -111,6 +116,4 @@ public class TextbookStudentClaim implements Serializable {
      */
     @ApiModelProperty("备注")
     private String remark;
-
-
 }

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

@@ -5,7 +5,10 @@ import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.textbook.dto.*;
 import com.xjrsoft.module.textbook.entity.TextbookStudentClaim;
 import com.xjrsoft.module.textbook.vo.*;
+import org.springframework.web.bind.annotation.RequestBody;
 
+import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
 import java.util.List;
 
 /**
@@ -30,7 +33,7 @@ public interface ITextbookStudentClaimService extends MPJBaseService<TextbookStu
      * @param
      * @return
      */
-    List<HeadTeaLookClassBookSemesterVo> headTeaLookClassBookSemester();
+    IPage<HeadTeaLookClassBookSemesterVo> headTeaLookClassBookSemester(HeadTeaLookClassBookSemesterDto dto);
 
     /**
      * 获取页面
@@ -94,4 +97,12 @@ public interface ITextbookStudentClaimService extends MPJBaseService<TextbookStu
     Boolean studentConfirm(StudentConfirmDto dto);
 
     List<TeacherConfirmBatchTextbookListVo> teacherConfirmBatchTextbookList(TeacherConfirmBatchTextbookListDto dto);
+
+    /**
+     * 某一学期全校学生领取记录条件导出
+     *
+     * @param dto
+     * @return
+     */
+    ByteArrayOutputStream allStuClaimExportQuery(AllStuClaimExportQueryDto dto) ;
 }

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

@@ -10,6 +10,7 @@ import com.xjrsoft.module.textbook.vo.WfTextbookClaimPageVo;
 import com.xjrsoft.module.textbook.vo.WfTextbookClaimVo;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -77,5 +78,5 @@ public interface IWfTextbookClaimService extends MPJBaseService<WfTextbookClaim>
 
     Boolean dataHandleAddClaimUserNode(Long id);
 
-    ByteArrayOutputStream claimRecordsExportQuery(ClaimRecordsExportQueryDto dto);
+    ByteArrayOutputStream claimRecordsExportQuery(ClaimRecordsExportQueryDto dto) throws IOException;
 }

+ 22 - 7
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookIssueRecordServiceImpl.java

@@ -128,8 +128,19 @@ public class TextbookIssueRecordServiceImpl extends MPJBaseServiceImpl<TextbookI
                 .eq(ObjectUtils.isNotEmpty(dto.getReturnState()) && dto.getReturnState() == 0, TextbookIssueRecord::getRecedeNumber, 0)
                 .orderByDesc(TextbookIssueRecord::getCreateDate)
         ;
-
-        return textbookIssueRecordMapper.selectJoinPage(ConventPage.getPage(dto), TextbookIssueRecordPageVo.class, textbookIssueRecordMPJLambdaWrapper);
+        IPage<TextbookIssueRecordPageVo> result = textbookIssueRecordMapper.selectJoinPage(ConventPage.getPage(dto), TextbookIssueRecordPageVo.class, textbookIssueRecordMPJLambdaWrapper);
+        for (TextbookIssueRecordPageVo vo : result.getRecords()){
+            if(ObjectUtils.isNotEmpty(vo.getPrice())){
+                vo.setPrice(vo.getPrice().stripTrailingZeros());
+            }
+            if(ObjectUtils.isNotEmpty(vo.getSubtotal())){
+                vo.setSubtotal(vo.getSubtotal().stripTrailingZeros());
+            }
+            if(ObjectUtils.isNotEmpty(vo.getActualTotalPrice())){
+                vo.setActualTotalPrice(vo.getActualTotalPrice().stripTrailingZeros());
+            }
+        }
+        return result;
 //        return textbookIssueRecordMapper.getPage(page, dto);
     }
 
@@ -467,12 +478,12 @@ public class TextbookIssueRecordServiceImpl extends MPJBaseServiceImpl<TextbookI
                 data.add(vo.getIssn());
                 data.add(vo.getEditorInChief());
                 data.add(vo.getPublishingHouse());
-                data.add(vo.getPrice() + "");
-                data.add(vo.getSubtotal() + "");
+                data.add(ObjectUtils.isNotEmpty(vo.getPrice()) ? vo.getPrice().stripTrailingZeros().toPlainString() : BigDecimal.ZERO.toPlainString());
+                data.add(ObjectUtils.isNotEmpty(vo.getSubtotal()) ? vo.getSubtotal().stripTrailingZeros().toPlainString() : BigDecimal.ZERO.toPlainString());
                 if (ObjectUtils.isEmpty(vo.getSummation())) {
                     data.add("0");
                 } else {
-                    data.add(vo.getSummation() + "");
+                    data.add(vo.getSummation().stripTrailingZeros().toPlainString());
                 }
 
                 numMap = vo.getNumMap();
@@ -485,12 +496,16 @@ public class TextbookIssueRecordServiceImpl extends MPJBaseServiceImpl<TextbookI
                             data.add(0 + "");
                         }
                     }
+                }else {
+                    for (int i = 0; i < sortedMap.size(); i++) {
+                        data.add(0 + "");
+                    }
                 }
 
                 data.add(vo.getIssueNumber() + "");
                 data.add(vo.getRecedeNumber() + "");
                 data.add(vo.getActualIssueNumber() + "");
-                data.add(vo.getActualTotalPrice() + "");
+                data.add(ObjectUtils.isNotEmpty(vo.getActualTotalPrice()) ? vo.getActualTotalPrice().stripTrailingZeros().toPlainString() : BigDecimal.ZERO.toPlainString());
                 data.add(vo.getRemark());
 
                 resultList.add(data);
@@ -568,7 +583,7 @@ public class TextbookIssueRecordServiceImpl extends MPJBaseServiceImpl<TextbookI
             totalSubtotalRowCell.setCellStyle(cellStyle);
 
             Cell totalPriceRowCell = totalSubtotalRow.createCell(eachImportConfigs.size() - 2);
-            totalPriceRowCell.setCellValue(totalPrice.toString());
+            totalPriceRowCell.setCellValue(totalPrice.stripTrailingZeros().toPlainString());
             totalPriceRowCell.setCellStyle(cellStyle);
 
             sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, 6));

+ 1 - 0
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookServiceImpl.java

@@ -1133,6 +1133,7 @@ public class TextbookServiceImpl extends MPJBaseServiceImpl<TextbookMapper, Text
                     .in(BaseClassAdminCourse::getClassId, classIdList)
                     .notIn(!baseClassCourseIds.isEmpty(), BaseClassCourse::getId, baseClassCourseIds)
                     .eq(BaseClassCourse::getDeleteMark, DeleteMark.NODELETE.getCode())
+                    .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
                     .groupBy(BaseClassCourse::getTextbookId)
                     .groupBy(BaseClassAdminCourse::getClassId)
             ;

+ 90 - 25
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookStudentClaimServiceImpl.java

@@ -10,6 +10,7 @@ import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.enums.ArchivesStatusEnum;
 import com.xjrsoft.common.enums.ClaimTypeEnum;
 import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.RoleEnum;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.utils.VoToColumnUtil;
@@ -47,6 +48,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.io.ByteArrayOutputStream;
 import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -172,7 +174,7 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
     }
 
     @Override
-    public List<HeadTeaLookClassBookSemesterVo> headTeaLookClassBookSemester() {
+    public IPage<HeadTeaLookClassBookSemesterVo> headTeaLookClassBookSemester(HeadTeaLookClassBookSemesterDto dto) {
         Long loginId = StpUtil.getLoginIdAsLong();
 
         MPJLambdaWrapper<BaseClassAdminCourse> baseClassAdminCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
@@ -184,10 +186,21 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                 .selectAs(BaseClass::getName, HeadTeaLookClassBookSemesterVo::getBaseClassIdCn)
                 .innerJoin(BaseClass.class, BaseClass::getId, BaseClassAdminCourse::getClassId)
                 .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassAdminCourse::getBaseSemesterId)
-                .eq(BaseClass::getTeacherId, loginId)
+                .eq(StringUtils.isNotEmpty(dto.getBaseSemesterId()), BaseClassAdminCourse::getBaseSemesterId, dto.getBaseSemesterId())
+                .eq(StringUtils.isNotEmpty(dto.getBaseClassId()), BaseClassAdminCourse::getClassId, dto.getBaseClassId())
+                .like(StringUtils.isNotEmpty(dto.getBaseSemesterIdCn()), BaseSemester::getName, dto.getBaseSemesterIdCn())
+                .like(StringUtils.isNotEmpty(dto.getBaseClassIdCn()), BaseClass::getName, dto.getBaseClassIdCn())
                 .orderByDesc(BaseSemester::getName)
+                .orderByDesc(BaseClass::getName)
         ;
-        return baseClassAdminCourseMapper.selectJoinList(HeadTeaLookClassBookSemesterVo.class, baseClassAdminCourseMPJLambdaWrapper);
+
+        // 权限控制,教材管理员可以看到所有班级所有学期的数据
+        // 班主任只能看到自己班上的
+        if(!StpUtil.hasRole("BOOKAdmin")) {
+            baseClassAdminCourseMPJLambdaWrapper
+                    .eq(BaseClass::getTeacherId, loginId);
+        }
+        return baseClassAdminCourseMapper.selectJoinPage(ConventPage.getPage(dto), HeadTeaLookClassBookSemesterVo.class, baseClassAdminCourseMPJLambdaWrapper);
     }
 
     @Override
@@ -546,24 +559,20 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
     @Override
     public IPage<TeacherCheckByclassVo> getTeacherCheckByclassList(TeacherCheckByclassDto dto) {
         // 如果没有传入班级id
-        if (ObjectUtils.isEmpty(dto.getClassIdList())) {
+        if (ObjectUtils.isEmpty(dto.getClassId())) {
             //根据当前班主任用户查出所管理的班级Id
             LambdaQueryWrapper<BaseClass> queryWrapperClassId = new LambdaQueryWrapper<>();
             queryWrapperClassId
                     .eq(BaseClass::getTeacherId, StpUtil.getLoginIdAsLong())
                     .eq(BaseClass::getDeleteMark, DeleteMark.NODELETE.getCode())
+                    .last("limit 1")
             ;
-            List<BaseClass> baseClassList = baseClassService.list(queryWrapperClassId);
-            if (ObjectUtils.isEmpty(baseClassList)) {
+            BaseClass baseClasse = baseClassService.getOne(queryWrapperClassId);
+            if (ObjectUtils.isEmpty(baseClasse)) {
                 return null;
             }
 
-            List<Long> classIdList = new ArrayList<>();
-            for (BaseClass baseClass : baseClassList) {
-                classIdList.add(baseClass.getId());
-            }
-
-            dto.setClassIdList(classIdList);
+            dto.setClassId(baseClasse.getId());
         }
 
 //        // 获取当前班级采用班级申领的所有教材
@@ -755,6 +764,7 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                 .leftJoin(BaseStudent.class, BaseStudent::getUserId, BaseStudentSchoolRoll::getUserId)
                 .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
                 .eq(BaseStudentSchoolRoll::getClassId, dto.getClassId())
+                .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
                 .orderByAsc(BaseStudent::getStudentId)
         ;
         List<TeacherCheckStuClaimVo> stuList = baseStudentSchoolRollMapper.selectJoinList(TeacherCheckStuClaimVo.class, baseStudentSchoolRollMPJLambdaWrapper);
@@ -838,6 +848,7 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
         wfTextbookClaimLambdaQueryWrapper
                 .selectAs(WfTextbookClaimItem::getTextbookId, ClassClaimTextbookIssuePrice::getTextbookId)
                 .selectAs(TextbookWarehouseRecord::getSubtotal, ClassClaimTextbookIssuePrice::getPrice)
+                .selectAs(TextbookIssueRecord::getTextbookWarehouseRecordId, ClassClaimTextbookIssuePrice::getTextbookWarehouseRecordId)
                 .innerJoin(WfTextbookClaimItem.class, WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaim::getId)
                 .innerJoin(TextbookIssueRecord.class,
                         wrapper -> wrapper
@@ -847,12 +858,13 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                 .innerJoin(TextbookWarehouseRecord.class, TextbookWarehouseRecord::getId, TextbookIssueRecord::getTextbookWarehouseRecordId)
                 .eq(WfTextbookClaim::getBaseSemesterId, dto.getBaseSemesterId())
                 .eq(WfTextbookClaim::getClassId, dto.getClassId())
+                .eq(WfTextbookClaim::getClaimType, ClaimTypeEnum.ClaimClass.getCode())
                 .eq(WfTextbookClaim::getWorkflowStatus, 1)
         ;
         List<ClassClaimTextbookIssuePrice> classClaimTextbookIssuePrices = wfTextbookClaimMapper.selectJoinList(ClassClaimTextbookIssuePrice.class, wfTextbookClaimLambdaQueryWrapper);
 
-        Map<Long, BigDecimal> textBookPriceMap = classClaimTextbookIssuePrices.stream()
-                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, ClassClaimTextbookIssuePrice::getPrice, (p1, p2) -> p2));
+        Map<Long, ClassClaimTextbookIssuePrice> textBookPriceMap = classClaimTextbookIssuePrices.stream()
+                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, c -> c, (p1, p2) -> p2));
 
         List<TextbookStudentClaim> insertList = new ArrayList<>();
         List<TextbookStudentClaim> updateList = new ArrayList<>();
@@ -861,12 +873,16 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
         TextbookStudentClaim updateTextbookStudentClaim;
         Date nowDate = new Date();
         Long loginUserId = StpUtil.getLoginIdAsLong();
+        ClassClaimTextbookIssuePrice classClaimTextbookIssuePrice = null;
         for (Long textbookId : dto.getTextbookIds()) {
             for (Long userId : dto.getUserIds()) {
-                BigDecimal price = BigDecimal.ZERO;
                 if (MapUtils.isNotEmpty(textBookPriceMap) && ObjectUtils.isNotEmpty(textBookPriceMap.get(textbookId))) {
-                    price = textBookPriceMap.get(textbookId);
+                    classClaimTextbookIssuePrice = textBookPriceMap.get(textbookId);
                 }
+                if(ObjectUtils.isEmpty(classClaimTextbookIssuePrice)){
+                    throw new MyException("有一本教材并没有发放,无法确认领取。");
+                }
+                BigDecimal price = classClaimTextbookIssuePrice.getPrice();
                 oldTextbookStudentClaim = byUserIdAndTextbookId.get("" + userId + textbookId);
                 if (ObjectUtils.isNotEmpty(oldTextbookStudentClaim)
                         && (ObjectUtils.isEmpty(oldTextbookStudentClaim.getClaimSource()) || oldTextbookStudentClaim.getClaimSource() != 1)
@@ -877,9 +893,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     updateTextbookStudentClaim.setModifyDate(nowDate);
                     updateTextbookStudentClaim.setModifyUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         updateTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         updateTextbookStudentClaim.setPrice(price);
                     }
                     updateTextbookStudentClaim.setClaimSource(2);
@@ -894,9 +912,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     insertTextbookStudentClaim.setCreateDate(nowDate);
                     insertTextbookStudentClaim.setCreateUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         insertTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         insertTextbookStudentClaim.setPrice(price);
                     }
                     insertTextbookStudentClaim.setClaimSource(2);
@@ -964,6 +984,7 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
         wfTextbookClaimLambdaQueryWrapper
                 .selectAs(WfTextbookClaimItem::getTextbookId, ClassClaimTextbookIssuePrice::getTextbookId)
                 .selectAs(TextbookWarehouseRecord::getSubtotal, ClassClaimTextbookIssuePrice::getPrice)
+                .selectAs(TextbookIssueRecord::getTextbookWarehouseRecordId, ClassClaimTextbookIssuePrice::getTextbookWarehouseRecordId)
                 .innerJoin(WfTextbookClaimItem.class, WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaim::getId)
                 .innerJoin(TextbookIssueRecord.class,
                         wrapper -> wrapper
@@ -973,40 +994,49 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                 .innerJoin(TextbookWarehouseRecord.class, TextbookWarehouseRecord::getId, TextbookIssueRecord::getTextbookWarehouseRecordId)
                 .in(WfTextbookClaim::getBaseSemesterId, baseSemesterIds)
                 .in(WfTextbookClaim::getClassId, classIds)
+                .eq(WfTextbookClaim::getClaimType, ClaimTypeEnum.ClaimClass.getCode())
                 .eq(WfTextbookClaim::getWorkflowStatus, 1)
         ;
 
         List<ClassClaimTextbookIssuePrice> classClaimTextbookIssuePrices = wfTextbookClaimMapper.selectJoinList(ClassClaimTextbookIssuePrice.class, wfTextbookClaimLambdaQueryWrapper);
 
-        Map<Long, BigDecimal> textBookPriceMap = classClaimTextbookIssuePrices.stream()
-                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, ClassClaimTextbookIssuePrice::getPrice, (p1, p2) -> p2));
+        Map<Long, ClassClaimTextbookIssuePrice> textBookPriceMap = classClaimTextbookIssuePrices.stream()
+                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, c -> c, (c1, c2) -> c2));
 
         List<TextbookStudentClaim> insertList = new ArrayList<>();
         List<TextbookStudentClaim> updateList = new ArrayList<>();
         TextbookStudentClaim oldTextbookStudentClaim;
         TextbookStudentClaim insertTextbookStudentClaim;
         TextbookStudentClaim updateTextbookStudentClaim;
+        ClassClaimTextbookIssuePrice classClaimTextbookIssuePrice = null;
         Date nowDate = new Date();
         Long loginUserId = StpUtil.getLoginIdAsLong();
         for (TeacherConfirmDto dto : dtos) {
-            BigDecimal price = BigDecimal.ZERO;
             if (MapUtils.isNotEmpty(textBookPriceMap) && ObjectUtils.isNotEmpty(textBookPriceMap.get(dto.getTextbookId()))) {
-                price = textBookPriceMap.get(dto.getTextbookId());
+                classClaimTextbookIssuePrice = textBookPriceMap.get(dto.getTextbookId());
+            }
+            if(ObjectUtils.isEmpty(classClaimTextbookIssuePrice)){
+                throw new MyException("有一本教材并没有发放,无法确认领取。");
             }
+            BigDecimal price = classClaimTextbookIssuePrice.getPrice();
             if (ObjectUtils.isNotEmpty(dto.getTextbookStudentClaimId())
                     && dto.getTextbookStudentClaimId() != 0) {
                 oldTextbookStudentClaim = byClaimSource.get(dto.getTextbookStudentClaimId());
                 if (ObjectUtils.isNotEmpty(oldTextbookStudentClaim)
-                        && (ObjectUtils.isEmpty(oldTextbookStudentClaim.getClaimSource()) || oldTextbookStudentClaim.getClaimSource() != 1)) {
+                        && (ObjectUtils.isEmpty(oldTextbookStudentClaim.getClaimSource())
+                        || oldTextbookStudentClaim.getClaimSource() != 1)
+                ) {
                     updateTextbookStudentClaim = new TextbookStudentClaim();
                     updateTextbookStudentClaim.setId(dto.getTextbookStudentClaimId());
                     updateTextbookStudentClaim.setIsClaim(dto.getIsClaim());
                     updateTextbookStudentClaim.setModifyUserId(loginUserId);
                     updateTextbookStudentClaim.setModifyDate(nowDate);
                     if (dto.getIsClaim() == 0) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         updateTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         updateTextbookStudentClaim.setPrice(price);
                     }
                     updateTextbookStudentClaim.setClaimSource(2);
@@ -1023,9 +1053,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     updateTextbookStudentClaim.setModifyDate(nowDate);
                     updateTextbookStudentClaim.setModifyUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         updateTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         updateTextbookStudentClaim.setPrice(price);
                     }
                     updateTextbookStudentClaim.setClaimSource(2);
@@ -1040,9 +1072,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     insertTextbookStudentClaim.setCreateDate(nowDate);
                     insertTextbookStudentClaim.setCreateUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         insertTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         insertTextbookStudentClaim.setPrice(price);
                     }
                     insertTextbookStudentClaim.setClaimSource(2);
@@ -1110,6 +1144,7 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
         MPJLambdaWrapper<WfTextbookClaim> wfTextbookClaimLambdaQueryWrapper = new MPJLambdaWrapper<>();
         wfTextbookClaimLambdaQueryWrapper
                 .selectAs(WfTextbookClaimItem::getTextbookId, ClassClaimTextbookIssuePrice::getTextbookId)
+                .selectAs(TextbookIssueRecord::getTextbookWarehouseRecordId, ClassClaimTextbookIssuePrice::getTextbookWarehouseRecordId)
                 .selectAs(TextbookWarehouseRecord::getSubtotal, ClassClaimTextbookIssuePrice::getPrice)
                 .innerJoin(WfTextbookClaimItem.class, WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaim::getId)
                 .innerJoin(TextbookIssueRecord.class,
@@ -1120,25 +1155,30 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                 .innerJoin(TextbookWarehouseRecord.class, TextbookWarehouseRecord::getId, TextbookIssueRecord::getTextbookWarehouseRecordId)
                 .eq(WfTextbookClaim::getBaseSemesterId, dto.getBaseSemesterId())
                 .eq(WfTextbookClaim::getClassId, baseStudentSchoolRoll.getClassId())
+                .eq(WfTextbookClaim::getClaimType, ClaimTypeEnum.ClaimClass.getCode())
                 .eq(WfTextbookClaim::getWorkflowStatus, 1)
         ;
         List<ClassClaimTextbookIssuePrice> classClaimTextbookIssuePrices = wfTextbookClaimMapper.selectJoinList(ClassClaimTextbookIssuePrice.class, wfTextbookClaimLambdaQueryWrapper);
 
-        Map<Long, BigDecimal> textBookPriceMap = classClaimTextbookIssuePrices.stream()
-                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, ClassClaimTextbookIssuePrice::getPrice, (p1, p2) -> p2));
+        Map<Long, ClassClaimTextbookIssuePrice> textBookPriceMap = classClaimTextbookIssuePrices.stream()
+                .collect(Collectors.toMap(ClassClaimTextbookIssuePrice::getTextbookId, c -> c, (c1, c2) -> c2));
 
         List<TextbookStudentClaim> insertList = new ArrayList<>();
         List<TextbookStudentClaim> updateList = new ArrayList<>();
         TextbookStudentClaim oldTextbookStudentClaim;
         TextbookStudentClaim insertTextbookStudentClaim;
         TextbookStudentClaim updateTextbookStudentClaim;
+        ClassClaimTextbookIssuePrice classClaimTextbookIssuePrice = null;
         Date nowDate = new Date();
         Long loginUserId = StpUtil.getLoginIdAsLong();
         for (StudentConfirmDetailDto studentConfirmDetailDto : dto.getStudentConfirmDetail()) {
-            BigDecimal price = BigDecimal.ZERO;
             if (MapUtils.isNotEmpty(textBookPriceMap) && ObjectUtils.isNotEmpty(textBookPriceMap.get(studentConfirmDetailDto.getTextbookId()))) {
-                price = textBookPriceMap.get(studentConfirmDetailDto.getTextbookId());
+                classClaimTextbookIssuePrice = textBookPriceMap.get(studentConfirmDetailDto.getTextbookId());
             }
+            if(ObjectUtils.isEmpty(classClaimTextbookIssuePrice)){
+                throw new MyException("有一本教材并没有发放,无法确认领取。");
+            }
+            BigDecimal price = classClaimTextbookIssuePrice.getPrice();
             if (ObjectUtils.isNotEmpty(studentConfirmDetailDto.getTextbookStudentClaimId())
                     && studentConfirmDetailDto.getTextbookStudentClaimId() != 0
             ) {
@@ -1151,9 +1191,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     updateTextbookStudentClaim.setModifyUserId(loginUserId);
                     updateTextbookStudentClaim.setModifyDate(nowDate);
                     if (dto.getIsClaim() == 0) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         updateTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         updateTextbookStudentClaim.setPrice(price);
                     }
                     updateTextbookStudentClaim.setClaimSource(2);
@@ -1168,9 +1210,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     updateTextbookStudentClaim.setModifyDate(nowDate);
                     updateTextbookStudentClaim.setModifyUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         updateTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         updateTextbookStudentClaim.setPrice(price);
                     }
                     updateTextbookStudentClaim.setClaimSource(2);
@@ -1185,9 +1229,11 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
                     insertTextbookStudentClaim.setCreateDate(nowDate);
                     insertTextbookStudentClaim.setCreateUserId(loginUserId);
                     if (dto.getIsClaim() == 0) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(0L);
                         insertTextbookStudentClaim.setPrice(BigDecimal.ZERO);
                     }
                     if (dto.getIsClaim() == 1) {
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(classClaimTextbookIssuePrice.getTextbookWarehouseRecordId());
                         insertTextbookStudentClaim.setPrice(price);
                     }
                     insertTextbookStudentClaim.setClaimSource(2);
@@ -1228,4 +1274,23 @@ public class TextbookStudentClaimServiceImpl extends MPJBaseServiceImpl<Textbook
         ;
         return wfTextbookClaimItemMapper.selectJoinList(TeacherConfirmBatchTextbookListVo.class, wfTextbookClaimItemMPJLambdaWrapper);
     }
+
+    @Override
+    public ByteArrayOutputStream allStuClaimExportQuery(AllStuClaimExportQueryDto dto) {
+        if(StringUtils.isEmpty(dto.getBaseSemesterId())){
+            throw new MyException("请选择学期");
+        }
+
+        BaseSemester baseSemester = baseSemesterMapper.selectById(dto.getBaseSemesterId());
+
+        if(ObjectUtils.isEmpty(baseSemester)){
+            throw new MyException("学期无效,请重新选择");
+        }
+
+        // 获取所有学生信息
+//        AllStuClaimExportQueryVo
+
+
+        return null;
+    }
 }

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

@@ -276,7 +276,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
         textbookSubscriptionDetailVo.setStudentTatolNum(stuNum);
         textbookSubscriptionDetailVo.setTeacherTatolNum(teaNum);
         textbookSubscriptionDetailVo.setSum(stuNum + teaNum);
-        textbookSubscriptionDetailVo.setSumPrice(totalPrice);
+        textbookSubscriptionDetailVo.setSumPrice(totalPrice.stripTrailingZeros());
         return textbookSubscriptionDetailVo;
     }
 
@@ -352,7 +352,9 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                         wrapper -> wrapper
                                 .selectAs(DictionaryDetail::getName, SubscriptionItemListDistributeVo::getWarehouseModeCn)
                 )
+                .leftJoin(TextbookSubscriptionItemClass.class, TextbookSubscriptionItemClass::getTextbookSubscriptionItemId, TextbookWarehouseRecord::getDataItemId)
                 .eq(TextbookWarehouseRecord::getTextbookId, dto.getTextbookId())
+                .eq(ObjectUtils.isNotEmpty(dto.getClassId()), TextbookSubscriptionItemClass::getBaseClassId, dto.getClassId())
                 .gt(TextbookWarehouseRecord::getRemainNumber, 0)
                 .orderByAsc(TextbookWarehouseRecord::getCreateDate)
         ;
@@ -537,7 +539,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 .collect(Collectors.groupingBy(
                         TextbookWarehouseRecord::getDataItemId, // 第一层分组:按征订项 ID 分组
                         Collectors.toMap(
-                                p -> p.getPrice().stripTrailingZeros().toPlainString() + "-" + String.format("%.2f", p.getDiscount()), // 第二层映射:按入库定价作为键
+                                p -> p.getPrice().stripTrailingZeros().toString() + "-" + String.format("%.2f", p.getDiscount()), // 第二层映射:按入库定价作为键
                                 wr -> wr,                      // 值为 TextbookStudentClaim 对象本身
                                 (existing, replacement) -> existing   // 如果有重复键,保留现有的值
                         )
@@ -594,7 +596,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 }
 
                 if(MapUtils.isNotEmpty(oldTextbookWarehouseRecordByPrice)){
-                    oldTextbookWarehouseRecord = oldTextbookWarehouseRecordByPrice.get(dto.getPrice().stripTrailingZeros().toPlainString() + "-" + String.format("%.2f", dto.getDiscount()));
+                    oldTextbookWarehouseRecord = oldTextbookWarehouseRecordByPrice.get(dto.getPrice().stripTrailingZeros().toString() + "-" + String.format("%.2f", dto.getDiscount()));
                 }
             }
 
@@ -602,6 +604,10 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 throw new MyException("第" + (i+1) + "本教材征订信息被修改,请刷新重试");
             }
 
+            if((old.getInStockNum() + dto.getInNum()) < 0){
+                throw new MyException("第" + (i+1) + "本教材已入库数量产生负数,请输入合理的入库数量");
+            }
+
             // 现在入库价格改动不影响征订项的价格相关属性
             updateItem = new TextbookSubscriptionItem();
             updateItem.setId(old.getId());
@@ -643,12 +649,26 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 textbookWarehouseRecordMapper.insert(textbookWarehouseRecord);
             } else {
                 textbookWarehouseRecordId = oldTextbookWarehouseRecord.getId();
-                textbookWarehouseRecord = BeanUtil.toBean(oldTextbookWarehouseRecord, TextbookWarehouseRecord.class);
-                textbookWarehouseRecord.setWarehouseNumber(textbookWarehouseRecord.getWarehouseNumber() + dto.getInNum());
+                textbookWarehouseRecord = new TextbookWarehouseRecord();
+                textbookWarehouseRecord.setId(textbookWarehouseRecordId);
+
+                if(oldTextbookWarehouseRecord.getWarehouseNumber() + dto.getInNum() < 0){
+                    throw new MyException("第" + (i+1) + "本教材已入库数量产生负数,请输入合理的入库数量");
+                }
+                textbookWarehouseRecord.setWarehouseNumber(oldTextbookWarehouseRecord.getWarehouseNumber() + dto.getInNum());
                 textbookWarehouseRecord.setTotalPrice(textbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(textbookWarehouseRecord.getWarehouseNumber())));
-                textbookWarehouseRecord.setActualWarehouseNumber(textbookWarehouseRecord.getActualWarehouseNumber() + dto.getInNum());
+
+                if(oldTextbookWarehouseRecord.getActualWarehouseNumber() + dto.getInNum() < 0){
+                    throw new MyException("第" + (i+1) + "本教材实际入库数量产生负数,请输入合理的入库数量");
+                }
+                textbookWarehouseRecord.setActualWarehouseNumber(oldTextbookWarehouseRecord.getActualWarehouseNumber() + dto.getInNum());
                 textbookWarehouseRecord.setActualTotalPrice(textbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(textbookWarehouseRecord.getActualWarehouseNumber())));
-                textbookWarehouseRecord.setRemainNumber(textbookWarehouseRecord.getRemainNumber() + dto.getInNum());
+
+                if(oldTextbookWarehouseRecord.getRemainNumber() + dto.getInNum() < 0){
+                    throw new MyException("第" + (i+1) + "本教材剩余库存数量产生负数,请输入合理的入库数量");
+                }
+                textbookWarehouseRecord.setRemainNumber(oldTextbookWarehouseRecord.getRemainNumber() + dto.getInNum());
+
                 textbookWarehouseRecord.setModifyDate(new Date());
                 textbookWarehouseRecord.setModifyUserId(StpUtil.getLoginIdAsLong());
                 textbookWarehouseRecordMapper.updateById(textbookWarehouseRecord);
@@ -662,7 +682,6 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
             textbookWarehouseRecordDetail.setCreateDate(new Date());
             textbookWarehouseRecordDetailMapper.insert(textbookWarehouseRecordDetail);
         }
-
         return true;
     }
 
@@ -708,7 +727,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
                 .collect(Collectors.groupingBy(
                         TextbookWarehouseRecord::getDataItemId, // 第一层分组:按征订项 ID 分组
                         Collectors.toMap(
-                                p -> p.getPrice().stripTrailingZeros().toPlainString() + "-" + String.format("%.2f", p.getDiscount()), // 第二层映射:按入库定价作为键
+                                p -> p.getPrice().stripTrailingZeros().toString() + "-" + String.format("%.2f", p.getDiscount()), // 第二层映射:按入库定价作为键
                                 wr -> wr,                      // 值为 TextbookStudentClaim 对象本身
                                 (existing, replacement) -> existing   // 如果有重复键,保留现有的值
                         )
@@ -779,7 +798,7 @@ public class TextbookSubscriptionServiceImpl extends MPJBaseServiceImpl<Textbook
 
             oldTextbookWarehouseRecordByPrice = textbookWarehouseRecordByItemIdByPriceMap.get(Long.parseLong(vo.getTextbookSubscriptionItemId()));
             if(MapUtils.isNotEmpty(oldTextbookWarehouseRecordByPrice)){
-                oldTextbookWarehouseRecord = oldTextbookWarehouseRecordByPrice.get(vo.getPrice().stripTrailingZeros().toPlainString() + "-" + String.format("%.2f", vo.getDiscount()));
+                oldTextbookWarehouseRecord = oldTextbookWarehouseRecordByPrice.get(vo.getPrice().stripTrailingZeros().toString() + "-" + String.format("%.2f", vo.getDiscount()));
             }
 
             updateItem = new TextbookSubscriptionItem();

+ 96 - 26
src/main/java/com/xjrsoft/module/textbook/service/impl/TextbookWarehouseRecordServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.util.IdUtil;
 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.metadata.IPage;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
@@ -15,14 +16,12 @@ import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.base.entity.BaseCourseSubject;
 import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.student.entity.BaseStudent;
 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.TextbookDiscountAlterRecordMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookSubscriptionItemMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookWarehouseRecordDetailMapper;
-import com.xjrsoft.module.textbook.mapper.TextbookWarehouseRecordMapper;
+import com.xjrsoft.module.textbook.mapper.*;
 import com.xjrsoft.module.textbook.service.ITextbookWarehouseRecordService;
 import com.xjrsoft.module.textbook.vo.TextbookWarehouseRecordExcelVo;
 import com.xjrsoft.module.textbook.vo.TextbookWarehouseRecordPageVo;
@@ -57,6 +56,9 @@ public class TextbookWarehouseRecordServiceImpl extends MPJBaseServiceImpl<Textb
     private final TextbookSubscriptionItemMapper textbookSubscriptionItemMapper;
 
     private final TextbookDiscountAlterRecordMapper textbookDiscountAlterRecordMapper;
+    private final TextbookIssueRecordMapper textbookIssueRecordMapper;
+
+    private final TextbookStudentClaimMapper textbookStudentClaimMapper;
 
     @Override
     public IPage<TextbookWarehouseRecordPageVo> getPage(TextbookWarehouseRecordPageDto dto) {
@@ -110,7 +112,21 @@ public class TextbookWarehouseRecordServiceImpl extends MPJBaseServiceImpl<Textb
                 .gt(ObjectUtils.isNotEmpty(dto.getReturnState()) && dto.getReturnState() == 1, TextbookWarehouseRecord::getRecedeNumber, 0)
                 .orderByDesc(TextbookWarehouseRecord::getCreateDate)
         ;
-        return this.selectJoinListPage(ConventPage.getPage(dto), TextbookWarehouseRecordPageVo.class, textbookWarehouseRecordMPJLambdaWrapper);
+
+        IPage<TextbookWarehouseRecordPageVo> page = this.selectJoinListPage(ConventPage.getPage(dto), TextbookWarehouseRecordPageVo.class, textbookWarehouseRecordMPJLambdaWrapper);
+        for (TextbookWarehouseRecordPageVo vo : page.getRecords()){
+            if(ObjectUtils.isNotEmpty(vo.getPrice())){
+                vo.setPrice(vo.getPrice().stripTrailingZeros());
+            }
+            if(ObjectUtils.isNotEmpty(vo.getSubtotal())){
+                vo.setSubtotal(vo.getSubtotal().stripTrailingZeros());
+            }
+            if(ObjectUtils.isNotEmpty(vo.getActualTotalPrice())){
+                vo.setActualTotalPrice(vo.getActualTotalPrice().stripTrailingZeros());
+            }
+        }
+
+        return page;
 //        return textbookWarehouseRecordMapper.getPage(page, dto);
     }
 
@@ -202,42 +218,96 @@ public class TextbookWarehouseRecordServiceImpl extends MPJBaseServiceImpl<Textb
             throw new MyException("当前入库记录已经被修改,请重新选择");
         }
 
-        // 如果是征订入库
-        // 根据入库记录找到对应的征订
-//        MPJLambdaWrapper<TextbookWarehouseRecord> textbookWarehouseRecordMPJLambdaWrapper = new MPJLambdaWrapper<>();
-//        textbookWarehouseRecordMPJLambdaWrapper
-//                .disableSubLogicDel()
-//                .select(TextbookSubscriptionItem::getId)
-//                .select(TextbookSubscriptionItem.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionItem.class).contains(x.getProperty()))
-//                .innerJoin(TextbookSubscriptionItem.class, TextbookSubscriptionItem::getId, TextbookWarehouseRecord::getDataItemId)
-//                .eq(TextbookWarehouseRecord::getId, dto.getId())
-//        ;
-//        TextbookSubscriptionItem textbookSubscriptionItem = textbookWarehouseRecordMapper.selectJoinOne(TextbookSubscriptionItem.class, textbookWarehouseRecordMPJLambdaWrapper);
-//        if (ObjectUtils.isNotEmpty(textbookSubscriptionItem)) {
-//            TextbookSubscriptionItem updateTextbookSubscriptionItem = new TextbookSubscriptionItem();
-//            updateTextbookSubscriptionItem.setId(textbookSubscriptionItem.getId());
-//            updateTextbookSubscriptionItem.setDiscount(ObjectUtils.isNotEmpty(dto.getDiscount()) ? dto.getDiscount() : 10);
-//            updateTextbookSubscriptionItem.setPrice(textbookWarehouseRecord.getPrice().multiply(BigDecimal.valueOf(dto.getDiscount() / 10)));
-//            updateTextbookSubscriptionItem.setModifyDate(new Date());
-//            textbookSubscriptionItemMapper.updateById(updateTextbookSubscriptionItem);
-//        }
+        if(textbookWarehouseRecord.getIssuedNumber() > dto.getWarehouseNumber()){
+            throw new MyException("入库数量不能少于已经发放数量");
+        }
 
         TextbookWarehouseRecord updateTextbookWarehouseRecord = new TextbookWarehouseRecord();
         updateTextbookWarehouseRecord.setId(textbookWarehouseRecord.getId());
+
+        if(dto.getWarehouseNumber() - textbookWarehouseRecord.getIssuedNumber() < 0){
+            throw new MyException(String.format("当前教材已经出库[%s],请输入合理的入库数量",
+                            textbookWarehouseRecord.getIssuedNumber()
+                    ));
+        }
+
+        if(dto.getWarehouseNumber() < 0){
+            throw new MyException("入库数量不能为负,请输入合理的入库数量");
+        }
+        updateTextbookWarehouseRecord.setWarehouseNumber(dto.getWarehouseNumber());
+
+        if(textbookWarehouseRecord.getActualWarehouseNumber() - (textbookWarehouseRecord.getWarehouseNumber() - dto.getWarehouseNumber()) < 0){
+            throw new MyException("修改入库数量导致实际入库数量为负,请输入合理的入库数量");
+        }
+        updateTextbookWarehouseRecord.setActualWarehouseNumber(textbookWarehouseRecord.getActualWarehouseNumber() - (textbookWarehouseRecord.getWarehouseNumber() - dto.getWarehouseNumber()));
+
         updateTextbookWarehouseRecord.setPrice(ObjectUtils.isNotEmpty(dto.getPrice()) ? dto.getPrice() : BigDecimal.ZERO);
         updateTextbookWarehouseRecord.setDiscount(ObjectUtils.isNotEmpty(dto.getDiscount()) ? dto.getDiscount() : 10);
         updateTextbookWarehouseRecord.setSubtotal(updateTextbookWarehouseRecord.getPrice().multiply(BigDecimal.valueOf(dto.getDiscount() / 10)));
-        updateTextbookWarehouseRecord.setTotalPrice(updateTextbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(textbookWarehouseRecord.getWarehouseNumber())));
-        updateTextbookWarehouseRecord.setActualTotalPrice(updateTextbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(textbookWarehouseRecord.getActualWarehouseNumber())));
+
+        updateTextbookWarehouseRecord.setTotalPrice(updateTextbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(updateTextbookWarehouseRecord.getWarehouseNumber())));
+        updateTextbookWarehouseRecord.setActualTotalPrice(updateTextbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(updateTextbookWarehouseRecord.getActualWarehouseNumber())));
+
+        if(textbookWarehouseRecord.getRemainNumber() - (textbookWarehouseRecord.getWarehouseNumber() - dto.getWarehouseNumber()) < 0){
+            throw new MyException("修改入库数量导致剩余库存数量为负,请输入合理的入库数量");
+        }
+        updateTextbookWarehouseRecord.setRemainNumber(textbookWarehouseRecord.getRemainNumber() - (textbookWarehouseRecord.getWarehouseNumber() - dto.getWarehouseNumber()));
+
         updateTextbookWarehouseRecord.setModifyDate(new Date());
         textbookWarehouseRecordMapper.updateById(updateTextbookWarehouseRecord);
 
+        // 需要找到使用当前入库记录的出库记录,改变其值
+        LambdaQueryWrapper<TextbookIssueRecord> textbookIssueRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        textbookIssueRecordLambdaQueryWrapper
+                .eq(TextbookIssueRecord::getTextbookWarehouseRecordId, textbookWarehouseRecord.getId())
+                .eq(TextbookIssueRecord::getDeleteMark, DeleteMark.NODELETE.getCode())
+                ;
+        List<TextbookIssueRecord> textbookIssueRecords = textbookIssueRecordMapper.selectList(textbookIssueRecordLambdaQueryWrapper);
+
+        TextbookIssueRecord updateTextbookIssueRecord;
+        for (TextbookIssueRecord textbookIssueRecord : textbookIssueRecords){
+            updateTextbookIssueRecord = new TextbookIssueRecord();
+            updateTextbookIssueRecord.setId(textbookIssueRecord.getId());
+            updateTextbookIssueRecord.setActualTotalPrice(updateTextbookWarehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(textbookIssueRecord.getActualIssueNumber())));
+            textbookIssueRecordMapper.updateById(updateTextbookIssueRecord);
+        }
+
+        // 如果是征订入库
+        // 根据入库记录找到对应的征订
+        MPJLambdaWrapper<TextbookSubscriptionItem> textbookWarehouseRecordMPJLambdaWrapper = new MPJLambdaWrapper<>();
+        textbookWarehouseRecordMPJLambdaWrapper
+                .disableSubLogicDel()
+                .select(TextbookSubscriptionItem::getId)
+                .select(TextbookSubscriptionItem.class, x -> VoToColumnUtil.fieldsToColumns(TextbookSubscriptionItem.class).contains(x.getProperty()))
+                .innerJoin(TextbookWarehouseRecord.class, TextbookWarehouseRecord::getDataItemId, TextbookSubscriptionItem::getId)
+                .eq(TextbookWarehouseRecord::getId, dto.getId())
+        ;
+        TextbookSubscriptionItem textbookSubscriptionItem = textbookSubscriptionItemMapper.selectJoinOne(TextbookSubscriptionItem.class, textbookWarehouseRecordMPJLambdaWrapper);
+        if (ObjectUtils.isNotEmpty(textbookSubscriptionItem)) {
+            TextbookSubscriptionItem updateTextbookSubscriptionItem = new TextbookSubscriptionItem();
+            updateTextbookSubscriptionItem.setId(textbookSubscriptionItem.getId());
+
+            updateTextbookSubscriptionItem.setInStockNum(dto.getWarehouseNumber());
+            updateTextbookSubscriptionItem.setModifyDate(new Date());
+            textbookSubscriptionItemMapper.updateById(updateTextbookSubscriptionItem);
+        }
+
+        // 需要找到使用当前入库记录的出库记录对应的学生确认领取,改变其值
+        LambdaUpdateWrapper<TextbookStudentClaim> textbookStudentClaimLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        textbookStudentClaimLambdaUpdateWrapper
+                .set(TextbookStudentClaim::getPrice, updateTextbookWarehouseRecord.getSubtotal())
+                .eq(TextbookStudentClaim::getTextbookWarehouseRecordId, textbookWarehouseRecord.getId())
+                ;
+        textbookStudentClaimMapper.update(new TextbookStudentClaim(), textbookStudentClaimLambdaUpdateWrapper);
+
         TextbookDiscountAlterRecord textbookDiscountAlterRecord = new TextbookDiscountAlterRecord();
         textbookDiscountAlterRecord.setTextbookWarehouseRecordId(textbookWarehouseRecord.getId());
         textbookDiscountAlterRecord.setOldPrice(textbookWarehouseRecord.getPrice());
         textbookDiscountAlterRecord.setNewPrice(dto.getPrice());
         textbookDiscountAlterRecord.setOldDiscount(textbookWarehouseRecord.getDiscount());
         textbookDiscountAlterRecord.setNewDiscount(dto.getDiscount());
+        textbookDiscountAlterRecord.setOldWarehouseNum(textbookWarehouseRecord.getWarehouseNumber());
+        textbookDiscountAlterRecord.setNewWarehouseNum(dto.getWarehouseNumber());
         textbookDiscountAlterRecord.setCreateDate(new Date());
         textbookDiscountAlterRecordMapper.insert(textbookDiscountAlterRecord);
 

+ 725 - 74
src/main/java/com/xjrsoft/module/textbook/service/impl/WfTextbookClaimServiceImpl.java

@@ -1,24 +1,23 @@
 package com.xjrsoft.module.textbook.service.impl;
 
 import cn.dev33.satoken.stp.StpUtil;
-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.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.ArchivesStatusEnum;
 import com.xjrsoft.common.enums.ClaimTypeEnum;
 import com.xjrsoft.common.enums.DeleteMark;
 import com.xjrsoft.common.enums.IssueModeEnum;
 import com.xjrsoft.common.exception.MyException;
-import com.xjrsoft.common.model.result.RT;
 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.BaseSemester;
-import com.xjrsoft.module.oa.entity.WfMeetingApply;
+import com.xjrsoft.module.generator.entity.ImportConfig;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
 import com.xjrsoft.module.teacher.entity.XjrUser;
 import com.xjrsoft.module.teacher.mapper.XjrUserMapper;
@@ -27,21 +26,29 @@ import com.xjrsoft.module.textbook.entity.*;
 import com.xjrsoft.module.textbook.mapper.*;
 import com.xjrsoft.module.textbook.service.IWfTextbookClaimService;
 import com.xjrsoft.module.textbook.vo.*;
+import com.xjrsoft.module.veb.util.ImportExcelUtil;
 import com.xjrsoft.module.workflow.entity.WorkflowFormRelation;
 import com.xjrsoft.module.workflow.mapper.WorkflowFormRelationMapper;
 import lombok.AllArgsConstructor;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.ObjectUtils;
 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.camunda.bpm.engine.history.HistoricProcessInstance;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -71,6 +78,7 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
 
     @Override
     public IPage<DistributePageVo> distributePage(DistributePageDto dto) {
+        // 申领主表记录
         MPJLambdaWrapper<WfTextbookClaim> wfTextbookClaimMPJLambdaWrapper = new MPJLambdaWrapper<>();
         wfTextbookClaimMPJLambdaWrapper
                 .disableSubLogicDel()
@@ -97,7 +105,6 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                                 .selectAs(XjrUser::getName, DistributePageVo::getStudentUserIdCn)
                 )
                 .eq(WfTextbookClaim::getBaseSemesterId, dto.getBaseSemesterId())
-                .eq(WfTextbookClaim::getWorkflowStatus, 1)
                 .eq(StringUtils.isNotEmpty(dto.getClaimType()), WfTextbookClaim::getClaimType, dto.getClaimType())
                 .and(StringUtils.isNotEmpty(dto.getName()),
                         wrapper -> wrapper
@@ -106,7 +113,10 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                                 .like(BaseClass::getName, dto.getName())
                 )
         ;
+
+        // 发放状态(是否有过发放(1:未发放,2:部分发放,3:全部发放,4:有发放))
         if (ObjectUtils.isNotEmpty(dto.getDistributeStatus())) {
+            // 有发放,除了未发放其他所有的状态
             if (dto.getDistributeStatus() == 4) {
                 wfTextbookClaimMPJLambdaWrapper
                         .ne(WfTextbookClaim::getStatus, 1)
@@ -116,8 +126,9 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                         .eq(WfTextbookClaim::getStatus, dto.getDistributeStatus())
                 ;
             }
-
         }
+
+        // 流程状态(0:未结束,1:已结束,正常通过,2:已结束,未通过,3:作废)
         if (ObjectUtils.isNotEmpty(dto.getWorkflowStatus())) {
             wfTextbookClaimMPJLambdaWrapper
                     .eq(WfTextbookClaim::getWorkflowStatus, dto.getWorkflowStatus())
@@ -131,42 +142,98 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                     )
             ;
         }
+
         IPage<DistributePageVo> page = this.selectJoinListPage(ConventPage.getPage(dto), DistributePageVo.class, wfTextbookClaimMPJLambdaWrapper);
 
-        List<DistributePageVo> distributePageVos = page.getRecords();
-
-        // 处理申领总数量和已经发放总数量
-        if (ObjectUtils.isNotEmpty(distributePageVos)) {
-            List<Long> textbookClaimIds = distributePageVos.stream()
-                    .map(DistributePageVo::getId)
-                    .collect(Collectors.toList());
-            Map<Long, WfTextbookClaimItem> applicantTatolNumberMap = new HashMap<>();
-            WfTextbookClaimItem wfTextbookClaimItem;
-            if (ObjectUtils.isNotEmpty(textbookClaimIds)) {
-                MPJLambdaWrapper<WfTextbookClaimItem> wfTextbookClaimItemLambdaQueryWrapper = new MPJLambdaWrapper<>();
-                wfTextbookClaimItemLambdaQueryWrapper
-                        .selectAs(WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaimItem::getWfTextbookClaimId)
-                        .selectSum(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItem::getApplicantNumber)
-                        .selectSum(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItem::getIssueNumber)
-                        .in(WfTextbookClaimItem::getWfTextbookClaimId, textbookClaimIds)
-                        .groupBy(WfTextbookClaimItem::getWfTextbookClaimId)
-                ;
-                List<WfTextbookClaimItem> wfTextbookClaimItemList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItem.class, wfTextbookClaimItemLambdaQueryWrapper);
-                if (ObjectUtils.isNotEmpty(wfTextbookClaimItemList)) {
-                    applicantTatolNumberMap = wfTextbookClaimItemList.stream()
-                            .collect(Collectors.toMap(WfTextbookClaimItem::getWfTextbookClaimId, w -> w, (w1, w2) -> w1));
-                }
+        // 当申领记录为空
+        List<DistributePageVo> records = page.getRecords();
+
+        if(CollectionUtils.isEmpty(records)){
+            return page;
+        }
+
+        List<Long> claimIds = records.stream()
+                .map(DistributePageVo::getId)
+                .collect(Collectors.toList());
+
+        // 查询统计数据
+        MPJLambdaWrapper<WfTextbookClaimItem> statsWrapper = new MPJLambdaWrapper<>();
+        statsWrapper
+                .selectAs(WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaimItem::getWfTextbookClaimId)
+                .selectSum(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItem::getApplicantNumber)
+                .selectSum(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItem::getIssueNumber)
+                .in(WfTextbookClaimItem::getWfTextbookClaimId, claimIds)
+                .groupBy(WfTextbookClaimItem::getWfTextbookClaimId);
+
+        List<WfTextbookClaimItem> statsList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItem.class, statsWrapper);
+        Map<Long, WfTextbookClaimItem> statsMap = statsList.stream()
+                .collect(Collectors.toMap(
+                        WfTextbookClaimItem::getWfTextbookClaimId,
+                        Function.identity(),
+                        (w1, w2) -> w1)); // 可视情况记录冲突日志
+
+        // 查询子项数据
+        MPJLambdaWrapper<WfTextbookClaimItem> itemWrapper = new MPJLambdaWrapper<>();
+        itemWrapper.disableSubLogicDel()
+                .select(WfTextbookClaimItem::getId)
+                .selectAs(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItemVo::getApplicantNumber)
+                .selectAs(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItemVo::getIssueNumber)
+                .select(WfTextbookClaimItem.class, x -> VoToColumnUtil.fieldsToColumns(WfTextbookClaimItemVo.class).contains(x.getProperty()))
+                .leftJoin(Textbook.class, Textbook::getId, WfTextbookClaimItem::getTextbookId,
+                        w -> w
+                                .selectAs(Textbook::getBookName, DistributeRecordVo::getTextbookIdCn)
+                                .selectAs(Textbook::getIssn, DistributeRecordVo::getIssn))
+                .in(WfTextbookClaimItem::getWfTextbookClaimId, claimIds);
+
+        List<WfTextbookClaimItemVo> itemList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItemVo.class, itemWrapper);
+        Map<Long, List<WfTextbookClaimItemVo>> itemMap = itemList.stream()
+                .collect(Collectors.groupingBy(WfTextbookClaimItemVo::getWfTextbookClaimId));
+
+        // 查询发放记录
+        MPJLambdaWrapper<TextbookIssueRecord> recordWrapper = new MPJLambdaWrapper<>();
+        recordWrapper.disableSubLogicDel()
+                .selectAs(TextbookIssueRecord::getDataId, DistributeRecordVo::getWfTextbookClaimId)
+                .selectAs(TextbookIssueRecord::getDataItemId, DistributeRecordVo::getWfTextbookClaimItemId)
+                .selectAs(TextbookIssueRecord::getCreateDate, DistributeRecordVo::getIssueDate)
+                .selectAs(TextbookIssueRecord::getIssueNumber, DistributeRecordVo::getIssueNumber)
+                .selectAs(TextbookIssueRecord::getOrderNumber, DistributeRecordVo::getOrderNumber)
+                .selectAs(TextbookIssueRecord::getRemark, DistributeRecordVo::getRemark)
+                .leftJoin(Textbook.class, Textbook::getId, TextbookIssueRecord::getTextbookId,
+                        w -> w
+                                .selectAs(Textbook::getBookName, DistributeRecordVo::getTextbookIdCn)
+                                .selectAs(Textbook::getIssn, DistributeRecordVo::getIssn))
+                .leftJoin(XjrUser.class, XjrUser::getId, TextbookIssueRecord::getIssueUserId,
+                        w -> w
+                                .selectAs(XjrUser::getName, DistributeRecordVo::getIssueUser))
+                .in(TextbookIssueRecord::getDataId, claimIds);
+
+        List<DistributeRecordVo> recordList = textbookIssueRecordMapper.selectJoinList(DistributeRecordVo.class, recordWrapper);
+        Map<Long, List<DistributeRecordVo>> recordMap = recordList.stream()
+                .collect(Collectors.groupingBy(DistributeRecordVo::getWfTextbookClaimItemId));
+
+        // 组装数据
+        for (DistributePageVo vo : records) {
+            Long claimId = vo.getId();
+
+            // 填充统计信息
+            if (MapUtils.isNotEmpty(statsMap) && statsMap.containsKey(claimId)) {
+                WfTextbookClaimItem stat = statsMap.get(claimId);
+                vo.setApplicantTatolNumber(stat.getApplicantNumber());
+                vo.setIssueTatolNumber(stat.getIssueNumber());
             }
-            if (ObjectUtils.isNotEmpty(applicantTatolNumberMap)) {
-                for (DistributePageVo distributePageVo : page.getRecords()) {
-                    wfTextbookClaimItem = applicantTatolNumberMap.get(distributePageVo.getId());
-                    if (ObjectUtils.isNotEmpty(wfTextbookClaimItem)) {
-                        distributePageVo.setApplicantTatolNumber(wfTextbookClaimItem.getApplicantNumber());
-                        distributePageVo.setIssueTatolNumber(wfTextbookClaimItem.getIssueNumber());
+
+            // 填充子项及发放记录
+            if (MapUtils.isNotEmpty(itemMap) && CollectionUtils.isNotEmpty(itemMap.get(claimId))) {
+                List<WfTextbookClaimItemVo> items = itemMap.get(claimId);
+                for (WfTextbookClaimItemVo item : items) {
+                    if (recordMap.containsKey(item.getId())) {
+                        item.setDistributeRecordVos(recordMap.get(item.getId()));
                     }
                 }
+                vo.setWfTextbookClaimItemVoList(items);
             }
         }
+
         return page;
     }
 
@@ -324,6 +391,7 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
         return textbookIssueRecordMapper.selectJoinList(DistributeRecordVo.class, textbookIssueRecordMPJLambdaWrapper);
     }
 
+/*
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean confirmDistribute(ConfirmDistributeDto dto) {
@@ -339,6 +407,21 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
             issueTotalNum += wfTextbookClaimItem.getIssueNumber();
         }
 
+        // 如果是班级申领,获取班级所有学生
+        List<XjrUser> stuList = new ArrayList<>();
+        if (ClaimTypeEnum.ClaimStudent.getCode().equals(wfTextbookClaim.getClaimType())
+                && ObjectUtils.isNotEmpty(wfTextbookClaim.getClassId())
+        ) {
+            MPJLambdaWrapper<XjrUser> xjrUserMPJLambdaWrapper = new MPJLambdaWrapper<>();
+            xjrUserMPJLambdaWrapper
+                    .select(XjrUser::getId)
+                    .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, XjrUser::getId)
+                    .eq(BaseStudentSchoolRoll::getClassId, wfTextbookClaim.getClassId())
+                    .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+            ;
+            stuList = xjrUserMapper.selectJoinList(XjrUser.class, xjrUserMPJLambdaWrapper);
+        }
+
         // 获取所有入库记录
         List<Long> textbookWarehouseRecordIds = new ArrayList<>();
         for (ConfirmDistributeDto.TextbookClaimItem textbookClaimItem : dto.getTextbookClaimItemList()) {
@@ -406,7 +489,7 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
             WfTextbookClaimItem wfTextbookClaimItem = wfTextbookClaimItemMap.get(textbookClaimItem.getTextbookClaimItemId());
 
             if (ObjectUtils.isEmpty(wfTextbookClaimItem)) {
-                throw new MyException("未找到申领详细数据");
+                throw new MyException("申领详细数据发生更改,请刷新页面");
             }
 
             //判断总发放数量是否超出该申请项的申请数量
@@ -426,7 +509,7 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
             for (ConfirmDistributeDto.TextbookWarehouseRecords textbookWarehouseRecords : textbookClaimItem.getTextbookWarehouseRecords()) {
                 TextbookWarehouseRecord textbookWarehouseRecord = textbookWarehouseRecordMap.get(textbookWarehouseRecords.getTextbookWarehouseRecordId());
                 if (ObjectUtils.isEmpty(textbookWarehouseRecord)) {
-                    throw new MyException("未找到入库详细数据");
+                    throw new MyException("未找到对应入库详细数据");
                 }
 
                 if (textbookWarehouseRecord.getRemainNumber() < textbookWarehouseRecords.getConfirmNumber()) {
@@ -512,12 +595,16 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                 // 如果申领项是个人申领,发放的时候应该直接帮助学生确认领取
                 if (ClaimTypeEnum.ClaimStudent.getCode().equals(wfTextbookClaim.getClaimType())) {
                     oldTextbookStudentClaim = byUserIdAndTextbookId.get("" + wfTextbookClaim.getApplicantUserId() + wfTextbookClaimItem.getTextbookId());
-                    if (ObjectUtils.isNotEmpty(oldTextbookStudentClaim) && (ObjectUtils.isEmpty(oldTextbookStudentClaim.getClaimSource()) || oldTextbookStudentClaim.getClaimSource() != 1)) {
+                    if (ObjectUtils.isNotEmpty(oldTextbookStudentClaim)
+                            && (ObjectUtils.isEmpty(oldTextbookStudentClaim.getClaimSource())
+                            || oldTextbookStudentClaim.getClaimSource() != 1)
+                    ) {
                         updateTextbookStudentClaim = new TextbookStudentClaim();
                         updateTextbookStudentClaim.setId(oldTextbookStudentClaim.getId());
                         updateTextbookStudentClaim.setIsClaim(1);
                         updateTextbookStudentClaim.setModifyDate(nowDate);
                         updateTextbookStudentClaim.setModifyUserId(loginUserId);
+                        updateTextbookStudentClaim.setTextbookWarehouseRecordId(textbookWarehouseRecord.getId());
                         updateTextbookStudentClaim.setPrice(textbookWarehouseRecord.getSubtotal());
                         updateTextbookStudentClaim.setClaimSource(2);
                         updateList.add(updateTextbookStudentClaim);
@@ -530,11 +617,33 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
                         insertTextbookStudentClaim.setIsClaim(1);
                         insertTextbookStudentClaim.setCreateDate(nowDate);
                         insertTextbookStudentClaim.setCreateUserId(loginUserId);
+                        insertTextbookStudentClaim.setTextbookWarehouseRecordId(textbookWarehouseRecord.getId());
                         insertTextbookStudentClaim.setPrice(textbookWarehouseRecord.getSubtotal());
                         insertTextbookStudentClaim.setClaimSource(2);
                         insertList.add(insertTextbookStudentClaim);
                     }
                 }
+
+                // 如果申领项是班级申领,发放的时候应该直接生成领取记录
+                if (ClaimTypeEnum.ClaimClass.getCode().equals(wfTextbookClaim.getClaimType())) {
+                    for (XjrUser stu : stuList) {
+                        oldTextbookStudentClaim = byUserIdAndTextbookId.get("" + stu.getId() + wfTextbookClaimItem.getTextbookId());
+                        if (ObjectUtils.isEmpty(oldTextbookStudentClaim)) {
+                            insertTextbookStudentClaim = new TextbookStudentClaim();
+                            insertTextbookStudentClaim.setBaseSemesterId(wfTextbookClaim.getBaseSemesterId());
+                            insertTextbookStudentClaim.setClassId(wfTextbookClaim.getClassId());
+                            insertTextbookStudentClaim.setStudentUserId(stu.getId());
+                            insertTextbookStudentClaim.setTextbookId(wfTextbookClaimItem.getTextbookId());
+                            insertTextbookStudentClaim.setIsClaim(0);
+                            insertTextbookStudentClaim.setCreateDate(nowDate);
+                            insertTextbookStudentClaim.setCreateUserId(loginUserId);
+                            insertTextbookStudentClaim.setTextbookWarehouseRecordId(textbookWarehouseRecord.getId());
+                            insertTextbookStudentClaim.setPrice(textbookWarehouseRecord.getSubtotal());
+                            insertTextbookStudentClaim.setClaimSource(2);
+                            insertList.add(insertTextbookStudentClaim);
+                        }
+                    }
+                }
             }
 
             // 修改征订项发放数量
@@ -583,6 +692,381 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
         wfTextbookClaimWfTextbookClaimMapper.updateById(updateWfTextbookClaim);
         return true;
     }
+*/
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean confirmDistribute(ConfirmDistributeDto dto) {
+        // 1. 参数校验和初始化
+        validateInput(dto);
+
+        // 2. 获取基础数据
+        WfTextbookClaim claim = getClaimData(dto);
+        List<XjrUser> students = getRelatedStudents(claim);
+        Map<Long, TextbookWarehouseRecord> warehouseRecords = getWarehouseRecords(dto);
+
+        // 3. 处理发放逻辑
+        processDistribution(claim, dto, warehouseRecords, students);
+
+        // 4. 更新申领状态
+        updateClaimStatus(claim);
+
+        return true;
+    }
+
+    // 1. 参数校验和初始化
+    private void validateInput(ConfirmDistributeDto dto) {
+        if (ObjectUtils.isEmpty(dto.getTextbookClaimId())) {
+            throw new MyException("申领ID不能为空");
+        }
+        if (CollectionUtils.isEmpty(dto.getTextbookClaimItemList())) {
+            throw new MyException("申领项列表不能为空");
+        }
+    }
+
+    // 2. 获取申领数据
+    private WfTextbookClaim getClaimData(ConfirmDistributeDto dto) {
+        WfTextbookClaim claim = this.getByIdDeep(dto.getTextbookClaimId());
+        if (ObjectUtils.isEmpty(claim) || CollectionUtils.isEmpty(claim.getWfTextbookClaimItemList())) {
+            throw new MyException("未找到申领数据或申领项为空");
+        }
+        return claim;
+    }
+
+    // 2. 获取关联学生数据
+    private List<XjrUser> getRelatedStudents(WfTextbookClaim claim) {
+        if (!ClaimTypeEnum.ClaimClass.getCode().equals(claim.getClaimType()) ||
+                ObjectUtils.isEmpty(claim.getClassId())) {
+            return Collections.emptyList();
+        }
+
+        return xjrUserMapper.selectJoinList(XjrUser.class,
+                new MPJLambdaWrapper<XjrUser>()
+                        .select(XjrUser::getId)
+                        .innerJoin(BaseStudentSchoolRoll.class,
+                                BaseStudentSchoolRoll::getUserId, XjrUser::getId)
+                        .eq(BaseStudentSchoolRoll::getClassId, claim.getClassId())
+                        .eq(BaseStudentSchoolRoll::getArchivesStatus,
+                                ArchivesStatusEnum.FB2901.getCode()));
+    }
+
+    // 2. 获取关联的入库单号数据
+    private Map<Long, TextbookWarehouseRecord> getWarehouseRecords(ConfirmDistributeDto dto) {
+        List<Long> recordIds = dto.getTextbookClaimItemList().stream()
+                .flatMap(item -> item.getTextbookWarehouseRecords().stream()
+                        .map(ConfirmDistributeDto.TextbookWarehouseRecords::getTextbookWarehouseRecordId))
+                .collect(Collectors.toList());
+
+        if (CollectionUtils.isEmpty(recordIds)) {
+            throw new MyException("入库单号无效");
+        }
+
+        return textbookWarehouseRecordMapper.selectList(
+                        Wrappers.lambdaQuery(TextbookWarehouseRecord.class)
+                                .in(TextbookWarehouseRecord::getId, recordIds)
+                                .eq(TextbookWarehouseRecord::getDeleteMark, DeleteMark.NODELETE.getCode()))
+                .stream()
+                .collect(Collectors.toMap(TextbookWarehouseRecord::getId, Function.identity()));
+    }
+
+    // 3. 处理发放逻辑
+    private void processDistribution(WfTextbookClaim claim, ConfirmDistributeDto dto,
+                                     Map<Long, TextbookWarehouseRecord> warehouseRecords,
+                                     List<XjrUser> students) {
+        Date now = new Date();
+        Long userId = StpUtil.getLoginIdAsLong();
+        int issueTimes = claim.getIssueTimes() + 1;
+
+        // 获取现有领取记录
+        Map<String, TextbookStudentClaim> existingClaims = getExistingStudentClaims(claim);
+
+        // 处理每个申领项
+        for (ConfirmDistributeDto.TextbookClaimItem item : dto.getTextbookClaimItemList()) {
+            processClaimItem(dto, claim, item, warehouseRecords, students, existingClaims,
+                    now, userId, issueTimes);
+        }
+    }
+
+    // 获取现有领取记录
+    private Map<String, TextbookStudentClaim> getExistingStudentClaims(WfTextbookClaim claim) {
+        return textbookStudentClaimMapper.selectList(
+                        Wrappers.lambdaQuery(TextbookStudentClaim.class)
+                                .eq(TextbookStudentClaim::getBaseSemesterId, claim.getBaseSemesterId())
+                                .eq(TextbookStudentClaim::getClassId, claim.getClassId()))
+                .stream()
+                .collect(Collectors.toMap(
+                        t -> t.getStudentUserId() + "_" + t.getTextbookId(),
+                        Function.identity()));
+    }
+
+    private void processClaimItem(ConfirmDistributeDto dto, WfTextbookClaim claim,
+                                  ConfirmDistributeDto.TextbookClaimItem item,
+                                  Map<Long, TextbookWarehouseRecord> warehouseRecords,
+                                  List<XjrUser> students,
+                                  Map<String, TextbookStudentClaim> existingClaims,
+                                  Date now, Long userId, int issueTimes) {
+        WfTextbookClaimItem claimItem = claim.getWfTextbookClaimItemList().stream()
+                .filter(i -> i.getId().equals(item.getTextbookClaimItemId()))
+                .findFirst()
+                .orElseThrow(() -> new MyException("申领详细数据发生更改"));
+
+        validateIssueQuantity(claimItem, item);
+
+        // 处理每个入库记录
+        for (ConfirmDistributeDto.TextbookWarehouseRecords record : item.getTextbookWarehouseRecords()) {
+            TextbookWarehouseRecord warehouseRecord = warehouseRecords.get(record.getTextbookWarehouseRecordId());
+            if (warehouseRecord == null) {
+                throw new MyException("未找到对应入库详细数据");
+            }
+
+            // 验证发放数量是否合法
+            validateRemainingQuantity(warehouseRecord, record, item);
+
+            // 更新库存
+            updateWarehouseRecord(warehouseRecord, record, now, userId);
+
+            // 创建出库记录
+            TextbookIssueRecord issueRecord = createIssueRecord(claim, claimItem, warehouseRecord, dto,
+                    record, now, userId, issueTimes);
+            textbookIssueRecordMapper.insert(issueRecord);
+
+            // 处理学生领取记录
+            processStudentClaims(claim, claimItem, warehouseRecord, students,
+                    existingClaims, now, userId);
+        }
+
+        // 更新申领项
+        updateClaimItem(claimItem, item.getConfirmTotalNumber());
+    }
+
+    // 验证发放数量是否合法
+    private void validateIssueQuantity(WfTextbookClaimItem claimItem,
+                                       ConfirmDistributeDto.TextbookClaimItem item) {
+        int issued = ObjectUtils.defaultIfNull(claimItem.getIssueNumber(), 0);
+        int applied = ObjectUtils.defaultIfNull(claimItem.getApplicantNumber(), 0);
+        int confirming = ObjectUtils.defaultIfNull(item.getConfirmTotalNumber(), 0);
+
+        if (issued + confirming > applied) {
+            throw new MyException(String.format(
+                    "教材[%s]发放总数量(%d)超出申领数量(%d)",
+                    item.getTextbookIdCn(),
+                    issued + confirming,
+                    applied
+            ));
+        }
+    }
+
+    // 验证库存是否充足
+    private void validateRemainingQuantity(TextbookWarehouseRecord warehouseRecord,
+                                           ConfirmDistributeDto.TextbookWarehouseRecords record,
+                                           ConfirmDistributeDto.TextbookClaimItem item
+    ) {
+        int remaining = ObjectUtils.defaultIfNull(warehouseRecord.getRemainNumber(), 0);
+        int confirming = ObjectUtils.defaultIfNull(record.getConfirmNumber(), 0);
+
+        if (remaining < confirming) {
+            throw new MyException(String.format(
+                    "教材[%s]发放数量(%d)大于库存剩余数量(%d)",
+                    item.getTextbookIdCn(),
+                    confirming,
+                    remaining
+            ));
+        }
+    }
+
+    // 验证库存是否充足
+    private void updateWarehouseRecord(TextbookWarehouseRecord record,
+                                       ConfirmDistributeDto.TextbookWarehouseRecords confirmRecord,
+                                       Date now, Long userId) {
+        TextbookWarehouseRecord update = new TextbookWarehouseRecord();
+        update.setId(record.getId());
+        update.setModifyUserId(userId);
+        update.setModifyDate(now);
+        update.setIssuedNumber(ObjectUtils.defaultIfNull(record.getIssuedNumber(), 0)
+                + confirmRecord.getConfirmNumber());
+        update.setRemainNumber(ObjectUtils.defaultIfNull(record.getRemainNumber(), 0)
+                - confirmRecord.getConfirmNumber());
+
+        textbookWarehouseRecordMapper.updateById(update);
+    }
+
+    // 创建出库记录
+    private TextbookIssueRecord createIssueRecord(WfTextbookClaim claim,
+                                                  WfTextbookClaimItem claimItem,
+                                                  TextbookWarehouseRecord warehouseRecord,
+                                                  ConfirmDistributeDto dto,
+                                                  ConfirmDistributeDto.TextbookWarehouseRecords confirmRecord,
+                                                  Date now, Long userId, int issueTimes) {
+        // 生成出库单号
+        String orderNumber = generateOrderNumber(claimItem.getId(), warehouseRecord.getId());
+
+        TextbookIssueRecord record = new TextbookIssueRecord();
+        record.setBaseSemesterId(claim.getBaseSemesterId());
+        record.setOrderNumber(orderNumber);
+        record.setIssueMode(getIssueMode(claim.getClaimType()));
+        record.setDataId(claim.getId());
+        record.setDataItemId(claimItem.getId());
+        record.setTextbookWarehouseRecordId(warehouseRecord.getId());
+        record.setTextbookId(claimItem.getTextbookId());
+        record.setIssueNumber(confirmRecord.getConfirmNumber());
+        record.setRecedeNumber(0);
+        record.setActualIssueNumber(confirmRecord.getConfirmNumber());
+        record.setActualTotalPrice(
+                warehouseRecord.getSubtotal().multiply(BigDecimal.valueOf(confirmRecord.getConfirmNumber()))
+        );
+
+        if (ObjectUtils.isNotEmpty(dto.getReceiveUserId())) {
+            record.setReceiveUserId(dto.getReceiveUserId());
+        } else {
+            record.setReceiveUserId(claim.getApplicantUserId());
+        }
+        record.setIssueUserId(userId);
+        record.setCreateDate(now);
+        record.setRemark(dto.getRemark());
+        record.setIssueTimes(issueTimes);
+
+        return record;
+    }
+
+    // 构造出库单号
+    private String generateOrderNumber(Long claimItemId, Long warehouseRecordId) {
+        LambdaQueryWrapper<TextbookIssueRecord> query = Wrappers.lambdaQuery(TextbookIssueRecord.class)
+                .eq(TextbookIssueRecord::getDataItemId, claimItemId)
+                .eq(TextbookIssueRecord::getTextbookWarehouseRecordId, warehouseRecordId)
+                .eq(TextbookIssueRecord::getDeleteMark, DeleteMark.NODELETE.getCode())
+                .orderByDesc(TextbookIssueRecord::getOrderNumber)
+                .last("LIMIT 1");
+
+        TextbookIssueRecord lastRecord = textbookIssueRecordMapper.selectOne(query);
+
+        if (lastRecord != null) {
+            // 已有记录则递增序号
+            String[] parts = lastRecord.getOrderNumber().split("-");
+            int seq = Integer.parseInt(parts[parts.length - 1]) + 1;
+            return parts[0] + "-" + String.format("%03d", seq);
+        } else {
+            // 新记录生成初始单号
+            return "CK" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
+                    + "-001";
+        }
+    }
+
+    // 判定申领类型
+    private String getIssueMode(String claimType) {
+        if (ClaimTypeEnum.ClaimStudent.getCode().equals(claimType)) {
+            return IssueModeEnum.ImStudent.getCode();
+        } else if (ClaimTypeEnum.ClaimClass.getCode().equals(claimType)) {
+            return IssueModeEnum.ImClass.getCode();
+        } else if (ClaimTypeEnum.ClaimTeacher.getCode().equals(claimType)) {
+            return IssueModeEnum.ImTeacher.getCode();
+        }
+        throw new MyException("未知的申领类型: " + claimType);
+    }
+
+    // 处理学生领取记录
+    private void processStudentClaims(WfTextbookClaim claim,
+                                      WfTextbookClaimItem claimItem,
+                                      TextbookWarehouseRecord warehouseRecord,
+                                      List<XjrUser> students,
+                                      Map<String, TextbookStudentClaim> existingClaims,
+                                      Date now, Long userId) {
+        List<TextbookStudentClaim> toInsert = new ArrayList<>();
+        List<TextbookStudentClaim> toUpdate = new ArrayList<>();
+
+        if (ClaimTypeEnum.ClaimStudent.getCode().equals(claim.getClaimType())) {
+            // 个人申领直接确认
+            handleStudentClaim(claim.getApplicantUserId(), claim, claimItem,
+                    warehouseRecord, existingClaims, now, userId, toInsert, toUpdate);
+        } else if (ClaimTypeEnum.ClaimClass.getCode().equals(claim.getClaimType())) {
+            // 班级申领为每个学生生成记录
+            students.forEach(student ->
+                    handleStudentClaim(student.getId(), claim, claimItem,
+                            warehouseRecord, existingClaims, now, userId, toInsert, toUpdate));
+        }
+
+        // 批量操作
+        if (!toInsert.isEmpty()) {
+            for (TextbookStudentClaim insert : toInsert){
+                textbookStudentClaimMapper.insert(insert);
+            }
+
+        }
+        if (!toUpdate.isEmpty()) {
+            for (TextbookStudentClaim update : toUpdate){
+                textbookStudentClaimMapper.updateById(update);
+            }
+        }
+    }
+
+    // 新增或修改领取记录
+    private void handleStudentClaim(Long studentId,
+                                    WfTextbookClaim claim,
+                                    WfTextbookClaimItem claimItem,
+                                    TextbookWarehouseRecord warehouseRecord,
+                                    Map<String, TextbookStudentClaim> existingClaims,
+                                    Date now, Long userId,
+                                    List<TextbookStudentClaim> toInsert,
+                                    List<TextbookStudentClaim> toUpdate) {
+        String key = studentId + "_" + claimItem.getTextbookId();
+        TextbookStudentClaim existing = existingClaims.get(key);
+
+        if (existing != null) {
+            if ((ClaimTypeEnum.ClaimStudent.getCode().equals(claim.getClaimType()))
+                    && !Integer.valueOf(1).equals(existing.getIsClaim())
+            ) {
+                TextbookStudentClaim update = new TextbookStudentClaim();
+                update.setId(existing.getId());
+                update.setIsClaim(1);
+                update.setModifyDate(now);
+                update.setModifyUserId(userId);
+                update.setTextbookWarehouseRecordId(warehouseRecord.getId());
+                update.setPrice(warehouseRecord.getSubtotal());
+                update.setClaimSource(2); // 管理员发放
+                toUpdate.add(update);
+            }
+        } else {
+            TextbookStudentClaim insert = new TextbookStudentClaim();
+            insert.setBaseSemesterId(claim.getBaseSemesterId());
+            insert.setClassId(claim.getClassId());
+            insert.setStudentUserId(studentId);
+            insert.setTextbookId(claimItem.getTextbookId());
+            insert.setIsClaim(ClaimTypeEnum.ClaimStudent.getCode().equals(claim.getClaimType()) ? 1 : 0);
+            insert.setCreateDate(now);
+            insert.setCreateUserId(userId);
+            insert.setTextbookWarehouseRecordId(warehouseRecord.getId());
+            insert.setPrice(warehouseRecord.getSubtotal());
+            insert.setClaimSource(2); // 管理员发放
+            toInsert.add(insert);
+        }
+    }
+
+    // 更新申领项
+    private void updateClaimItem(WfTextbookClaimItem claimItem, int confirmNumber) {
+        WfTextbookClaimItem update = new WfTextbookClaimItem();
+        update.setId(claimItem.getId());
+        update.setIssueNumber(ObjectUtils.defaultIfNull(claimItem.getIssueNumber(), 0) + confirmNumber);
+        wfTextbookClaimWfTextbookClaimItemMapper.updateById(update);
+    }
+
+    // 4. 更新申领状态
+    private void updateClaimStatus(WfTextbookClaim claim) {
+        long incompleteItems = wfTextbookClaimWfTextbookClaimItemMapper.selectCount(
+                new MPJLambdaWrapper<WfTextbookClaimItem>()
+                        .select(WfTextbookClaimItem::getId)
+                        .innerJoin(WfTextbookClaim.class,
+                                WfTextbookClaim::getId, WfTextbookClaimItem::getWfTextbookClaimId)
+                        .lt(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItem::getApplicantNumber)
+                        .eq(WfTextbookClaimItem::getWfTextbookClaimId, claim.getId()));
+
+        WfTextbookClaim update = new WfTextbookClaim();
+        update.setId(claim.getId());
+        update.setStatus(incompleteItems > 0 ? 2 : 3);
+        update.setIssueTimes(claim.getIssueTimes() + 1);
+        update.setModifyUserId(StpUtil.getLoginIdAsLong());
+        update.setModifyDate(new Date());
+
+        wfTextbookClaimWfTextbookClaimMapper.updateById(update);
+    }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -692,7 +1176,7 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
     }
 
     @Override
-    public ByteArrayOutputStream claimRecordsExportQuery(ClaimRecordsExportQueryDto dto) {
+    public ByteArrayOutputStream claimRecordsExportQuery(ClaimRecordsExportQueryDto dto) throws IOException {
         MPJLambdaWrapper<WfTextbookClaim> wfTextbookClaimMPJLambdaWrapper = new MPJLambdaWrapper<>();
         wfTextbookClaimMPJLambdaWrapper
                 .disableSubLogicDel()
@@ -719,39 +1203,112 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
         ;
         List<ClaimRecordsExportQueryVo> dataList = this.selectJoinList(ClaimRecordsExportQueryVo.class, wfTextbookClaimMPJLambdaWrapper);
 
-        // 处理申领总数量和已经发放总数量
-        if (ObjectUtils.isNotEmpty(dataList)) {
-            List<Long> textbookClaimIds = dataList.stream()
-                    .map(ClaimRecordsExportQueryVo::getId)
-                    .collect(Collectors.toList());
-            Map<Long, WfTextbookClaimItem> applicantTatolNumberMap = new HashMap<>();
-            WfTextbookClaimItem wfTextbookClaimItem;
-            if (ObjectUtils.isNotEmpty(textbookClaimIds)) {
-                MPJLambdaWrapper<WfTextbookClaimItem> wfTextbookClaimItemLambdaQueryWrapper = new MPJLambdaWrapper<>();
-                wfTextbookClaimItemLambdaQueryWrapper
-                        .selectAs(WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaimItem::getWfTextbookClaimId)
-                        .selectSum(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItem::getApplicantNumber)
-                        .selectSum(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItem::getIssueNumber)
-                        .in(WfTextbookClaimItem::getWfTextbookClaimId, textbookClaimIds)
-                        .groupBy(WfTextbookClaimItem::getWfTextbookClaimId)
-                ;
-                List<WfTextbookClaimItem> wfTextbookClaimItemList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItem.class, wfTextbookClaimItemLambdaQueryWrapper);
-                if (ObjectUtils.isNotEmpty(wfTextbookClaimItemList)) {
-                    applicantTatolNumberMap = wfTextbookClaimItemList.stream()
-                            .collect(Collectors.toMap(WfTextbookClaimItem::getWfTextbookClaimId, w -> w, (w1, w2) -> w1));
-                }
-            }
-            if (ObjectUtils.isNotEmpty(applicantTatolNumberMap)) {
-                for (ClaimRecordsExportQueryVo vo : dataList) {
-                    wfTextbookClaimItem = applicantTatolNumberMap.get(vo.getId());
-                    if (ObjectUtils.isNotEmpty(wfTextbookClaimItem)) {
-                        vo.setApplicantTatolNumber(wfTextbookClaimItem.getApplicantNumber());
-                        vo.setIssueTatolNumber(wfTextbookClaimItem.getIssueNumber());
-                    }
-                }
-            }
-        }
-
+        List<Long> claimIds = dataList.stream()
+                .map(ClaimRecordsExportQueryVo::getId)
+                .collect(Collectors.toList());
+
+        // 查询统计数据
+        MPJLambdaWrapper<WfTextbookClaimItem> statsWrapper = new MPJLambdaWrapper<>();
+        statsWrapper
+                .selectAs(WfTextbookClaimItem::getWfTextbookClaimId, WfTextbookClaimItem::getWfTextbookClaimId)
+                .selectSum(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItem::getApplicantNumber)
+                .selectSum(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItem::getIssueNumber)
+                .in(WfTextbookClaimItem::getWfTextbookClaimId, claimIds)
+                .groupBy(WfTextbookClaimItem::getWfTextbookClaimId);
+
+        List<WfTextbookClaimItem> statsList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItem.class, statsWrapper);
+        Map<Long, WfTextbookClaimItem> statsMap = statsList.stream()
+                .collect(Collectors.toMap(
+                        WfTextbookClaimItem::getWfTextbookClaimId,
+                        Function.identity(),
+                        (w1, w2) -> w1)); // 可视情况记录冲突日志
+
+        // 查询子项数据
+        MPJLambdaWrapper<WfTextbookClaimItem> itemWrapper = new MPJLambdaWrapper<>();
+        itemWrapper.disableSubLogicDel()
+                .select(WfTextbookClaimItem::getId)
+                .selectAs(WfTextbookClaimItem::getApplicantNumber, WfTextbookClaimItemVo::getApplicantNumber)
+                .selectAs(WfTextbookClaimItem::getIssueNumber, WfTextbookClaimItemVo::getIssueNumber)
+                .select(WfTextbookClaimItem.class, x -> VoToColumnUtil.fieldsToColumns(WfTextbookClaimItemVo.class).contains(x.getProperty()))
+                .leftJoin(Textbook.class, Textbook::getId, WfTextbookClaimItem::getTextbookId,
+                        w -> w
+                                .selectAs(Textbook::getBookName, DistributeRecordVo::getTextbookIdCn)
+                                .selectAs(Textbook::getIssn, DistributeRecordVo::getIssn))
+                .in(WfTextbookClaimItem::getWfTextbookClaimId, claimIds);
+
+        List<WfTextbookClaimItemVo> itemList = wfTextbookClaimWfTextbookClaimItemMapper.selectJoinList(WfTextbookClaimItemVo.class, itemWrapper);
+        Map<Long, List<WfTextbookClaimItemVo>> itemMap = itemList.stream()
+                .collect(Collectors.groupingBy(WfTextbookClaimItemVo::getWfTextbookClaimId));
+
+        // 查询发放记录
+        MPJLambdaWrapper<TextbookIssueRecord> recordWrapper = new MPJLambdaWrapper<>();
+        recordWrapper.disableSubLogicDel()
+                .selectAs(TextbookIssueRecord::getDataId, DistributeRecordVo::getWfTextbookClaimId)
+                .selectAs(TextbookIssueRecord::getDataItemId, DistributeRecordVo::getWfTextbookClaimItemId)
+                .selectAs(TextbookIssueRecord::getCreateDate, DistributeRecordVo::getIssueDate)
+                .selectAs(TextbookIssueRecord::getIssueNumber, DistributeRecordVo::getIssueNumber)
+                .selectAs(TextbookIssueRecord::getOrderNumber, DistributeRecordVo::getOrderNumber)
+                .selectAs(TextbookIssueRecord::getRemark, DistributeRecordVo::getRemark)
+                .leftJoin(Textbook.class, Textbook::getId, TextbookIssueRecord::getTextbookId,
+                        w -> w
+                                .selectAs(Textbook::getBookName, DistributeRecordVo::getTextbookIdCn)
+                                .selectAs(Textbook::getIssn, DistributeRecordVo::getIssn))
+                .leftJoin(XjrUser.class, XjrUser::getId, TextbookIssueRecord::getIssueUserId,
+                        w -> w
+                                .selectAs(XjrUser::getName, DistributeRecordVo::getIssueUser))
+                .in(TextbookIssueRecord::getDataId, claimIds);
+
+        List<DistributeRecordVo> recordList = textbookIssueRecordMapper.selectJoinList(DistributeRecordVo.class, recordWrapper);
+        Map<Long, List<DistributeRecordVo>> recordMap = recordList.stream()
+                .collect(Collectors.groupingBy(DistributeRecordVo::getWfTextbookClaimItemId));
+
+        // 开始写入
+        Workbook workbook = new XSSFWorkbook();
+        // 创建一个工作表(sheet)
+        String sheetName = "sheet1";
+        Sheet sheet = workbook.createSheet(sheetName);
+
+        // 出参vo字段数量
+        ClaimRecordsExportQueryVo obj = new ClaimRecordsExportQueryVo();
+        List<ImportConfig> importConfigs = ImportExcelUtil.allFields(obj);
+
+        // 写大标题
+        int rowNumber = 0;
+        ImportExcelUtil.createBigHead(workbook, sheet, "教材申领情况", rowNumber++, importConfigs.size() - 1);
+
+        // 表头
+        ImportExcelUtil.createHead(workbook, sheet, importConfigs, IndexedColors.YELLOW.getIndex(), IndexedColors.RED.getIndex(), rowNumber++);
+
+        // 字体内容格式
+        Font font = workbook.createFont();
+        font.setBold(false);// 设置为粗体
+        font.setFontName("宋体");
+        font.setFontHeightInPoints((short) 12);
+
+        // 单元格样式
+        CellStyle cellStyle = workbook.createCellStyle();
+        cellStyle.setFont(font); // 将字体应用到样式
+        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        cellStyle.setAlignment(HorizontalAlignment.CENTER);
+
+        // 设置边框样式为细线
+        cellStyle.setBorderTop(BorderStyle.THIN);
+        cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 设置顶部边框颜色
+
+        cellStyle.setBorderBottom(BorderStyle.THIN);
+        cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 设置底部边框颜色
+
+        cellStyle.setBorderLeft(BorderStyle.THIN);
+        cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 设置左边框颜色
+
+        cellStyle.setBorderRight(BorderStyle.THIN);
+        cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 设置右边框颜色
+
+        // 记录写入
+        List<String> claimVo;
+        List<String> claimItemVo;
+        List<String> claimItemIssueVo;
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
         for (ClaimRecordsExportQueryVo vo : dataList) {
             if (ObjectUtils.isNotEmpty(vo.getClaimType()) && ClaimTypeEnum.ClaimClass.getCode().equals(vo.getClaimType())) {
                 vo.setReceiver(vo.getClassIdCn());
@@ -767,11 +1324,105 @@ public class WfTextbookClaimServiceImpl extends MPJBaseServiceImpl<WfTextbookCla
             } else {
                 vo.setStatusStr("未发放");
             }
+
+            Long claimId = vo.getId();
+
+            // 填充统计信息
+            if (MapUtils.isNotEmpty(statsMap) && statsMap.containsKey(claimId)) {
+                WfTextbookClaimItem stat = statsMap.get(claimId);
+                vo.setApplicantTatolNumber(stat.getApplicantNumber());
+                vo.setIssueTatolNumber(stat.getIssueNumber());
+            }
+
+            // 申领总记录
+            claimVo = new ArrayList<>();
+            claimVo.add(vo.getBaseSemesterIdCn());
+            claimVo.add(vo.getClaimTypeCn());
+            claimVo.add(vo.getReceiver());
+            if (StringUtils.isNotEmpty(vo.getClassIdCn())) {
+                claimVo.add(vo.getClassIdCn());
+            } else {
+                claimVo.add("无");
+            }
+            claimVo.add(vo.getApplicantTatolNumber() + "");
+            claimVo.add(vo.getStatusStr());
+            claimVo.add(vo.getIssueTatolNumber() + "");
+
+            // 填充子项及发放记录
+            int mergeClaim = 0;
+            if (MapUtils.isNotEmpty(itemMap) && CollectionUtils.isNotEmpty(itemMap.get(claimId))) {
+                List<WfTextbookClaimItemVo> items = itemMap.get(claimId);
+                for (WfTextbookClaimItemVo item : items) {
+                    mergeClaim++;
+                    claimItemVo = new ArrayList<>(claimVo);
+                    claimItemVo.add(item.getTextbookIdCN());
+                    claimItemVo.add(item.getIssn());
+                    claimItemVo.add(item.getApplicantNumber() + "");
+                    claimItemVo.add(item.getIssueNumber() + "");
+
+                    int mergeClaimItem = 0;
+                    if (recordMap.containsKey(item.getId())) {
+                        List<DistributeRecordVo> issues = recordMap.get(item.getId());
+                        for (DistributeRecordVo issue : issues) {
+                            mergeClaimItem++;
+                            claimItemIssueVo = new ArrayList<>(claimItemVo);
+                            LocalDateTime localDateTime = issue.getIssueDate().toInstant()
+                                    .atZone(ZoneId.systemDefault())
+                                    .toLocalDateTime();
+                            claimItemIssueVo.add(localDateTime.format(formatter));
+                            claimItemIssueVo.add(issue.getIssueUser());
+                            claimItemIssueVo.add(issue.getOrderNumber());
+                            claimItemIssueVo.add(issue.getIssueNumber() + "");
+
+                            Row dataRow = sheet.createRow(rowNumber++);
+                            for (int j = 0; j < claimItemIssueVo.size(); j++) {
+                                String content = claimItemIssueVo.get(j);
+                                Cell cell = dataRow.createCell(j);
+                                cell.setCellValue(content);
+                                cell.setCellStyle(cellStyle);
+                            }
+                        }
+                        // 合并申领项
+                        if (mergeClaimItem > 1) {
+                            for (int k = 7; k < 11; k++) {
+                                sheet.addMergedRegion(new CellRangeAddress(rowNumber - mergeClaimItem, rowNumber - 1, k, k));
+                            }
+                        }
+                    } else {
+                        Row dataRow = sheet.createRow(rowNumber++);
+                        for (int j = 0; j < claimItemVo.size(); j++) {
+                            String content = claimItemVo.get(j);
+                            Cell cell = dataRow.createCell(j);
+                            cell.setCellValue(content);
+                            cell.setCellStyle(cellStyle);
+                        }
+                    }
+                }
+
+                // 合并申领
+                if (mergeClaim > 1) {
+                    for (int k = 0; k < 7; k++) {
+                        sheet.addMergedRegion(new CellRangeAddress(rowNumber - mergeClaim, rowNumber - 1, k, k));
+                    }
+                }
+            } else {
+                Row dataRow = sheet.createRow(rowNumber++);
+                for (int j = 0; j < claimVo.size(); j++) {
+                    String content = claimVo.get(j);
+                    Cell cell = dataRow.createCell(j);
+                    cell.setCellValue(content);
+                    cell.setCellStyle(cellStyle);
+                }
+            }
         }
 
-        ByteArrayOutputStream bot = new ByteArrayOutputStream();
-        EasyExcel.write(bot, ClaimRecordsExportQueryVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(dataList);
+        // 自动列宽
+        for (int i = 0; i < importConfigs.size(); i++) {
+            sheet.autoSizeColumn(i);
+        }
 
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        workbook.write(bot);
         return bot;
     }
 }

+ 100 - 0
src/main/java/com/xjrsoft/module/textbook/vo/AllStuClaimExportQueryVo.java

@@ -0,0 +1,100 @@
+package com.xjrsoft.module.textbook.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class AllStuClaimExportQueryVo {
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("学期")
+    @ApiModelProperty("学期ID(base_semester)")
+    private String baseSemesterIdCn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelIgnore
+    @ApiModelProperty("申领类型(xjr_dictionary_item[claim_type])")
+    private String claimType;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("申领类型")
+    @ApiModelProperty("申领类型(xjr_dictionary_item[claim_type])")
+    private String claimTypeCn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("领取人")
+    @ApiModelProperty("领取人")
+    private String receiver;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelIgnore
+    @ApiModelProperty("申请人")
+    private String applicantUserIdCn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("班级名称")
+    @ApiModelProperty("班级名称")
+    private String classIdCn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("申请数量")
+    @ApiModelProperty("申请总数量")
+    private Integer applicantTatolNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelIgnore
+    @ApiModelProperty("状态()")
+    private Integer status;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("发放状态")
+    @ApiModelProperty("状态()")
+    private String statusStr;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("发放数量")
+    @ApiModelProperty("已经发放总数量")
+    private Integer issueTatolNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材名称")
+    @ApiModelProperty("教材名称")
+    private String textbookIdCN;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("国际标准刊号")
+    @ApiModelProperty("国际标准刊号")
+    private String issn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("申请数量")
+    @ApiModelProperty("申请数量")
+    private Integer applicantNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("已发放数量")
+    @ApiModelProperty("已发放数量")
+    private Integer issueNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库时间")
+    @ApiModelProperty("出库时间")
+    private String issueDate;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库人员")
+    @ApiModelProperty("出库人员")
+    private String issueUser;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库单号")
+    @ApiModelProperty("出库单号(标识+当前时间(YYYYMMDDHHmmss)+三位序号+当前申领项出库次数(-n))")
+    private String orderNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("单次出库数量")
+    @ApiModelProperty("单次出库数量")
+    private Integer onceIssueNumber;
+}

+ 46 - 2
src/main/java/com/xjrsoft/module/textbook/vo/ClaimRecordsExportQueryVo.java

@@ -6,8 +6,12 @@ import com.alibaba.excel.annotation.write.style.ContentStyle;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.util.Date;
+import java.util.List;
+
 @Data
 public class ClaimRecordsExportQueryVo {
+    @ContentStyle(dataFormat = 49)
     @ExcelIgnore
     @ApiModelProperty("主键编号")
     private Long id;
@@ -38,8 +42,8 @@ public class ClaimRecordsExportQueryVo {
     private String applicantUserIdCn;
 
     @ContentStyle(dataFormat = 49)
-    @ExcelIgnore
-    @ApiModelProperty("班级编号")
+    @ExcelProperty("班级名称")
+    @ApiModelProperty("班级名称")
     private String classIdCn;
 
     @ContentStyle(dataFormat = 49)
@@ -61,4 +65,44 @@ public class ClaimRecordsExportQueryVo {
     @ExcelProperty("发放数量")
     @ApiModelProperty("已经发放总数量")
     private Integer issueTatolNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("教材名称")
+    @ApiModelProperty("教材名称")
+    private String textbookIdCN;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("国际标准刊号")
+    @ApiModelProperty("国际标准刊号")
+    private String issn;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("申请数量")
+    @ApiModelProperty("申请数量")
+    private Integer applicantNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("已发放数量")
+    @ApiModelProperty("已发放数量")
+    private Integer issueNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库时间")
+    @ApiModelProperty("出库时间")
+    private String issueDate;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库人员")
+    @ApiModelProperty("出库人员")
+    private String issueUser;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("出库单号")
+    @ApiModelProperty("出库单号(标识+当前时间(YYYYMMDDHHmmss)+三位序号+当前申领项出库次数(-n))")
+    private String orderNumber;
+
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("单次出库数量")
+    @ApiModelProperty("单次出库数量")
+    private Integer onceIssueNumber;
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/textbook/vo/ClassClaimTextbookIssuePrice.java

@@ -17,6 +17,9 @@ public class ClassClaimTextbookIssuePrice {
     @ApiModelProperty("教材管理编号")
     private Long textbookId;
 
+    @ApiModelProperty("教材发放的入库的编号")
+    private Long textbookWarehouseRecordId;
+
     @ApiModelProperty("教材发放的入库的价格")
     private BigDecimal price;
 }

+ 4 - 0
src/main/java/com/xjrsoft/module/textbook/vo/DistributePageVo.java

@@ -7,6 +7,7 @@ import lombok.Data;
 
 import java.time.LocalDateTime;
 import java.util.Date;
+import java.util.List;
 
 @Data
 public class DistributePageVo {
@@ -61,4 +62,7 @@ public class DistributePageVo {
 
     @ApiModelProperty("创建时间")
     private LocalDateTime createDate;
+
+    @ApiModelProperty("申领子项集合")
+    List<WfTextbookClaimItemVo> wfTextbookClaimItemVoList;
 }

+ 16 - 1
src/main/java/com/xjrsoft/module/textbook/vo/DistributeRecordVo.java

@@ -13,7 +13,16 @@ import java.util.Date;
  */
 @Data
 public class DistributeRecordVo {
-
+    /**
+     * 教材申领编号
+     */
+    @ApiModelProperty("教材申领编号")
+    private Long wfTextbookClaimId;
+    /**
+     * 教材申领子项编号
+     */
+    @ApiModelProperty("教材申领子项编号")
+    private Long wfTextbookClaimItemId;
     /**
      * 出库时间
      */
@@ -32,6 +41,12 @@ public class DistributeRecordVo {
     @ApiModelProperty("教材管理编号")
     private String textbookIdCn;
 
+    /**
+     * 国际标准刊号
+     */
+    @ApiModelProperty("国际标准刊号")
+    private String issn;
+
     /**
      * 出库单号(标识+当前时间(YYYYMMDDHHmmss)+三位序号+当前申领项出库次数(-n))
      */

+ 11 - 4
src/main/java/com/xjrsoft/module/textbook/vo/TextbookDiscountAlterRecordListVo.java

@@ -66,16 +66,23 @@ public class TextbookDiscountAlterRecordListVo {
     /**
      * 旧的折扣
      */
-    @ContentStyle(dataFormat = 49)
-    @ExcelProperty("旧的折扣")
     @ApiModelProperty("旧的折扣")
     private Double oldDiscount;
     /**
      * 新的折扣
      */
-    @ContentStyle(dataFormat = 49)
-    @ExcelProperty("新的折扣")
     @ApiModelProperty("新的折扣")
     private Double newDiscount;
 
+    /**
+     * 旧的入库数量
+     */
+    @ApiModelProperty("旧的入库数量")
+    private Integer oldWarehouseNum;
+    /**
+     * 新的入库数量
+     */
+    @ApiModelProperty("新的入库数量")
+    private Integer newWarehouseNum;
+
 }

+ 11 - 5
src/main/java/com/xjrsoft/module/textbook/vo/WfTextbookClaimItemVo.java

@@ -1,8 +1,12 @@
 package com.xjrsoft.module.textbook.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.List;
+
 /**
  * @title: 教材申领项表单出参
  * @Author szs
@@ -17,11 +21,6 @@ public class WfTextbookClaimItemVo {
      */
     @ApiModelProperty("主键编号")
     private Long id;
-    /**
-     * 序号
-     */
-    @ApiModelProperty("序号")
-    private Integer sortCode;
     /**
      * 教材申领编号
      */
@@ -37,6 +36,11 @@ public class WfTextbookClaimItemVo {
      */
     @ApiModelProperty("教材管理编号")
     private String textbookIdCN;
+    /**
+     * 国际标准刊号
+     */
+    @ApiModelProperty("国际标准刊号")
+    private String issn;
     /**
      * 申请数量
      */
@@ -48,4 +52,6 @@ public class WfTextbookClaimItemVo {
     @ApiModelProperty("已发放数量")
     private Integer issueNumber;
 
+    @ApiModelProperty("当前申领子项领取情况")
+    List<DistributeRecordVo> distributeRecordVos;
 }

+ 3 - 4
src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java

@@ -1656,16 +1656,16 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                 List<WorkflowRecord> recordList = mapRecords.get(task.getProcessInstanceId());
                 if (recordList != null && recordList.size() > 1) {
                     String comment = recordList.get(recordList.size() - 1).getMessage();
-                    if (comment.contains("【驳回】")) {
+                    if (StrUtil.isNotEmpty(comment) && comment.contains("【驳回】")) {
                         User rejectUser = userService.getById(recordList.get(recordList.size() - 1).getCreateUserId());
                         vo.setRejectState(rejectUser.getName() + "驳回");
-                    } else if (comment.contains("自动驳回")) {
+                    } else if (StrUtil.isNotEmpty(comment) && comment.contains("自动驳回")) {
                         vo.setRejectState("系统自动驳回");
                     }
                 }
                 if (recordList != null && recordList.size() > 2) {
                     String comment2 = recordList.get(recordList.size() - 2).getMessage();
-                    if (comment2.contains("自动驳回")) {
+                    if (StrUtil.isNotEmpty(comment2) && comment2.contains("自动驳回")) {
                         vo.setRejectState("系统自动驳回");
                     }
                 }
@@ -2891,7 +2891,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         NoticePolicyParam param = new NoticePolicyParam();
         param.setNoticeUserIds(Convert.toList(Long.class, approveIds));
         param.setTaskId(task.getId());
-        param.setTaskName(task.getName());
         param.setProcessId(task.getProcessInstanceId());
         param.setTaskName(task.getName());
         param.setSchemaId(MapUtil.get(variables, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class));

+ 1 - 1
src/main/resources/application-prod.yml

@@ -45,7 +45,7 @@ xjrsoft:
     cloud-type: minio
     access-key: 2LHjFEvzGaSTw7vt
     secret-key: taHsgYz9hk7ZrQZD
-    endpoint: http://219.153.208.41:9000
+    endpoint: http://219.153.208.34:9001
     endpoint-preview: https://zhxy.cqtlzjzx.com/minio
     bucket-name: static
     prefix: xjr

+ 8 - 0
src/main/resources/mapper/oa/OfficialDocumentReceivedHandleMapper.xml

@@ -48,6 +48,14 @@
         <if test="dto.handleDateStart != null and dto.handleDateEnd != ''">
             AND DATE_FORMAT(t1.handle_time, '%Y-%m-%d') between and #{dto.handleDateStart} and #{dto.handleDateEnd}
         </if>
+        <if test="dto.keyword != null and dto.keyword != ''">
+            AND (
+                t1.received_type like concat('%', #{dto.keyword},'%')
+                or t1.received_title like concat('%', #{dto.keyword},'%')
+                or t3.name like concat('%', #{dto.keyword},'%')
+                or t4.name like concat('%', #{dto.keyword},'%')
+            )
+        </if>
         order by t1.id desc
     </select>
 

+ 8 - 24
src/main/resources/mapper/textbook/TextbookStudentClaimMapper.xml

@@ -34,12 +34,8 @@
         <if test="dto.baseSemesterId != null and dto.baseSemesterId > 0">
             AND t.base_semester_id = #{dto.baseSemesterId}
         </if>
-        <if test="dto.classIdList != null and dto.classIdList.size() > 0">
-            AND t.class_id IN
-            <foreach item="classId" index="index" collection="dto.classIdList" open="(" close=")"
-                     separator=",">
-                #{classId}
-            </foreach>
+        <if test="dto.classId != null and dto.classId > 0">
+            AND t.class_id = #{dto.classId}
         </if>
         AND t.claim_type = 'claim_class'
         and t.workflow_status = 1
@@ -52,12 +48,8 @@
         <if test="dto.baseSemesterId != null and dto.baseSemesterId > 0">
             AND base_semester_id = #{dto.baseSemesterId}
         </if>
-        <if test="dto.classIdList != null and dto.classIdList.size() > 0">
-            AND class_id IN
-            <foreach item="classId" index="index" collection="dto.classIdList" open="(" close=")"
-                     separator=",">
-                #{classId}
-            </foreach>
+        <if test="dto.classId != null and dto.classId > 0">
+            AND class_id = #{dto.classId}
         </if>
         GROUP BY base_semester_id, class_id, textbook_id),
         class_stu_num AS
@@ -65,12 +57,8 @@
         FROM base_student_school_roll t
         WHERE t.delete_mark = 0
         and t.archives_status = 'FB2901'
-        <if test="dto.classIdList != null and dto.classIdList.size() > 0">
-            AND t.class_id IN
-            <foreach item="classId" index="index" collection="dto.classIdList" open="(" close=")"
-                     separator=",">
-                #{classId}
-            </foreach>
+        <if test="dto.classId != null and dto.classId > 0">
+            AND t.class_id = #{dto.classId}
         </if>
         GROUP BY class_id)
         SELECT t.base_semester_id,
@@ -91,12 +79,8 @@
         t3.textbook_id = t.textbook_id
         LEFT JOIN class_stu_num t4 ON t4.class_id = t.class_id
         where t.class_id &lt;&gt; 0
-        <if test="dto.classIdList != null and dto.classIdList.size() > 0">
-            AND t.class_id IN
-            <foreach item="classId" index="index" collection="dto.classIdList" open="(" close=")"
-                     separator=",">
-                #{classId}
-            </foreach>
+        <if test="dto.classId != null and dto.classId > 0">
+            AND t.class_id = #{dto.classId}
         </if>
         <if test="dto.claimStatus != null and dto.claimStatus == 2">
             AND t.received_num &lt;= t3.claim_num

File diff suppressed because it is too large
+ 11 - 0
src/main/resources/sqlScript/20250603sql.sql


+ 5 - 0
src/main/resources/sqlScript/20250612sql.sql

@@ -0,0 +1,5 @@
+alter table textbook_discount_alter_record
+    add old_warehouse_num int null comment '旧的入库数量' after new_price;
+
+alter table textbook_discount_alter_record
+    add new_warehouse_num int null comment '新的入库数量' after old_warehouse_num;

+ 24 - 0
src/test/java/com/xjrsoft/module/hikvision/controller/OutInControllerTest.java

@@ -0,0 +1,24 @@
+package com.xjrsoft.module.hikvision.controller;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author dzx
+ * @date 2025/6/6
+ */
+class OutInControllerTest {
+
+    @Test
+    void test(){
+        String result = "{\"code\":\"0x02e13f03\",\"msg\":\"pms.base.license.notExist\",\"data\":null}";
+        JsonParser parser = new JsonParser();
+        JsonObject data = parser.parse(result).getAsJsonObject().get("data").getAsJsonObject();
+        System.out.println();
+
+    }
+
+}

+ 4 - 2
src/test/java/com/xjrsoft/xjrsoftboot/StringTest.java

@@ -4,6 +4,7 @@ import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
 import com.xjrsoft.module.base.entity.BaseClass;
 import org.junit.jupiter.api.Test;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
@@ -15,8 +16,9 @@ public class StringTest {
 
     @Test
     void test2(){
-
-        System.out.println(underscoreToCamel("create_user_id"));
+        BigDecimal bigDecimal = new BigDecimal("40001");
+        String str = bigDecimal.stripTrailingZeros().toString();
+        System.out.println(str); // 输出: 123.45
     }
 
     public static String underscoreToCamel(String input) {

Some files were not shown because too many files changed in this diff