Ver código fonte

部分新增查询需求

caozixuan 1 ano atrás
pai
commit
9d87bcc7db

+ 170 - 0
install/mysql/init/init.sql

@@ -0,0 +1,170 @@
+-- ----------------------------
+--  Table structure for `pm_break_record`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_break_record`;
+CREATE TABLE `pm_break_record`
+(
+    `id`           bigint(20)                   NOT NULL AUTO_INCREMENT,
+    `create_time`  datetime(6)                  NOT NULL,
+    `creator_id`   bigint(20)                    DEFAULT NULL,
+    `update_time`  datetime(6)                   DEFAULT NULL,
+    `updater_id`   bigint(20)                    DEFAULT NULL,
+    `org_id`       bigint(20)                   NOT NULL,
+    `exam_id`      bigint(20)                   NOT NULL,
+    `group_type`   varchar(16) COLLATE utf8_bin NOT NULL,
+    `group_name`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `status`       varchar(16) COLLATE utf8_bin  DEFAULT NULL,
+    `start_number` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `end_number`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    PRIMARY KEY (`id`),
+    KEY `IDX_BREAK_RECORD_001` (`org_id`, `exam_id`, `group_type`),
+    KEY `IDX_BREAK_RECORD_002` (`exam_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_check_record`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_check_record`;
+CREATE TABLE `pm_check_record`
+(
+    `id`           bigint(20)                   NOT NULL AUTO_INCREMENT,
+    `create_time`  datetime(6)                  NOT NULL,
+    `creator_id`   bigint(20)                    DEFAULT NULL,
+    `update_time`  datetime(6)                   DEFAULT NULL,
+    `updater_id`   bigint(20)                    DEFAULT NULL,
+    `org_id`       bigint(20)                   NOT NULL,
+    `exam_id`      bigint(20)                   NOT NULL,
+    `group_type`   varchar(16) COLLATE utf8_bin NOT NULL,
+    `status`       varchar(16) COLLATE utf8_bin NOT NULL,
+    `group_name`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `start_number` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `end_number`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    PRIMARY KEY (`id`),
+    KEY `IDX_CHECK_RECORD_001` (`org_id`, `exam_id`, `group_type`),
+    KEY `IDX_CHECK_RECORD_002` (`exam_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_exam`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_exam`;
+CREATE TABLE `pm_exam`
+(
+    `id`          bigint(20)                    NOT NULL AUTO_INCREMENT,
+    `create_time` datetime(6)                   NOT NULL,
+    `creator_id`  bigint(20)                    DEFAULT NULL,
+    `update_time` datetime(6)                   DEFAULT NULL,
+    `updater_id`  bigint(20)                    DEFAULT NULL,
+    `org_id`      bigint(20)                    NOT NULL,
+    `name`        varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `enable`      bigint(1)                     NOT NULL,
+    `group_type`  varchar(255) COLLATE utf8_bin NOT NULL,
+    `check_sort`  varchar(255) COLLATE utf8_bin NOT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `IDX_EXAM_001` (`org_id`, `name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_exam_student`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_exam_student`;
+CREATE TABLE `pm_exam_student`
+(
+    `create_time`  datetime(6)                   NOT NULL,
+    `creator_id`   bigint(20)                    DEFAULT NULL,
+    `update_time`  datetime(6)                   DEFAULT NULL,
+    `updater_id`   bigint(20)                    DEFAULT NULL,
+    `org_id`       bigint(20)                    NOT NULL,
+    `exam_id`      bigint(20)                    NOT NULL,
+    `sort_no`      bigint(20)                    NOT NULL,
+    `name`         varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `course_code`  varchar(255) COLLATE utf8_bin NOT NULL,
+    `student_code` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `exam_number`  varchar(255) COLLATE utf8_bin NOT NULL,
+    `exam_site`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `exam_room`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    PRIMARY KEY (`exam_id`, `sort_no`),
+    KEY `IDX_EXAM_STUDENT_001` (`org_id`, `exam_id`),
+    KEY `IDX_EXAM_STUDENT_002` (`exam_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_exam_user_relation`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_exam_user_relation`;
+CREATE TABLE `pm_exam_user_relation`
+(
+    `user_id`     bigint(20)  NOT NULL,
+    `exam_id`     bigint(20)  NOT NULL,
+    `create_time` datetime(6) NOT NULL,
+    `update_time` datetime(6) NOT NULL,
+    `creator_id`  bigint(20) DEFAULT NULL,
+    `updater_id`  bigint(20) DEFAULT NULL,
+    PRIMARY KEY (`user_id`, `exam_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_org`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_org`;
+CREATE TABLE `pm_org`
+(
+    `id`            bigint(20)                    NOT NULL AUTO_INCREMENT,
+    `create_time`   datetime(6)                   NOT NULL,
+    `update_time`   datetime(6)                   NOT NULL,
+    `name`          varchar(255) COLLATE utf8_bin NOT NULL,
+    `code`          varchar(255) COLLATE utf8_bin NOT NULL,
+    `enable`        bit(1)                        NOT NULL,
+    `access_key`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `access_secret` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `description`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `domain_name`   varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `logo_url`      varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `IDX_ORG_01` (`code`),
+    UNIQUE KEY `IDX_ORG_02` (`domain_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+-- ----------------------------
+--  Table structure for `pm_user`
+-- ----------------------------
+DROP TABLE IF EXISTS `pm_user`;
+CREATE TABLE `pm_user`
+(
+    `id`          bigint(20)                    NOT NULL AUTO_INCREMENT,
+    `create_time` datetime(6)                   NOT NULL,
+    `creator_id`  bigint(20)                    DEFAULT NULL,
+    `update_time` datetime(6)                   NOT NULL,
+    `updater_id`  bigint(20)                    DEFAULT NULL,
+    `login_name`  varchar(255) COLLATE utf8_bin NOT NULL,
+    `name`        varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `enable`      bit(1)                        NOT NULL,
+    `password`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `role`        varchar(64) COLLATE utf8_bin  NOT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `IDX_USER_01` (`login_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8
+  COLLATE = utf8_bin;
+
+INSERT INTO `pm_user` (`id`, `create_time`, `update_time`, `enable`, `login_name`, `name`, `password`, `creator_id`,
+                       `updater_id`, `role`)
+VALUES (1, now(), now(), 1, ''admin'', ''超管'', ''123456 '', 1, 1, ''ADMIN'');
+

+ 0 - 0
install/mysql/upgrade/1.1.0.sql


+ 89 - 11
src/main/java/cn/com/qmth/print/manage/controller/SysController.java

@@ -1,29 +1,41 @@
 package cn.com.qmth.print.manage.controller;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestAttribute;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
+import cn.com.qmth.print.manage.entity.ExamEntity;
+import cn.com.qmth.print.manage.entity.UserEntity;
+import cn.com.qmth.print.manage.enums.RoleMeta;
 import cn.com.qmth.print.manage.service.AuthService;
+import cn.com.qmth.print.manage.service.ExamService;
 import cn.com.qmth.print.manage.service.PmSession;
-
+import cn.com.qmth.print.manage.service.UserService;
+import cn.com.qmth.print.manage.vo.CommonQueryVo;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.api.constant.ApiConstant;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @Date: 2021/11/17.
  */
 @RestController
 @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX)
-public class SysController {
+public class SysController extends BaseController {
 
-    @Autowired
+    @Resource
     private AuthService authService;
+    @Resource
+    private UserService userService;
+    @Resource
+    private ExamService examService;
 
     /**
      * 登录
@@ -42,4 +54,70 @@ public class SysController {
     public void logout(@RequestAttribute PmSession accessEntity) {
         authService.logout(accessEntity);
     }
+
+    /**
+     * 公共接口-查询用户数据
+     * <p>
+     * 1.管理员-用户管理 : 根据所选角色查询,是否启用根据选择。
+     * 2.印点负责人-用户管理 : 只查询校验员角色,只查询自己创建的,是否启用根据选择。
+     * 3.管理员-批次管理 : 只查询印点负责人角色,是否启用根据选择
+     * </p>
+     *
+     * @param accessEntity 当前登录人信息
+     * @param role         角色
+     * @param creatorDpr   是否启用当前人为用户创建人权限
+     * @return 用户集合
+     */
+    @ApiOperation(value = "公共接口-查询用户数据")
+    @RequestMapping(value = "/common/find_user_list", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = CommonQueryVo.class)})
+    public Object findUserList(@RequestAttribute PmSession accessEntity,
+                               @ApiParam(value = "角色") @RequestParam(required = false) RoleMeta role,
+                               @ApiParam(value = "当前登录人创建") @RequestParam(required = false) Boolean creatorDpr,
+                               @ApiParam(value = "是否启用?") @RequestParam(required = false) Boolean enable) {
+
+
+        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
+
+        if (Objects.nonNull(role)) {
+            queryWrapper.lambda().eq(UserEntity::getRole, role);
+        }
+        if (creatorDpr) {
+            Long userId = getAccessUserId(accessEntity);
+            queryWrapper.lambda().eq(UserEntity::getCreatorId, userId);
+        }
+        if (Objects.nonNull(enable)) {
+            queryWrapper.lambda().eq(UserEntity::isEnable, enable);
+        }
+
+        return userService.list(queryWrapper).stream().flatMap(e -> {
+            CommonQueryVo vo = new CommonQueryVo();
+            vo.setId(e.getId());
+            vo.setValue(e.getName());
+            return Stream.of(vo);
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 公共接口-查询考试批次数据
+     * <p>
+     * 1.管理员-批次管理 : 根据所选印点负责人查询
+     * 2.印点负责人-批次管理 : 根据当前登录人id作为印点负责人id查询
+     * </p>
+     *
+     * @param userId 印点负责人id
+     * @return 考试批次集合
+     */
+    @ApiOperation(value = "公共接口-查询考试批次数据")
+    @RequestMapping(value = "/common/find_exam_list", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = CommonQueryVo.class)})
+    public Object findExamList(@ApiParam(value = "印点负责人Id", required = true) @RequestParam Long userId) {
+        return examService.list(new QueryWrapper<ExamEntity>().lambda().eq(ExamEntity::getCreatorId, userId))
+                .stream().flatMap(e -> {
+                    CommonQueryVo vo = new CommonQueryVo();
+                    vo.setId(e.getId());
+                    vo.setValue(e.getName());
+                    return Stream.of(vo);
+                }).collect(Collectors.toList());
+    }
 }

+ 13 - 21
src/main/java/cn/com/qmth/print/manage/controller/UserController.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.print.manage.controller;
 
 import cn.com.qmth.print.manage.entity.UserEntity;
+import cn.com.qmth.print.manage.enums.RoleMeta;
 import cn.com.qmth.print.manage.service.PmSession;
 import cn.com.qmth.print.manage.service.UserService;
 import cn.com.qmth.print.manage.service.query.UserQuery;
@@ -14,12 +15,13 @@ import com.qmth.boot.core.exception.StatusException;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestAttribute;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.management.relation.Role;
+import java.io.IOException;
 import java.util.Date;
+import java.util.Objects;
 
 /**
  * @Date: 2021/11/16.
@@ -60,24 +62,14 @@ public class UserController extends BaseController {
      * @return
      */
     @RequestMapping(value = "/save", method = RequestMethod.POST)
-    public Object save(@RequestAttribute PmSession accessEntity, UserEntity user) {
+    public Object save(@RequestAttribute PmSession accessEntity, @RequestBody UserEntity user, @RequestParam(required = false) MultipartFile file) throws IOException {
         Long userId = getAccessUserId(accessEntity);
-        if (user.getId() != null) {
-            UserEntity userEntity = userService.getById(user.getId());
-            if (userEntity == null) {
-                throw new StatusException("用户不存在");
-            }
-            if (!user.getLoginName().equals(userEntity.getLoginName())) {
-                throw new StatusException("用户名不能修改");
-            }
+        UserEntity requestUser = userService.getById(userId);
+        if (Objects.isNull(requestUser)){
+            throw new StatusException("当前用户不存在");
         }
-        if(StringUtils.isBlank(user.getName())){
-            user.setName(user.getLoginName());
-        }
-        user.setCreatorId(userId);
-        user.setCreateTime(new Date());
-        user.setUpdaterId(userId);
-        user.setUpdateTime(new Date());
-        return userService.saveOrUpdate(user);
+        return userService.save(requestUser, user, file);
     }
+
+    // TODO: 2023/10/17 修改密码 初始化密码 
 }

+ 21 - 0
src/main/java/cn/com/qmth/print/manage/dto/ExamDTO.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.print.manage.dto;
+
+import cn.com.qmth.print.manage.utils.excel.ExcelProperty;
+
+/**
+ * @Description: 考试(批次)导入
+ * @Author: CaoZixuan
+ * @Date: 2023-10-16
+ */
+public class ExamDTO {
+    @ExcelProperty(index = 1, name = "学校名称", type = 0)
+    private String schoolName;
+
+    public String getSchoolName() {
+        return schoolName;
+    }
+
+    public void setSchoolName(String schoolName) {
+        this.schoolName = schoolName;
+    }
+}

+ 3 - 2
src/main/java/cn/com/qmth/print/manage/enums/RoleMeta.java

@@ -4,7 +4,9 @@ public enum RoleMeta {
 
     ADMIN("管理员", 1L),
 
-    CHECKER("校验员", 2L);
+    CHECKER("校验员", 2L),
+
+    PRINT_LEADER("印点负责人", 3L);
 
     /**
      * 角色名
@@ -42,5 +44,4 @@ public enum RoleMeta {
         }
         return null;
     }
-
 }

+ 16 - 2
src/main/java/cn/com/qmth/print/manage/service/ExamService.java

@@ -1,12 +1,14 @@
 package cn.com.qmth.print.manage.service;
 
 import cn.com.qmth.print.manage.entity.ExamEntity;
+import cn.com.qmth.print.manage.entity.UserEntity;
 import cn.com.qmth.print.manage.service.query.ExamQuery;
 import cn.com.qmth.print.manage.vo.ExamVo;
-
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
 import java.util.List;
 
 public interface ExamService extends IService<ExamEntity> {
@@ -17,5 +19,17 @@ public interface ExamService extends IService<ExamEntity> {
 
     IPage<ExamVo> pageQuery(ExamQuery query);
 
-    List<ExamEntity> listByUserId(Long userId);
+    List<ExamVo> listByUserId(Long userId);
+
+    /**
+     * 导入考试
+     *
+     * @param requestUser 请求用户
+     * @param printLeader 印点负责人
+     * @param file        文件
+     * @return 报错信息
+     */
+    Object importExams(UserEntity requestUser, Long printLeader, MultipartFile file) throws IOException;
+
+
 }

+ 7 - 0
src/main/java/cn/com/qmth/print/manage/service/OrgService.java

@@ -15,4 +15,11 @@ public interface OrgService extends IService<OrgEntity> {
     List<OrgEntity> listByEnable();
 
     void pull();
+
+    /**
+     * 根据机构编号查询机构
+     * @param code 机构编号
+     * @return 机构信息
+     */
+    OrgEntity findByCode(String code);
 }

+ 12 - 0
src/main/java/cn/com/qmth/print/manage/service/UserService.java

@@ -5,11 +5,23 @@ import cn.com.qmth.print.manage.service.query.UserQuery;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
 import java.util.List;
 
 public interface UserService extends IService<UserEntity> {
 
+    /**
+     * 用户保存
+     *
+     * @param requestUser 当前请求用户
+     * @param user        编辑的用户信息
+     * @param file        批次导入文件
+     * @return 用户保存结果
+     */
+    boolean save(UserEntity requestUser, UserEntity user, MultipartFile file) throws IOException;
+
     IPage<UserEntity> pageQuery(UserQuery query);
 
     List<UserEntity> listByEnable();

+ 142 - 15
src/main/java/cn/com/qmth/print/manage/service/impl/ExamServiceImpl.java

@@ -1,45 +1,59 @@
 package cn.com.qmth.print.manage.service.impl;
 
 import cn.com.qmth.print.manage.dao.ExamDao;
+import cn.com.qmth.print.manage.dto.ExamDTO;
 import cn.com.qmth.print.manage.entity.*;
+import cn.com.qmth.print.manage.enums.CheckSort;
+import cn.com.qmth.print.manage.enums.GroupType;
 import cn.com.qmth.print.manage.enums.RecordStatus;
 import cn.com.qmth.print.manage.service.*;
 import cn.com.qmth.print.manage.service.query.ExamQuery;
+import cn.com.qmth.print.manage.utils.excel.ExcelError;
+import cn.com.qmth.print.manage.utils.excel.ExcelReader;
 import cn.com.qmth.print.manage.vo.ExamVo;
-
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.boot.core.exception.StatusException;
-
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.util.CollectionUtils;
-
-import java.util.Date;
-import java.util.List;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Year;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @Service
 public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements ExamService {
 
-    @Autowired
+    @Resource
     private ExamUserRelationService examUserRelationService;
 
-    @Autowired
+    @Resource
     private ExamStudentService examStudentService;
 
-    @Autowired
+    @Resource
     private CheckRecordService checkRecordService;
 
-    @Autowired
+    @Resource
     private BreakRecordService breakRecordService;
 
-    @Autowired
+    @Resource
     private ExamDao examDao;
 
+    @Resource
+    private OrgService orgService;
+
     @Override
     public List<ExamEntity> listByOrgId() {
         QueryWrapper<ExamEntity> queryWrapper = new QueryWrapper<>();
@@ -50,7 +64,21 @@ public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements
     @Transactional
     @Override
     public Long saveExam(ExamEntity exam) {
+        // 同机构下的考试批次名称不能重复校验
+        String examName = exam.getName();
+        Long orgId = exam.getOrgId();
+        ExamEntity nameCheck = this.getOne(new QueryWrapper<ExamEntity>().lambda()
+                .eq(ExamEntity::getName, examName)
+                .eq(ExamEntity::getOrgId, orgId));
+        if (Objects.nonNull(nameCheck)) {
+            Long id = nameCheck.getId();
+            if (!Objects.equals(id, exam.getId())) {
+                throw new StatusException(String.format("批次名称重复! 已经存在名称为[%s]的批次", examName));
+            }
+        }
+
         if (exam.getId() != null) {
+            // 编辑
             ExamEntity examEntity = this.getById(exam.getId());
             if (examEntity == null) {
                 throw new StatusException("批次不存在");
@@ -88,8 +116,8 @@ public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements
             // 绑定用户
             List<ExamUserRelationEntity> examUserRelationEntities = examUserRelationService.listByExamId(record.getId());
             String userIds = null;
-            if(!CollectionUtils.isEmpty(examUserRelationEntities)){
-                List<String> ids = examUserRelationEntities.stream().map(m->String.valueOf(m.getUserId())).collect(Collectors.toList());
+            if (!CollectionUtils.isEmpty(examUserRelationEntities)) {
+                List<String> ids = examUserRelationEntities.stream().map(m -> String.valueOf(m.getUserId())).collect(Collectors.toList());
                 userIds = String.join(",", ids);
             }
             record.setUserIds(userIds);
@@ -115,12 +143,111 @@ public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements
                         .filter(m -> m.getStatus().equals(RecordStatus.NORMAL)).count();
                 record.setBreakNormalLCount(Math.toIntExact(breakNormalLCount));
             }
+
+            // 计算进度
+            BigDecimal progress = new BigDecimal(record.getCheckNormalLCount()).divide(new BigDecimal(record.getCheckCount()), 4, RoundingMode.HALF_UP);
+            progress = progress.multiply(new BigDecimal(100));
+            record.setProgress(progress);
         }
         return iPage;
     }
 
     @Override
-    public List<ExamEntity> listByUserId(Long userId) {
-        return examDao.listByUserId(userId);
+    public List<ExamVo> listByUserId(Long userId) {
+        List<ExamEntity> examEntityList = examDao.listByUserId(userId);
+        return examEntityList.stream().flatMap(e -> {
+            ExamVo vo = new ExamVo();
+            BeanUtils.copyProperties(e, vo);
+
+            // 校验数量
+            List<CheckRecordEntity> checkRecordEntities = checkRecordService.listByExamId(vo.getId());
+            vo.setCheckCount(checkRecordEntities.size());
+            if (!CollectionUtils.isEmpty(checkRecordEntities)) {
+                long checkNormalLCount = checkRecordEntities.stream()
+                        .filter(m -> m.getStatus().equals(RecordStatus.NORMAL)).count();
+                vo.setCheckNormalLCount(Math.toIntExact(checkNormalLCount));
+
+                long checkErrorLCount = checkRecordEntities.stream()
+                        .filter(m -> m.getStatus().equals(RecordStatus.ERROR)).count();
+                vo.setCheckErrorCount(Math.toIntExact(checkErrorLCount));
+
+                // 计算进度
+                BigDecimal progress = new BigDecimal(vo.getCheckNormalLCount()).divide(new BigDecimal(vo.getCheckCount()), 4, RoundingMode.HALF_UP);
+                progress = progress.multiply(new BigDecimal(100));
+                vo.setProgress(progress);
+            }
+            return Stream.of(vo);
+        }).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<ExcelError> importExams(UserEntity requestUser, Long printLeader, MultipartFile file) throws IOException {
+        List<String> examNameDatasource = this.list().stream()
+                .map(ExamEntity::getName)
+                .collect(Collectors.toList());
+        // 默认机构
+        OrgEntity defaultOrg = orgService.findByCode("qmth");
+
+        List<ExamEntity> examEntityList = new ArrayList<>();
+
+        ExcelReader excelReader = new ExcelReader(ExamDTO.class);
+        AtomicLong sort = new AtomicLong(1L);
+        List<ExcelError> excelErrors = excelReader.reader(file.getInputStream(), obj -> {
+            try {
+                sort.getAndIncrement();
+                ExamDTO dto = (ExamDTO) obj;
+                String schoolName = dto.getSchoolName();
+                Year year = Year.now();
+                String examName = (Long.parseLong(year.toString()) + 1) + schoolName;
+                if (examNameDatasource.contains(examName)) {
+                    throw new StatusException(String.format("第[%s]行已有学校名称则,导入不成功", examName));
+                }
+                ExamEntity examEntity = new ExamEntity();
+                examEntity.setOrgId(defaultOrg.getId());
+                examEntity.setName(examName);
+                examEntity.setEnable(true);
+                examEntity.setGroupType(GroupType.COURSE);
+                examEntity.setCheckSort(CheckSort.ASC);
+                examEntity.setCreateTime(new Date());
+                examEntity.setUpdateTime(new Date());
+                examEntity.setCreatorId(requestUser.getCreatorId());
+                examEntityList.add(examEntity);
+                return null;
+            } catch (RuntimeException e) {
+                // 手动回滚
+                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+                ExcelError excelError = new ExcelError();
+                excelError.setExcelErrorType(e.getMessage());
+                return excelError;
+            }
+        });
+        String errors = errorsString(excelErrors);
+        if (errors.length() > 0) {
+            throw new StatusException(errors);
+        }
+        if (!CollectionUtils.isEmpty(examEntityList)) {
+            this.saveBatch(examEntityList);
+        }
+        return excelErrors;
+    }
+
+    /**
+     * 拼接导入异常信息
+     *
+     * @param excelErrors
+     * @return
+     */
+    private String errorsString(List<ExcelError> excelErrors) {
+        StringJoiner sj = new StringJoiner(";");
+        if (!excelErrors.isEmpty()) {
+            int forint = excelErrors.size() < 10 ? excelErrors.size() : 9;
+            for (int i = 0; i < forint; i++) {
+                ExcelError excelError = excelErrors.get(i);
+                StringBuffer sb = new StringBuffer();
+                sb.append("第").append(excelError.getRow()).append("行,").append(excelError.getExcelErrorType());
+                sj.add(sb.toString());
+            }
+        }
+        return sj.toString();
     }
 }

+ 14 - 22
src/main/java/cn/com/qmth/print/manage/service/impl/ExamStudentServiceImpl.java

@@ -1,24 +1,5 @@
 package cn.com.qmth.print.manage.service.impl;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.StringJoiner;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-
-import javax.annotation.Resource;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.interceptor.TransactionAspectSupport;
-import org.springframework.web.multipart.MultipartFile;
-
 import cn.com.qmth.print.manage.dao.ExamDao;
 import cn.com.qmth.print.manage.dao.ExamStudentDao;
 import cn.com.qmth.print.manage.dto.StudentDTO;
@@ -33,7 +14,6 @@ import cn.com.qmth.print.manage.service.ExamStudentService;
 import cn.com.qmth.print.manage.service.query.ExamStudentQuery;
 import cn.com.qmth.print.manage.utils.excel.ExcelError;
 import cn.com.qmth.print.manage.utils.excel.ExcelReader;
-
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
@@ -41,15 +21,27 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.boot.core.exception.StatusException;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 @Service
 public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentDao, ExamStudentEntity> implements
         ExamStudentService {
 
-    @Autowired
+    @Resource
     private CheckRecordService checkRecordService;
 
-    @Autowired
+    @Resource
     private BreakRecordService breakRecordService;
 
     @Resource

+ 13 - 0
src/main/java/cn/com/qmth/print/manage/service/impl/OrgServiceImpl.java

@@ -5,6 +5,7 @@ import java.util.List;
 
 import javax.annotation.Resource;
 
+import com.qmth.boot.core.exception.StatusException;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -88,4 +89,16 @@ public class OrgServiceImpl extends ServiceImpl<OrgDao, OrgEntity> implements Or
             }
         }
     }
+
+    @Override
+    public OrgEntity findByCode(String code) {
+        List<OrgEntity> orgEntityList = this.list(new QueryWrapper<OrgEntity>().lambda().eq(OrgEntity::getCode, code));
+        if (CollectionUtils.isEmpty(orgEntityList)) {
+            throw new StatusException(String.format("机构[%s]不存在", code));
+        }
+        if (orgEntityList.size() > 1) {
+            throw new StatusException(String.format("存在多个编号为[%s]的机构", code));
+        }
+        return orgEntityList.get(0);
+    }
 }

+ 57 - 2
src/main/java/cn/com/qmth/print/manage/service/impl/UserServiceImpl.java

@@ -3,24 +3,79 @@ package cn.com.qmth.print.manage.service.impl;
 import cn.com.qmth.print.manage.dao.UserDao;
 import cn.com.qmth.print.manage.entity.UserEntity;
 import cn.com.qmth.print.manage.enums.RoleMeta;
+import cn.com.qmth.print.manage.service.ExamService;
 import cn.com.qmth.print.manage.service.UserService;
 import cn.com.qmth.print.manage.service.query.UserQuery;
-
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-
+import com.qmth.boot.core.exception.StatusException;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @Date: 2021/11/16.
  */
 @Service
 public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
+    @Resource
+    private ExamService examService;
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public boolean save(UserEntity requestUser, UserEntity user, MultipartFile file) throws IOException {
+        Long requestUserId = requestUser.getId();
+        if (user.getId() != null) {
+            UserEntity userEntity = this.getById(user.getId());
+            if (userEntity == null) {
+                throw new StatusException("用户不存在");
+            }
+            if (!user.getLoginName().equals(userEntity.getLoginName())) {
+                throw new StatusException("用户名不能修改");
+            }
+        }
+        if (StringUtils.isBlank(user.getName())) {
+            user.setName(user.getLoginName());
+        }
+        RoleMeta requestUserRole = requestUser.getRole();
+        RoleMeta role = user.getRole();
+        switch (requestUserRole) {
+            case ADMIN:
+                if (!RoleMeta.PRINT_LEADER.equals(role)) {
+                    throw new StatusException(String.format("[%s]只能创建[%s]角色的用户", RoleMeta.ADMIN.getName(), RoleMeta.PRINT_LEADER.getName()));
+                }
+                break;
+            case PRINT_LEADER:
+                if (!RoleMeta.CHECKER.equals(role)) {
+                    throw new StatusException(String.format("[%s]只能创建[%s]角色的用户", RoleMeta.PRINT_LEADER.getName(), RoleMeta.CHECKER.getName()));
+                }
+                break;
+            default:
+                throw new StatusException(String.format("只有[%s][%s]角色的用户可以编辑用户", RoleMeta.ADMIN, RoleMeta.PRINT_LEADER));
+        }
+
+
+        user.setCreatorId(requestUserId);
+        user.setCreateTime(new Date());
+        user.setUpdaterId(requestUserId);
+        user.setUpdateTime(new Date());
+        boolean result = this.saveOrUpdate(user);
+        Long userId = user.getId();
+        if (RoleMeta.ADMIN.equals(requestUser.getRole()) && Objects.nonNull(file)) {
+            // 如果是管理员且包含导入文件-处理导入批次逻辑
+            examService.importExams(requestUser, userId, file);
+        }
+        return result;
+    }
 
     @Override
     public IPage<UserEntity> pageQuery(UserQuery query) {

+ 13 - 10
src/main/java/cn/com/qmth/print/manage/service/query/ExamQuery.java

@@ -2,6 +2,7 @@ package cn.com.qmth.print.manage.service.query;
 
 import cn.com.qmth.print.manage.entity.ExamEntity;
 import com.qmth.boot.mybatis.query.BaseQuery;
+import io.swagger.annotations.ApiModelProperty;
 import org.springframework.validation.annotation.Validated;
 
 import javax.validation.constraints.Max;
@@ -13,27 +14,29 @@ public class ExamQuery extends BaseQuery<ExamEntity> {
 
     private static final long serialVersionUID = 3260496142491163981L;
 
-    private String name;
+    @ApiModelProperty("印点负责人id")
+    private Long printLeaderId;
 
-    private Long orgId;
+    @ApiModelProperty("考试批次id")
+    private Long id;
 
     @NotNull
     private boolean enable;
 
-    public String getName() {
-        return name;
+    public Long getPrintLeaderId() {
+        return printLeaderId;
     }
 
-    public void setName(String name) {
-        this.name = name;
+    public void setPrintLeaderId(Long printLeaderId) {
+        this.printLeaderId = printLeaderId;
     }
 
-    public Long getOrgId() {
-        return orgId;
+    public Long getId() {
+        return id;
     }
 
-    public void setOrgId(Long orgId) {
-        this.orgId = orgId;
+    public void setId(Long id) {
+        this.id = id;
     }
 
     public boolean isEnable() {

+ 32 - 0
src/main/java/cn/com/qmth/print/manage/vo/CommonQueryVo.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.print.manage.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 公共查询Vo
+ * @Author: CaoZixuan
+ * @Date: 2023-10-17
+ */
+public class CommonQueryVo {
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("值")
+    private String value;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+}

+ 25 - 0
src/main/java/cn/com/qmth/print/manage/vo/ExamVo.java

@@ -1,6 +1,9 @@
 package cn.com.qmth.print.manage.vo;
 
 import cn.com.qmth.print.manage.entity.ExamEntity;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.math.BigDecimal;
 
 public class ExamVo extends ExamEntity {
 
@@ -18,6 +21,12 @@ public class ExamVo extends ExamEntity {
 
     private int breakNormalLCount;
 
+    @ApiModelProperty("进度(checkNormalLCount/checkCount 保留两位小数)")
+    private BigDecimal progress;
+
+    @ApiModelProperty("印点负责人名称")
+    private String printLeaderName;
+
     public String getOrgName() {
         return orgName;
     }
@@ -73,4 +82,20 @@ public class ExamVo extends ExamEntity {
     public void setBreakNormalLCount(int breakNormalLCount) {
         this.breakNormalLCount = breakNormalLCount;
     }
+
+    public BigDecimal getProgress() {
+        return progress;
+    }
+
+    public void setProgress(BigDecimal progress) {
+        this.progress = progress;
+    }
+
+    public String getPrintLeaderName() {
+        return printLeaderName;
+    }
+
+    public void setPrintLeaderName(String printLeaderName) {
+        this.printLeaderName = printLeaderName;
+    }
 }

+ 8 - 5
src/main/resources/mapper/ExamDao.xml

@@ -9,18 +9,21 @@
             pe.name,
             pe.group_type groupType,
             pe.check_sort checkSort,
-            po.name orgName
+            po.name orgName,
+            pu.name AS printLeaderName
         FROM
             pm_exam pe
                 LEFT JOIN
             pm_org po ON pe.org_id = po.id
+                LEFT JOIN
+            pm_user pu ON pe.creator_id = pu.id
         <where>
             pe.enable = #{query.enable}
-            <if test="query.name != null and query.name != ''">
-                and pe.name like concat(#{query.name},"%")
+            <if test="query.id != null">
+                and pe.id = #{query.id}
             </if>
-            <if test="query.orgId != null and query.orgId != ''">
-                and pe.org_id = #{query.orgId}
+            <if test="query.printLeaderId != null">
+                and pe.creator_id = #{query.printLeaderId}
             </if>
         </where>
     </select>