Compare commits
4 Commits
4d775d2332
...
24210dd1b7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
24210dd1b7 | ||
![]() |
a7fd185889 | ||
3eb97cb736 | |||
6f7832d65e |
@@ -78,7 +78,8 @@ public class AppCheckController {
|
||||
appCheckDO.setTaskId(taskId);
|
||||
appCheckDO.setAppName(exams.getRoles());
|
||||
// 判断是否在数组中存在
|
||||
boolean exists = appCheckDOList.contains(appCheckDO);
|
||||
boolean exists = appCheckDOList.stream()
|
||||
.anyMatch(a -> exams.getRoles().equals(a.getAppName())); // 根据 appName 判断
|
||||
if (!exists) {
|
||||
appCheckDOList.add(appCheckDO);
|
||||
}
|
||||
|
@@ -57,6 +57,8 @@ public class MonitorPageReqVO extends PageParam {
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] updateTime;
|
||||
|
||||
}
|
@@ -51,8 +51,11 @@ public class MonitorRespVO {
|
||||
|
||||
@ExcelProperty(value = "剩余时间", converter = SecondsToTimeConverter.class)
|
||||
private String remainingTime;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ExcelProperty("开始时间")
|
||||
private String startTime;
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package pc.exam.pp.module.exam.controller.admin.paper;
|
||||
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
@@ -22,6 +23,8 @@ import pc.exam.pp.module.exam.service.paper.IEducationPaperTaskService;
|
||||
import static pc.exam.pp.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
@@ -46,7 +49,15 @@ public class EducationPaperTaskController {
|
||||
PageResult<EducationPaperTask> pageResult = educationPaperTaskService.selectEducationPaperTaskList(educationPaperTask);
|
||||
return CommonResult.success(BeanUtils.toBean(pageResult, EducationPaperTask.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询试卷任务列表(服务器端)
|
||||
*/
|
||||
@Operation(summary = "查询试卷任务列表(服务器端)")
|
||||
@GetMapping("/listMoBan")
|
||||
public CommonResult<PageResult<EducationPaperTask>> listMoBan(PaperTaskPageVo educationPaperTask) {
|
||||
PageResult<EducationPaperTask> pageResult = educationPaperTaskService.selectEducationPaperTaskListlistMoBan(educationPaperTask);
|
||||
return CommonResult.success(BeanUtils.toBean(pageResult, EducationPaperTask.class));
|
||||
}
|
||||
@Operation(summary = "查询试卷任务列表(带试卷)")
|
||||
@GetMapping("/listPaper")
|
||||
public CommonResult<PageResult<EducationPaperTask>> taskAndPaperlist(PaperTaskPageVo educationPaperTask) {
|
||||
@@ -59,9 +70,18 @@ public class EducationPaperTaskController {
|
||||
*/
|
||||
@Operation(summary = "查询试卷任务列表(学生端)")
|
||||
@GetMapping("/stulist")
|
||||
public CommonResult<PageResult<EducationPaperTask>> stulist(PaperTaskPageVo educationPaperTask) {
|
||||
public CommonResult<PageResult<Map<String, Object>>> stulist(PaperTaskPageVo educationPaperTask) {
|
||||
PageResult<EducationPaperTask> pageResult = educationPaperTaskService.selectEducationPaperTaskListByStu(educationPaperTask);
|
||||
return CommonResult.success(BeanUtils.toBean(pageResult, EducationPaperTask.class));
|
||||
List<Map<String, Object>> newList = pageResult.getList().stream()
|
||||
.map(task -> {
|
||||
Map<String, Object> map = BeanUtil.beanToMap(task, false, true);
|
||||
map.put("status", task.getStatus() == null ? "" : String.valueOf(task.getStatus()));
|
||||
return map;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageResult<Map<String, Object>> newPage = new PageResult<>(newList, pageResult.getTotal());
|
||||
return CommonResult.success(newPage);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,7 @@ public class PaperTaskPageVo extends PageParam {
|
||||
private String status;
|
||||
|
||||
|
||||
private String creator;
|
||||
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
|
@@ -171,7 +171,8 @@ public class ExamSpecialtyController {
|
||||
public CommonResult getRole(@PathVariable("id") String id) {
|
||||
String roles = examSpecialtyService.getRoleById(id);
|
||||
if (roles != null) {
|
||||
return success(Integer.parseInt(roles));
|
||||
// return success(Integer.parseInt(roles));
|
||||
return success(roles);
|
||||
}
|
||||
return success("");
|
||||
}
|
||||
|
@@ -0,0 +1,129 @@
|
||||
package pc.exam.pp.module.exam.dal.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.tenant.core.db.TenantBaseDO;
|
||||
import pc.exam.pp.module.system.enums.common.SexEnum;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 管理后台的用户 DO
|
||||
*
|
||||
* @author 朋辰
|
||||
*/
|
||||
@TableName(value = "system_users", autoResultMap = true) // 由于 SQL Server 的 system_user 是关键字,所以使用 system_users
|
||||
@KeySequence("system_users_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AdminUser extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 加密后的密码
|
||||
*
|
||||
* 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐
|
||||
*/
|
||||
private String password;
|
||||
/**
|
||||
* 身份证
|
||||
*/
|
||||
private String sfz;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
/**
|
||||
* 学校名称
|
||||
*/
|
||||
private String schoolName;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
private Long deptId;
|
||||
/**
|
||||
* 班级 ID
|
||||
*/
|
||||
private Long classId;
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Set<Long> postIds;
|
||||
|
||||
/**
|
||||
* 班级编号数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Set<Long> classIds;
|
||||
|
||||
/**
|
||||
* 专业编号数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Set<Long> specialtyIds;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
/**
|
||||
* 用户性别
|
||||
*
|
||||
* 枚举类 {@link SexEnum}
|
||||
*/
|
||||
private Integer sex;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
/**
|
||||
* 帐号状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
|
||||
private String queueName;
|
||||
|
||||
}
|
@@ -46,6 +46,8 @@ public class EducationPaperTask extends TenantBaseDO
|
||||
private String taskType;
|
||||
|
||||
private String isOne;
|
||||
/** 是否共享 */
|
||||
private Integer share;
|
||||
|
||||
/** 是否为模板 */
|
||||
//@Excel(name = "是否为模板")
|
||||
|
@@ -0,0 +1,24 @@
|
||||
package pc.exam.pp.module.exam.dal.dataobject;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
@TableName(value = "exam_tenant_specialty")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TenantSpcialty {
|
||||
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
private Long tenantId;
|
||||
|
||||
private Long specialtyId;
|
||||
|
||||
private String points;
|
||||
}
|
@@ -49,10 +49,28 @@ public interface EducationPaperTaskMapper extends BaseMapperX<EducationPaperTask
|
||||
.likeIfPresent(EducationPaperTask::getTaskSpecialty , pageReqVO.getTaskSpecialty())
|
||||
.likeIfPresent(EducationPaperTask::getIsTemplate , pageReqVO.getIsTemplate())
|
||||
.betweenIfPresent(EducationPaperTask::getCreateTime, pageReqVO.getCreateTime())
|
||||
.and(wrapper ->
|
||||
wrapper
|
||||
// 自己创建的
|
||||
.eq(EducationPaperTask::getCreator, pageReqVO.getCreator())
|
||||
// 或者被共享的(share=0)
|
||||
.or()
|
||||
.eq(EducationPaperTask::getShare, 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
default PageResult<EducationPaperTask> selectEducationPaperTaskStuList(PaperTaskPageVo pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<EducationPaperTask>()
|
||||
.likeIfPresent(EducationPaperTask::getTaskType, pageReqVO.getTaskType())
|
||||
.likeIfPresent(EducationPaperTask::getTaskName , pageReqVO.getTaskName())
|
||||
.likeIfPresent(EducationPaperTask::getStatus , pageReqVO.getStatus())
|
||||
.likeIfPresent(EducationPaperTask::getTaskNum , pageReqVO.getTaskNum())
|
||||
.likeIfPresent(EducationPaperTask::getTaskSpecialty , pageReqVO.getTaskSpecialty())
|
||||
.likeIfPresent(EducationPaperTask::getIsTemplate , pageReqVO.getIsTemplate())
|
||||
.betweenIfPresent(EducationPaperTask::getCreateTime, pageReqVO.getCreateTime())
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 新增试卷任务
|
||||
*
|
||||
@@ -171,6 +189,14 @@ public interface EducationPaperTaskMapper extends BaseMapperX<EducationPaperTask
|
||||
.likeIfPresent(EducationPaperTask::getTaskSpecialty , pageReqVO.getTaskSpecialty())
|
||||
.likeIfPresent(EducationPaperTask::getIsTemplate , pageReqVO.getIsTemplate())
|
||||
.betweenIfPresent(EducationPaperTask::getCreateTime, pageReqVO.getCreateTime())
|
||||
.and(wrapper ->
|
||||
wrapper
|
||||
// 自己创建的
|
||||
.eq(EducationPaperTask::getCreator, pageReqVO.getCreator())
|
||||
// 或者被共享的(share=1)
|
||||
.or()
|
||||
.eq(EducationPaperTask::getShare, 0)
|
||||
)
|
||||
).getTotal();
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,8 @@ import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtListReqVo;
|
||||
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtyQueryVo;
|
||||
import pc.exam.pp.module.exam.controller.admin.specialty.vo.TenantSpcialtyVo;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.AdminUser;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.TenantSpcialty;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.knowledge.ExamKnowledgePoints;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.monitor.TentSpecialy;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.specialty.ExamSpecialty;
|
||||
@@ -145,4 +147,7 @@ public interface ExamSpecialtyMapper extends BaseMapperX<ExamSpecialty> {
|
||||
List<IdParentPair> selectAllIdToParent(Long loginTenantId);
|
||||
|
||||
|
||||
List<TenantSpcialty> getSpecialtyPoints(Long tenantId);
|
||||
|
||||
AdminUser selectUserById(Long id);
|
||||
}
|
||||
|
@@ -125,8 +125,8 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
public PageResult<MonitorDO> getMonitorPage(MonitorPageReqVO pageReqVO) {
|
||||
PageResult<MonitorDO> page = monitorMapper.selectPage(pageReqVO);
|
||||
page.getList().forEach(monitor -> {
|
||||
// 获取考试状态
|
||||
if (!monitor.getExamStatus().equals("0")) {
|
||||
// 获取考试状态,结束的考试 starttime归零了,这里只取正在考试的时间
|
||||
if ("1".equals(monitor.getExamStatus())) {
|
||||
String startTime = monitor.getStartTime();
|
||||
LocalDateTime nowTime = LocalDateTime.now();
|
||||
LocalDateTime endTime = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
|
@@ -6,6 +6,7 @@ import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import pc.exam.pp.framework.common.pojo.PageResult;
|
||||
import pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import pc.exam.pp.module.exam.controller.admin.monitor.vo.MonitorPageReqVO;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperTaskPageVo;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.EducationPaper;
|
||||
@@ -40,7 +41,9 @@ public class MonitorTaskServiceImpl implements MonitorTaskService{
|
||||
private EducationPaperQuMapper educationPaperQuMapper;
|
||||
@Override
|
||||
public PageResult<MonitorTaskDO> getMonitorPage(PaperTaskPageVo pageReqVO) {
|
||||
|
||||
//获取创建人
|
||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||
pageReqVO.setCreator(String.valueOf(loginUserId));
|
||||
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskList(pageReqVO);
|
||||
long total= educationPaperTaskMapper.selectEducationPaperTaskTotal(pageReqVO);
|
||||
List<EducationPaperTask> list = educationPaperTasks.getList();
|
||||
|
@@ -1,10 +1,16 @@
|
||||
package pc.exam.pp.module.exam.service.paper;
|
||||
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.EducationPaperScheme;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.app.AppCheckDO;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.specialty.ExamSpecialty;
|
||||
import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperSchemeMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.specialty.ExamSpecialtyMapper;
|
||||
import pc.exam.pp.module.exam.service.app.AppCheckService;
|
||||
import pc.exam.pp.module.exam.service.specialty.ExamSpecialtyService;
|
||||
import pc.exam.pp.module.exam.utils.uuid.IdUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -20,7 +26,10 @@ import java.util.stream.Collectors;
|
||||
public class EducationPaperSchemeServiceImpl implements IEducationPaperSchemeService {
|
||||
@Autowired
|
||||
private EducationPaperSchemeMapper educationPaperSchemeMapper;
|
||||
|
||||
@Autowired
|
||||
private ExamSpecialtyMapper examSpecialtyMapper;
|
||||
@Resource
|
||||
AppCheckService appCheckService;
|
||||
/**
|
||||
* 查询试卷方案
|
||||
*
|
||||
@@ -68,6 +77,25 @@ public class EducationPaperSchemeServiceImpl implements IEducationPaperSchemeSer
|
||||
|
||||
educationPaperScheme.setKeywords(keywordStr);
|
||||
educationPaperScheme.setPointNames(pointNameStr);
|
||||
List<AppCheckDO> appCheckDOList = appCheckService.getAppList(educationPaperScheme.getTaskId());
|
||||
|
||||
// 根据题型名称查询软件环境
|
||||
List<ExamSpecialty> examSpecialty = examSpecialtyMapper.selectExamSpecialtyBySpName(educationPaperScheme.getSpName());
|
||||
if (examSpecialty != null && !examSpecialty.isEmpty()) {
|
||||
ExamSpecialty exams = examSpecialty.get(0);
|
||||
if (exams.getRoles() != null && !exams.getRoles().isEmpty()) {
|
||||
|
||||
// 判断是否在数组中存在
|
||||
boolean exists = appCheckDOList.stream()
|
||||
.anyMatch(a -> exams.getRoles().equals(a.getAppName())); // 根据 appName 判断
|
||||
if (!exists) {
|
||||
AppCheckDO appCheckDO = new AppCheckDO();
|
||||
appCheckDO.setTaskId(educationPaperScheme.getTaskId());
|
||||
appCheckDO.setAppName(exams.getRoles());
|
||||
appCheckService.insertAppCheck(appCheckDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 然后插入到数据库
|
||||
return educationPaperSchemeMapper.insertEducationPaperScheme(educationPaperScheme);
|
||||
|
@@ -163,6 +163,8 @@ public class EducationPaperServiceImpl implements IEducationPaperService
|
||||
public int addPaperList(Integer num, String taskid,String taskSpecialty) {
|
||||
//根据试卷任务id查找方案集合
|
||||
List<EducationPaperScheme> educationPaperSchemeList= educationPaperSchemeMapper.selectEducationPaperTaskByTaskId(taskid);
|
||||
//根据任务查找任务里面是否有试卷,如果没有给新创建的试卷 抽卷方式为 随机
|
||||
List<EducationPaper> educationPapers = educationPaperMapper.selectPaperListByTaskId(taskid);
|
||||
for (int i = 0; i <num ; i++) {
|
||||
List<String> examQuestionIds = new ArrayList<>();
|
||||
int totalScore = 0;
|
||||
@@ -211,8 +213,6 @@ public class EducationPaperServiceImpl implements IEducationPaperService
|
||||
// 格式化为8位,不足前面补0
|
||||
String formattedNumber = String.format("%08d", ++number);
|
||||
|
||||
//根据任务查找任务里面是否有试卷,如果没有给新创建的试卷 抽卷方式为 随机
|
||||
List<EducationPaper> educationPapers = educationPaperMapper.selectPaperListByTaskId(taskid);
|
||||
|
||||
|
||||
//构建试卷
|
||||
|
@@ -60,6 +60,12 @@ public class EducationPaperSessionServiceImpl implements IEducationPaperSessionS
|
||||
{
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
educationPaperSession.setSessionId(uuid);
|
||||
List<EducationPaperSession> educationPaperSessions = educationPaperSessionMapper.selectEducationPaperSessionByTaskId(educationPaperSession.getTaskId());
|
||||
int size = educationPaperSessions.size()+1;
|
||||
String batch= "第"+size+"场";
|
||||
educationPaperSession.setBatch(batch);
|
||||
|
||||
|
||||
return educationPaperSessionMapper.insertEducationPaperSession(educationPaperSession);
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
package pc.exam.pp.module.exam.service.paper;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -9,6 +11,7 @@ import pc.exam.pp.framework.common.pojo.PageResult;
|
||||
import pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
||||
import pc.exam.pp.framework.tenant.core.context.TenantContextHolder;
|
||||
import pc.exam.pp.framework.web.core.util.WebFrameworkUtils;
|
||||
import pc.exam.pp.module.exam.controller.admin.exception.QueTypeException;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.dto.PaperQueUpdateDTO;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.dto.SchemeParam;
|
||||
@@ -16,11 +19,16 @@ import pc.exam.pp.module.exam.controller.admin.paper.dto.TempDto;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperTaskPageVo;
|
||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.StuInfoPaper;
|
||||
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtyQueryVo;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.*;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.app.AppCheckDO;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.specialty.ExamSpecialty;
|
||||
import pc.exam.pp.module.exam.dal.mysql.app.AppCheckMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.monitor.MonitorMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.paper.*;
|
||||
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionFileMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.specialty.ExamSpecialtyMapper;
|
||||
import pc.exam.pp.module.exam.utils.date.DateUtils;
|
||||
import pc.exam.pp.module.exam.utils.uuid.IdUtils;
|
||||
|
||||
@@ -31,6 +39,8 @@ import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static pc.exam.pp.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
/**
|
||||
* 试卷任务Service业务层处理
|
||||
*
|
||||
@@ -65,9 +75,12 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
private MonitorMapper monitorMapper;
|
||||
//@Autowired
|
||||
//private ExamQuestionMapper
|
||||
|
||||
@Resource
|
||||
private ExamSpecialtyMapper examSpecialtyMapper;
|
||||
@Autowired
|
||||
private ExamQuestionMapper examQuestionMapper;
|
||||
@Resource
|
||||
AppCheckMapper appCheckMapper;
|
||||
|
||||
/**
|
||||
* 查询试卷任务
|
||||
@@ -88,6 +101,9 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
*/
|
||||
@Override
|
||||
public PageResult<EducationPaperTask> selectEducationPaperTaskList(PaperTaskPageVo educationPaperTask) {
|
||||
//获取创建人
|
||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||
educationPaperTask.setCreator(String.valueOf(loginUserId));
|
||||
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskList(educationPaperTask);
|
||||
List<EducationPaperTask> list = educationPaperTasks.getList();
|
||||
if (list != null && list.size() > 0) {
|
||||
@@ -144,7 +160,6 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
educationPaperParam.setIsConnect("0");
|
||||
educationPaperParam.setIsAnswerId("1");
|
||||
educationPaperParam.setIsTime("0");
|
||||
educationPaperParam.setIsDelete("0");
|
||||
educationPaperParam.setDirectory("KSWJ");
|
||||
educationPaperParam.setUploadTime("5");
|
||||
educationPaperParam.setIsCopy("1");
|
||||
@@ -161,7 +176,9 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
educationPaperParam.setIsConnect("30");
|
||||
educationPaperParam.setIsScore("1");
|
||||
educationPaperParam.setIsScoreDetail("1");
|
||||
educationPaperParam.setIsDelete("1");
|
||||
} else {
|
||||
educationPaperParam.setIsDelete("0");
|
||||
educationPaperParam.setIsRepeat("0");
|
||||
educationPaperParam.setIsAnswer("0");
|
||||
educationPaperParam.setIsLook("0");
|
||||
@@ -176,7 +193,7 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
// 新增任务参数
|
||||
educationPaperParamMapper.insertEducationPaperParam(educationPaperParam);
|
||||
// 新增任务
|
||||
return educationPaperTaskMapper.insertEducationPaperTask(educationPaperTask);
|
||||
return educationPaperTaskMapper.insert(educationPaperTask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,7 +343,122 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
|
||||
@Override
|
||||
public List<String> getCourseList() {
|
||||
return educationPaperTaskMapper.getCourseList();
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
// 获取考点ID
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
AdminUser adminUserDO = getUser(userId);
|
||||
List<SpecialtyQueryVo> specialtyQueryVos = new ArrayList<>();
|
||||
// 判断是否是中心服务器,如果是中心服务器的话直接返回所有,如果不是查询对应的授权数据
|
||||
if (tenantId == 1) {
|
||||
// 判断用户类型 管理员所有专业
|
||||
if (adminUserDO.getUserType().equals("0")) {
|
||||
// 查询所有专业数据
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyAll();
|
||||
} else {
|
||||
// 判断专业是否为空,为空的话查询所有
|
||||
if (adminUserDO.getSpecialtyIds() == null) {
|
||||
// 查询所有数据
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyAll();
|
||||
} else {
|
||||
// 查询部分数据
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 需要先界定 数据范围,通过考点服务器ID进行查询考点服务器的授权范围
|
||||
List<TenantSpcialty> tenantSpcialtyDOS = examSpecialtyMapper.getSpecialtyPoints(tenantId);
|
||||
// 通过ID查询对应的科目信息
|
||||
for (TenantSpcialty spcialtyDO : tenantSpcialtyDOS) {
|
||||
ExamSpecialty examSpecialty = examSpecialtyMapper.selectExamSpecialtyBySpId(spcialtyDO.getSpecialtyId());
|
||||
// 获取对应的父级参数
|
||||
ExamSpecialty examSpecialtyForUp = examSpecialtyMapper.selectExamSpecialtyBySpId(examSpecialty.getParentId());
|
||||
if (examSpecialty.getParentId() == 0) {
|
||||
// 说明是整个专业下面所有的
|
||||
List<ExamSpecialty> examSpecialties = getChildExamSpecialtyList(Collections.singleton(examSpecialtyForUp.getSpId()));
|
||||
for (ExamSpecialty examSpecialtyInfo : examSpecialties) {
|
||||
// 检查是否已存在相同ID的元素
|
||||
boolean exists = specialtyQueryVos.stream()
|
||||
.anyMatch(v -> v.getId().equals(examSpecialtyInfo.getSpId()));
|
||||
if (!exists) {
|
||||
SpecialtyQueryVo specialtyQueryVo = new SpecialtyQueryVo();
|
||||
specialtyQueryVo.setStatus(examSpecialtyInfo.getStatus());
|
||||
specialtyQueryVo.setName(examSpecialtyInfo.getSpName());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyInfo.getAncestors());
|
||||
specialtyQueryVo.setOrderNum(examSpecialtyInfo.getOrderNum());
|
||||
specialtyQueryVo.setId(examSpecialtyInfo.getSpId());
|
||||
specialtyQueryVo.setRoles(examSpecialtyInfo.getRoles());
|
||||
specialtyQueryVo.setParentId(examSpecialtyInfo.getParentId());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyInfo.getAncestors());
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 检查是否已存在相同ID的元素
|
||||
boolean exists = specialtyQueryVos.stream()
|
||||
.anyMatch(v -> v.getId().equals(examSpecialty.getSpId()));
|
||||
if (!exists) {
|
||||
SpecialtyQueryVo specialtyQueryVo = new SpecialtyQueryVo();
|
||||
specialtyQueryVo.setStatus(examSpecialty.getStatus());
|
||||
specialtyQueryVo.setName(examSpecialty.getSpName());
|
||||
specialtyQueryVo.setAncestors(examSpecialty.getAncestors());
|
||||
specialtyQueryVo.setOrderNum(examSpecialty.getOrderNum());
|
||||
specialtyQueryVo.setId(examSpecialty.getSpId());
|
||||
specialtyQueryVo.setRoles(examSpecialty.getRoles());
|
||||
specialtyQueryVo.setParentId(examSpecialty.getParentId());
|
||||
specialtyQueryVo.setAncestors(examSpecialty.getAncestors());
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
}
|
||||
boolean existsUp = specialtyQueryVos.stream()
|
||||
.anyMatch(v -> v.getId().equals(examSpecialtyForUp.getSpId()));
|
||||
if (!existsUp) {
|
||||
SpecialtyQueryVo specialtyQueryVo = new SpecialtyQueryVo();
|
||||
specialtyQueryVo.setStatus(examSpecialtyForUp.getStatus());
|
||||
specialtyQueryVo.setName(examSpecialtyForUp.getSpName());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyForUp.getAncestors());
|
||||
specialtyQueryVo.setOrderNum(examSpecialtyForUp.getOrderNum());
|
||||
specialtyQueryVo.setId(examSpecialtyForUp.getSpId());
|
||||
specialtyQueryVo.setRoles(examSpecialtyForUp.getRoles());
|
||||
specialtyQueryVo.setParentId(examSpecialtyForUp.getParentId());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyForUp.getAncestors());
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
}
|
||||
List<ExamSpecialty> examSpecialties = getChildExamSpecialtyList(Collections.singleton(examSpecialty.getSpId()));
|
||||
for (ExamSpecialty examSpecialtyInfo : examSpecialties) {
|
||||
// 检查是否已存在相同ID的元素
|
||||
boolean existsDown = specialtyQueryVos.stream()
|
||||
.anyMatch(v -> v.getId().equals(examSpecialtyInfo.getSpId()));
|
||||
if (!existsDown) {
|
||||
SpecialtyQueryVo specialtyQueryVo = new SpecialtyQueryVo();
|
||||
specialtyQueryVo.setStatus(examSpecialtyInfo.getStatus());
|
||||
specialtyQueryVo.setName(examSpecialtyInfo.getSpName());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyInfo.getAncestors());
|
||||
specialtyQueryVo.setOrderNum(examSpecialtyInfo.getOrderNum());
|
||||
specialtyQueryVo.setId(examSpecialtyInfo.getSpId());
|
||||
specialtyQueryVo.setRoles(examSpecialtyInfo.getRoles());
|
||||
specialtyQueryVo.setParentId(examSpecialtyInfo.getParentId());
|
||||
specialtyQueryVo.setAncestors(examSpecialtyInfo.getAncestors());
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 通过ID查询下面的参数
|
||||
// 判断用户类型 管理员所有专业 , 不是管理员的话需要筛选
|
||||
if (!adminUserDO.getUserType().equals("0")) {
|
||||
// 判断专业是否为空,为空的话查询所有
|
||||
if (adminUserDO.getSpecialtyIds() == null) {
|
||||
// 查询所有数据
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyAll();
|
||||
} else {
|
||||
// 查询部分数据
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
List<String> courseNames = getThirdLevelNames(specialtyQueryVos);
|
||||
return courseNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -405,7 +537,7 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
// 格式化时间为字符串
|
||||
String timeString = now.format(formatter);
|
||||
educationPaperTask.setTaskName(educationPaperTask.getTaskName() + timeString);
|
||||
|
||||
educationPaperTask.setCreateTime(now);
|
||||
educationPaperTask.setIsTemplate(1);
|
||||
educationPaperTaskMapper.insertEducationPaperTask(educationPaperTask);
|
||||
|
||||
@@ -419,6 +551,17 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
educationPaperSchemeList.forEach(scheme -> scheme.setTaskId(newtaskId));
|
||||
//构建新方案
|
||||
educationPaperSchemeMapper.insertEducationPaperSchemeList(educationPaperSchemeList);
|
||||
List<AppCheckDO> appCheckDOList = new ArrayList<>();
|
||||
List<AppCheckDO> appCheckDOS = appCheckMapper.selectList(taskId);
|
||||
if (appCheckDOS!=null&&appCheckDOS.size()>0){
|
||||
for (AppCheckDO appCheckDO : appCheckDOS) {
|
||||
AppCheckDO newAppCheckDO = new AppCheckDO();
|
||||
newAppCheckDO.setTaskId(newtaskId);
|
||||
newAppCheckDO.setAppName(appCheckDO.getAppName());
|
||||
appCheckDOList.add(newAppCheckDO);
|
||||
}
|
||||
appCheckMapper.insert(appCheckDOList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -464,6 +607,18 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId);
|
||||
educationPaperParam.setTaskId(newtaskId);
|
||||
educationPaperParam.setParamId(IdUtils.simpleUUID());
|
||||
//考试不删除学生文件
|
||||
String taskType = educationPaperTask.getTaskType();
|
||||
if ("1".equals(taskType)){
|
||||
educationPaperParam.setIsDelete("1");
|
||||
educationPaperParam.setIsRepeat("1");
|
||||
educationPaperParam.setIsAnswer("1");
|
||||
educationPaperParam.setIsLook("1");
|
||||
educationPaperParam.setIsConnect("30");
|
||||
educationPaperParam.setIsScore("1");
|
||||
educationPaperParam.setIsScoreDetail("1");
|
||||
educationPaperParam.setIsDelete("1");
|
||||
}
|
||||
educationPaperParamMapper.insertEducationPaperParam(educationPaperParam);
|
||||
|
||||
}
|
||||
@@ -618,7 +773,7 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
public PageResult<EducationPaperTask> selectEducationPaperTaskListByStu(PaperTaskPageVo educationPaperTask) {
|
||||
String taskType = educationPaperTask.getTaskType();
|
||||
|
||||
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskList(educationPaperTask);
|
||||
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskStuList(educationPaperTask);
|
||||
Long stuId = SecurityFrameworkUtils.getLoginUserId();
|
||||
List<EducationPaperTask> list = educationPaperTasks.getList();
|
||||
List<String> taskIds = educationPaperPersonMapper.selectTaskIdByStuid(stuId);
|
||||
@@ -671,11 +826,12 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
//查找 考试状态还没结束的 任务id ,取 交集
|
||||
List<String> taskNoEndIds = monitorMapper.selectByStuIdAndTaskId(stuId);
|
||||
|
||||
if (taskType.equals("1")) {
|
||||
if ("1".equals(taskType)) {
|
||||
if (list != null && list.size() > 0 && taskNoEndIds != null && taskNoEndIds.size() > 0) {
|
||||
list = list.stream()
|
||||
.filter(task -> taskNoEndIds.contains(task.getTaskId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,4 +885,95 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<EducationPaperTask> selectEducationPaperTaskListlistMoBan(PaperTaskPageVo educationPaperTask) {
|
||||
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskList(educationPaperTask);
|
||||
List<EducationPaperTask> list = educationPaperTasks.getList();
|
||||
if (list != null && list.size() > 0) {
|
||||
for (EducationPaperTask paperTask : list) {
|
||||
int count = 0;
|
||||
List<EducationPaper> educationPapers = educationPaperMapper.selectPaperListByTaskId(paperTask.getTaskId());
|
||||
if (educationPapers != null && educationPapers.size() > 0) {
|
||||
for (EducationPaper educationPaper : educationPapers) {
|
||||
try {
|
||||
count += Integer.parseInt(educationPaper.getCounts());
|
||||
} catch (NumberFormatException e) {
|
||||
// 可选:记录异常或忽略非法数字
|
||||
System.err.println("无效的 counts 值: " + educationPaper.getCounts());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
paperTask.setCount(String.valueOf(count));
|
||||
|
||||
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(paperTask.getTaskId());
|
||||
paperTask.setEducationPaperParam(educationPaperParam);
|
||||
}
|
||||
}
|
||||
|
||||
return educationPaperTasks;
|
||||
}
|
||||
|
||||
public List<ExamSpecialty> getChildExamSpecialtyList(Collection<Long> ids) {
|
||||
List<ExamSpecialty> children = new LinkedList<>();
|
||||
// 遍历每一层
|
||||
Collection<Long> parentIds = ids;
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
|
||||
// 查询当前层,所有的子Xlsx考点
|
||||
List<ExamSpecialty> Xlsxs = examSpecialtyMapper.selectListByParentId(parentIds);
|
||||
// 1. 如果没有子Xlsx考点,则结束遍历
|
||||
if (CollUtil.isEmpty(Xlsxs)) {
|
||||
break;
|
||||
}
|
||||
// 2. 如果有子Xlsx考点,继续遍历
|
||||
children.addAll(Xlsxs);
|
||||
parentIds = convertSet(Xlsxs, ExamSpecialty::getSpId);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
public static List<String> getThirdLevelNames(List<SpecialtyQueryVo> list) {
|
||||
// ✅ 判空
|
||||
if (list == null || list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 第1层:专业(parentId = 0)
|
||||
Set<Long> level1Ids = list.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(item -> item.getParentId() != null && item.getParentId() == 0)
|
||||
.map(SpecialtyQueryVo::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (level1Ids.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 第2层:课程(父节点是专业)
|
||||
Set<Long> level2Ids = list.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(item -> item.getParentId() != null && level1Ids.contains(item.getParentId()))
|
||||
.map(SpecialtyQueryVo::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (level2Ids.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 第3层:题型(父节点是课程)
|
||||
return list.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(item -> item.getParentId() != null && level2Ids.contains(item.getParentId()))
|
||||
.map(SpecialtyQueryVo::getName) // ✅ 只返回 name
|
||||
.filter(Objects::nonNull)
|
||||
.distinct() // 去重(可选)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public AdminUser getUser(Long id) {
|
||||
return examSpecialtyMapper.selectUserById(id);
|
||||
}
|
||||
}
|
||||
|
@@ -119,5 +119,7 @@ public interface IEducationPaperTaskService
|
||||
|
||||
void checkType(PaperQueUpdateDTO dto);
|
||||
|
||||
PageResult<EducationPaperTask> selectEducationPaperTaskListlistMoBan(PaperTaskPageVo educationPaperTask);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
<select id="selectEducationPaperSessionByTaskId" resultMap="EducationPaperSessionResult">
|
||||
<include refid="selectEducationPaperSessionVo"/>
|
||||
where task_id =#{taskId}
|
||||
and status = '0'
|
||||
</select>
|
||||
<select id="getAnswerTime" resultType="java.sql.Time">
|
||||
select exam_time from education_paper_param where task_id =#{taskId}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
<result property="taskSpecialty" column="task_specialty" />
|
||||
<result property="taskType" column="task_type" />
|
||||
<result property="isOne" column="is_one" />
|
||||
<result property="share" column="share" />
|
||||
<result property="isTemplate" column="is_template" />
|
||||
<result property="status" column="status" />
|
||||
<result property="createTime" column="create_time" />
|
||||
@@ -31,7 +32,7 @@
|
||||
<result property="treeNum" column="tree_num" />
|
||||
</resultMap>
|
||||
<sql id="selectEducationPaperTaskVo">
|
||||
select task_id, task_name,task_num, task_specialty, task_type,is_one, is_template, status, create_time, update_time, creator, updater, deleted,tenant_id from education_paper_task
|
||||
select task_id, task_name,task_num, task_specialty, task_type,is_one, is_template, status,share, create_time, update_time, creator, updater, deleted,tenant_id from education_paper_task
|
||||
</sql>
|
||||
|
||||
|
||||
@@ -215,6 +216,7 @@
|
||||
<if test="taskSpecialty != null">task_specialty,</if>
|
||||
<if test="taskType != null">task_type,</if>
|
||||
<if test="isOne != null">is_one,</if>
|
||||
<if test="share != null">share,</if>
|
||||
<if test="isTemplate != null">is_template,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
@@ -231,6 +233,7 @@
|
||||
<if test="taskSpecialty != null">#{taskSpecialty},</if>
|
||||
<if test="taskType != null">#{taskType},</if>
|
||||
<if test="isOne != null">#{isOne},</if>
|
||||
<if test="share != null">#{share},</if>
|
||||
<if test="isTemplate != null">#{isTemplate},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
@@ -250,6 +253,7 @@
|
||||
<if test="taskSpecialty != null">task_specialty = #{taskSpecialty},</if>
|
||||
<if test="taskType != null">task_type = #{taskType},</if>
|
||||
<if test="isOne != null">is_one = #{isOne},</if>
|
||||
<if test="share != null">share = #{share},</if>
|
||||
<if test="isTemplate != null">is_template = #{isTemplate},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
|
@@ -73,7 +73,6 @@
|
||||
where stu_id =#{stuId}
|
||||
and task_id = #{taskId}
|
||||
and deleted = '0'
|
||||
and exam_status = '0'
|
||||
</select>
|
||||
|
||||
|
||||
|
@@ -194,6 +194,16 @@
|
||||
and status = '0'
|
||||
and tenant_id = #{loginTenantId}
|
||||
</select>
|
||||
<select id="getSpecialtyPoints" resultType="pc.exam.pp.module.exam.dal.dataobject.TenantSpcialty">
|
||||
SELECT *
|
||||
FROM exam_tenant_specialty
|
||||
WHERE tenant_id = #{tenantId}
|
||||
</select>
|
||||
<select id="selectUserById" resultType="pc.exam.pp.module.exam.dal.dataobject.AdminUser">
|
||||
SELECT *
|
||||
FROM system_users
|
||||
WHERE id = #{id}
|
||||
</select>
|
||||
|
||||
|
||||
<update id="deleteExamSpecialtyBySpId" parameterType="Long">
|
||||
|
@@ -120,7 +120,7 @@ public class AutoWpsController {
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping(value = "/xlsxMaster", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public CommonResult<List<JudgementXlsxVO>> xlsxMaster(@RequestPart("data") String jsonData, @RequestPart("file") MultipartFile file, @RequestParam(value = "cell", required = false) List<String> cell) throws Exception {
|
||||
public CommonResult<List<JudgementXlsxVO>> xlsxMaster(@RequestPart("data") String jsonData, @RequestPart("file") MultipartFile file, @RequestParam(value = "cell", required = false) List<String> cell,@RequestParam(value = "keyWords", required = false) String keyWords ) throws Exception {
|
||||
// 手动解析JSON数组
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<WpsXlsxInfoVo> wpsXlsxInfoVos = objectMapper.readValue(
|
||||
@@ -128,7 +128,7 @@ public class AutoWpsController {
|
||||
new TypeReference<List<WpsXlsxInfoVo>>() {
|
||||
}
|
||||
);
|
||||
return CommonResult.success(judgementWpsExcelService.xlsxMaster(wpsXlsxInfoVos, file, cell));
|
||||
return CommonResult.success(judgementWpsExcelService.xlsxMaster(wpsXlsxInfoVos, file, cell,keyWords));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -356,6 +356,20 @@ public class AutoToolsController {
|
||||
return CommonResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止考试(用户所有)
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
@GetMapping("/allStopExam")
|
||||
public CommonResult<Boolean> stopExam() {
|
||||
String userId = null;
|
||||
userId = String.valueOf(SecurityFrameworkUtils.getLoginUserId());
|
||||
// 删除该用户对应的线程池
|
||||
taskManager.stopTask(userId);
|
||||
return CommonResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止考试
|
||||
*
|
||||
@@ -502,6 +516,12 @@ public class AutoToolsController {
|
||||
return CommonResult.error(1_0001_002,"没有找到对应的学生信息");
|
||||
}
|
||||
|
||||
@GetMapping("/taskStatus")
|
||||
@Operation(summary = "获取WS的任务列表")
|
||||
public CommonResult<Map<String, Object>> logTaskStatus() {
|
||||
return CommonResult.success(taskManager.getTasksInfo());
|
||||
}
|
||||
|
||||
// 时间转换
|
||||
public static String formatLongDuration(int totalSeconds) {
|
||||
return TaskManager.formatLongDuration(totalSeconds);
|
||||
|
@@ -13,6 +13,8 @@ import pc.exam.pp.module.infra.api.websocket.WebSocketSenderApi;
|
||||
import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuInTheExam;
|
||||
import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuTheExamInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -64,6 +66,13 @@ public class TaskManager {
|
||||
log.info("任务 {} 已启动", userId);
|
||||
}
|
||||
|
||||
public Map<String, Object> getTasksInfo() {
|
||||
Map<String, Object> info = new HashMap<>();
|
||||
info.put("totalTasks", tasks.size());
|
||||
info.put("activeUserIds", new ArrayList<>(tasks.keySet()));
|
||||
return info;
|
||||
}
|
||||
|
||||
/** 结束任务 */
|
||||
public void stopTask(String userId) {
|
||||
ScheduledFuture<?> future = tasks.get(userId);
|
||||
|
@@ -15,7 +15,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface JudgementWpsExcelService {
|
||||
|
||||
List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell) throws Exception;
|
||||
List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell,String keyWords) throws Exception;
|
||||
|
||||
List<XlsxDataInfoVO> xlsxDataInfo(MultipartFile file) throws Exception;
|
||||
}
|
||||
|
@@ -17,8 +17,8 @@ public class JudgementWpsExcelServiceImpl implements JudgementWpsExcelService {
|
||||
|
||||
|
||||
@Override
|
||||
public List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell) throws Exception {
|
||||
return XlsxMaster.xlsxMaster(wpsXlsxInfoVos, file,cell);
|
||||
public List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell,String keyWords) throws Exception {
|
||||
return XlsxMaster.xlsxMaster(wpsXlsxInfoVos, file,cell,keyWords);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -45,7 +45,7 @@ public class XlsxMaster {
|
||||
* @throws IOException IO
|
||||
* @throws Docx4JException 异常
|
||||
*/
|
||||
public static List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell) throws IOException, Docx4JException {
|
||||
public static List<JudgementXlsxVO> xlsxMaster(List<WpsXlsxInfoVo> wpsXlsxInfoVos, MultipartFile file,List<String> cell,String keyWords) throws IOException, Docx4JException {
|
||||
List<JudgementXlsxVO> judgementXlsxVOS = new ArrayList<>();
|
||||
// 1、获取想要判断的文件地址(文件流)
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
@@ -91,6 +91,7 @@ public class XlsxMaster {
|
||||
Class<?>[] paramTypes = {
|
||||
org.apache.poi.ss.usermodel.Cell.class,
|
||||
org.apache.poi.ss.usermodel.Workbook.class,
|
||||
String.class
|
||||
};
|
||||
Method methodWithArgs = excelFunctions.getClass().getMethod(function, paramTypes);
|
||||
|
||||
@@ -99,7 +100,7 @@ public class XlsxMaster {
|
||||
for (String cellRef : cell) {
|
||||
org.apache.poi.ss.usermodel.Cell poiCell = getPoiCellFromRef(workbook, sheetName, cellRef);
|
||||
if (poiCell == null) continue;
|
||||
String value = (String) methodWithArgs.invoke(excelFunctions, poiCell, workbook);
|
||||
String value = (String) methodWithArgs.invoke(excelFunctions, poiCell, workbook,keyWords);
|
||||
|
||||
if (value != null) {
|
||||
if ("getCellDataFormat".equals(function)){
|
||||
|
@@ -36,13 +36,13 @@ public class CellIng {
|
||||
Map.entry("SLANTEDDASHDOT", "斜点划线")
|
||||
);
|
||||
// 获取左框线样式
|
||||
public String getLeftBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getLeftBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
BorderStyle border = style.getBorderLeft();
|
||||
return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无";
|
||||
}
|
||||
// 获取左框线颜色
|
||||
public String getLeftBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getLeftBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style instanceof XSSFCellStyle) {
|
||||
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
|
||||
@@ -53,14 +53,14 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取上框线样式
|
||||
public String getTopBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getTopBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
BorderStyle border = style.getBorderTop();
|
||||
return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无";
|
||||
}
|
||||
|
||||
// 获取上框线颜色
|
||||
public String getTopBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getTopBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style instanceof XSSFCellStyle) {
|
||||
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
|
||||
@@ -70,14 +70,14 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取右框线样式
|
||||
public String getRightBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getRightBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
BorderStyle border = style.getBorderRight();
|
||||
return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无";
|
||||
}
|
||||
|
||||
// 获取右框线颜色
|
||||
public String getRightBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getRightBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style instanceof XSSFCellStyle) {
|
||||
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
|
||||
@@ -87,14 +87,14 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取下框线样式
|
||||
public String getBottomBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getBottomBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
BorderStyle border = style.getBorderBottom();
|
||||
return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无";
|
||||
}
|
||||
|
||||
// 获取下框线颜色
|
||||
public String getBottomBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) {
|
||||
public String getBottomBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb,String keyWords) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style instanceof XSSFCellStyle) {
|
||||
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
|
||||
@@ -103,16 +103,34 @@ public class CellIng {
|
||||
return "无";
|
||||
}
|
||||
// 获取单元格的公式表达式(字符串形式)
|
||||
public String getFormulaExpression(Cell cell, Workbook wb) {
|
||||
public String getFormulaExpression(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
if (cell.getCellType() == CellType.FORMULA) {
|
||||
return cell.getCellFormula();
|
||||
}
|
||||
return "无";
|
||||
}
|
||||
// 获取单元格的公式表达式关键字
|
||||
public String getFormulaExpressionContains(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
|
||||
if (cell.getCellType() == CellType.FORMULA) {
|
||||
String formula = cell.getCellFormula();
|
||||
// 转为小写再比较
|
||||
if (formula.toLowerCase().contains(keyWords.toLowerCase())) {
|
||||
return formula; // 包含关键字时返回公式内容
|
||||
} else {
|
||||
return "否"; // 不包含关键字
|
||||
}
|
||||
}
|
||||
return "否";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 获取单元格的公式计算结果(已经计算出来的值,字符串形式)
|
||||
public String getFormulaResult(Cell cell, Workbook wb) {
|
||||
public String getFormulaResult(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
if (cell.getCellType() != CellType.FORMULA) {
|
||||
return null; // 不是公式单元格返回null
|
||||
@@ -138,7 +156,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取单元格字体名称
|
||||
public String getFontName(Cell cell, Workbook wb) {
|
||||
public String getFontName(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -152,7 +170,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取单元格字体字号
|
||||
public String getFontSize(Cell cell, Workbook wb) {
|
||||
public String getFontSize(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -170,7 +188,7 @@ public class CellIng {
|
||||
|
||||
|
||||
// 获取单元格字形(加粗 / 斜体 )
|
||||
public String getFontStyle(Cell cell, Workbook wb) {
|
||||
public String getFontStyle(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -190,7 +208,7 @@ public class CellIng {
|
||||
|
||||
// 获取单元格下划线
|
||||
// 获取单元格下划线类型
|
||||
public String getUnderline(Cell cell, Workbook wb) {
|
||||
public String getUnderline(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -217,7 +235,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 获取单元格颜色
|
||||
public String getFontColor(Cell cell, Workbook wb) {
|
||||
public String getFontColor(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -242,7 +260,7 @@ public class CellIng {
|
||||
return "无";
|
||||
}
|
||||
// 删除线
|
||||
public static String getCellStrikeThrough(Cell cell, Workbook wb) {
|
||||
public static String getCellStrikeThrough(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "否";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "否";
|
||||
@@ -251,7 +269,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 上标
|
||||
public static String getCellSuperScript(Cell cell, Workbook wb) {
|
||||
public static String getCellSuperScript(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "否";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "否";
|
||||
@@ -260,7 +278,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 下标
|
||||
public static String getCellSubScript(Cell cell, Workbook wb) {
|
||||
public static String getCellSubScript(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "否";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "否";
|
||||
@@ -271,7 +289,7 @@ public class CellIng {
|
||||
|
||||
|
||||
// 获取斜下框线样式
|
||||
public static String getDiagonalDownBorderStyle(Cell cell, Workbook wb) {
|
||||
public static String getDiagonalDownBorderStyle(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || !(cell instanceof XSSFCell)) return "无";
|
||||
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
|
||||
|
||||
@@ -297,7 +315,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 斜下框线→颜色
|
||||
public static String getDiagonalDownBorderColor(Cell cell, Workbook wb) {
|
||||
public static String getDiagonalDownBorderColor(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || !(cell instanceof XSSFCell)) return "无";
|
||||
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
|
||||
|
||||
@@ -320,7 +338,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 斜上框线→样式
|
||||
public static String getDiagonalUpBorderStyle(Cell cell, Workbook wb) {
|
||||
public static String getDiagonalUpBorderStyle(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || !(cell instanceof XSSFCell)) return "无";
|
||||
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
|
||||
|
||||
@@ -342,7 +360,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 斜上框线→颜色
|
||||
public static String getDiagonalUpBorderColor(Cell cell, Workbook wb) {
|
||||
public static String getDiagonalUpBorderColor(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || !(cell instanceof XSSFCell)) return "无";
|
||||
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
|
||||
|
||||
@@ -380,14 +398,14 @@ public class CellIng {
|
||||
|
||||
|
||||
// ===== 获取单元格文本(String) =====
|
||||
public String getCellText(Cell cell, Workbook wb) {
|
||||
public String getCellText(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
DataFormatter formatter = new DataFormatter();
|
||||
return formatter.formatCellValue(cell);
|
||||
}
|
||||
|
||||
// ===== 获取单元格值
|
||||
public String getCellValue(Cell cell, Workbook wb) {
|
||||
public String getCellValue(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "";
|
||||
|
||||
switch (cell.getCellType()) {
|
||||
@@ -436,7 +454,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 数字格式
|
||||
public static String getCellDataFormat(Cell cell, Workbook wb) {
|
||||
public static String getCellDataFormat(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -444,7 +462,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 水平对齐
|
||||
public static String getCellHorizontalAlignment(Cell cell, Workbook wb) {
|
||||
public static String getCellHorizontalAlignment(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -453,7 +471,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 垂直对齐
|
||||
public static String getCellVerticalAlignment(Cell cell, Workbook wb) {
|
||||
public static String getCellVerticalAlignment(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -462,7 +480,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 缩进
|
||||
public static String getCellIndent(Cell cell, Workbook wb) {
|
||||
public static String getCellIndent(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "0";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "0";
|
||||
@@ -470,7 +488,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 自动换行
|
||||
public static String getCellWrapText(Cell cell, Workbook wb) {
|
||||
public static String getCellWrapText(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "否";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "否";
|
||||
@@ -478,7 +496,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 缩小字体填充(ShrinkToFit)
|
||||
public static String getCellShrinkToFit(Cell cell, Workbook wb) {
|
||||
public static String getCellShrinkToFit(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "否";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "否";
|
||||
@@ -486,7 +504,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 合并单元格
|
||||
public static String getCellMerged(Cell cell, Workbook wb) {
|
||||
public static String getCellMerged(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || wb == null) return "否";
|
||||
Sheet sheet = cell.getSheet();
|
||||
if (sheet == null) return "否";
|
||||
@@ -505,7 +523,7 @@ public class CellIng {
|
||||
|
||||
|
||||
// 文本方向(rotation)
|
||||
public static String getCellTextRotation(Cell cell, Workbook wb) {
|
||||
public static String getCellTextRotation(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "0";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "0";
|
||||
@@ -513,7 +531,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 文本样式(加粗/斜体/下划线等)
|
||||
public static String getCellFontStyle(Cell cell, Workbook wb) {
|
||||
public static String getCellFontStyle(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null) return "无";
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if (style == null) return "无";
|
||||
@@ -536,7 +554,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 高度(行高)
|
||||
public static String getCellRowHeight(Cell cell, Workbook wb) {
|
||||
public static String getCellRowHeight(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || cell.getSheet() == null) return "默认";
|
||||
Row row = cell.getRow();
|
||||
if (row == null) return "默认";
|
||||
@@ -544,7 +562,7 @@ public class CellIng {
|
||||
}
|
||||
|
||||
// 宽度(列宽)
|
||||
public static String getCellColumnWidth(Cell cell, Workbook wb) {
|
||||
public static String getCellColumnWidth(Cell cell, Workbook wb,String keyWords) {
|
||||
if (cell == null || cell.getSheet() == null) return "默认";
|
||||
int colWidth = cell.getSheet().getColumnWidth(cell.getColumnIndex()); // 单位 1/256字符
|
||||
return String.format("%.2f pt", colWidth / 256.0 * 7); // 约 7pt/字符宽,可根据字体调整
|
||||
|
@@ -1686,7 +1686,7 @@ public class SectionPage {
|
||||
}
|
||||
// 横向匹配
|
||||
if (Math.abs(width - sh) <= tol && Math.abs(height - sw) <= tol) {
|
||||
return entry.getKey() + " (横向)";
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ import pc.exam.pp.module.system.convert.auth.AuthConvert;
|
||||
import pc.exam.pp.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.permission.MenuDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import pc.exam.pp.module.system.enums.logger.LoginLogTypeEnum;
|
||||
import pc.exam.pp.module.system.service.auth.AdminAuthService;
|
||||
@@ -25,6 +26,7 @@ import pc.exam.pp.module.system.service.permission.MenuService;
|
||||
import pc.exam.pp.module.system.service.permission.PermissionService;
|
||||
import pc.exam.pp.module.system.service.permission.RoleService;
|
||||
import pc.exam.pp.module.system.service.social.SocialClientService;
|
||||
import pc.exam.pp.module.system.service.tenant.TenantService;
|
||||
import pc.exam.pp.module.system.service.user.AdminUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@@ -37,6 +39,7 @@ import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import pc.exam.pp.module.system.util.oauth2.MacUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -79,6 +82,8 @@ public class AuthController {
|
||||
private ConfigService configService;
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private TenantService tenantService;
|
||||
|
||||
@GetMapping("/login_config")
|
||||
@PermitAll
|
||||
@@ -142,7 +147,7 @@ public class AuthController {
|
||||
// 先判断管理员密码
|
||||
ConfigDO config = configService.getConfigByKey("system_username_logout");
|
||||
if (!config.getValue().equals(loginoutVo.getLoginOutPassword())) {
|
||||
return CommonResult.error(900002, "系统管理员密码错误!");
|
||||
return success("900002");
|
||||
}
|
||||
Set<String> oauth2_access_token_set = stringRedisTemplate.keys("oauth2_access_token:*");
|
||||
for (String oauth2_access_token : oauth2_access_token_set) {
|
||||
|
@@ -7,10 +7,8 @@ import pc.exam.pp.framework.common.pojo.PageParam;
|
||||
import pc.exam.pp.framework.common.pojo.PageResult;
|
||||
import pc.exam.pp.framework.common.util.object.BeanUtils;
|
||||
import pc.exam.pp.framework.excel.core.util.ExcelUtils;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSpecialtyPointsVO;
|
||||
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.*;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantSpcialtyDO;
|
||||
import pc.exam.pp.module.system.service.tenant.TenantService;
|
||||
@@ -113,6 +111,7 @@ public class TenantController {
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得租户分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
|
||||
@TenantIgnore
|
||||
public CommonResult<PageResult<TenantRespVO>> getTenantPage(@Valid TenantPageReqVO pageVO) {
|
||||
PageResult<TenantDO> pageResult = tenantService.getTenantPage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, TenantRespVO.class));
|
||||
@@ -131,4 +130,14 @@ public class TenantController {
|
||||
BeanUtils.toBean(list, TenantRespVO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置租户管理员密码
|
||||
*/
|
||||
@PostMapping("/reset-password")
|
||||
@Operation(summary = "重置租户管理员密码")
|
||||
@TenantIgnore
|
||||
public CommonResult<String> resetPassword(@RequestBody ResetPasswordReqVO reqVO) {
|
||||
tenantService.resetPassword(reqVO);
|
||||
return success("密码重置成功!");
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,9 @@
|
||||
package pc.exam.pp.module.system.controller.admin.tenant.vo.tenant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ResetPasswordReqVO {
|
||||
private Long id; // 租户ID 或 管理员ID
|
||||
private String password; // 新密码
|
||||
}
|
@@ -19,8 +19,8 @@ public class TenantRespVO {
|
||||
@ExcelProperty("租户编号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
@ExcelProperty("租户名")
|
||||
@Schema(description = "学校用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
@ExcelProperty("学校用户名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
|
||||
@@ -36,7 +36,11 @@ public class TenantRespVO {
|
||||
@DictFormat(DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "绑定域名", example = "https://www.iocoder.cn")
|
||||
@Schema(description = "管理员账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
|
||||
@ExcelProperty("管理员账号")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "绑定MAC地址", example = "https://www.iocoder.cn")
|
||||
private String website;
|
||||
|
||||
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@@ -52,4 +56,6 @@ public class TenantRespVO {
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String contactUserId;
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package pc.exam.pp.module.system.dal.dataobject.tenant;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.mybatis.core.dataobject.BaseDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.user.AdminUserDO;
|
||||
@@ -79,5 +80,10 @@ public class TenantDO extends BaseDO {
|
||||
|
||||
|
||||
private String queueName;
|
||||
/**
|
||||
* 管理员账号
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String username;
|
||||
|
||||
}
|
||||
|
@@ -70,4 +70,7 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
|
||||
|
||||
List<UserRespVO> selectUserByIdList(@Param("id") Long id);
|
||||
|
||||
String selectOneById(Long id);
|
||||
|
||||
void updateByIdToPassword(@Param("password")String password, @Param("id")Long id);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package pc.exam.pp.module.system.service.tenant;
|
||||
|
||||
import pc.exam.pp.framework.common.pojo.PageResult;
|
||||
import pc.exam.pp.framework.tenant.core.context.TenantContextHolder;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.ResetPasswordReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSpecialtyPointsVO;
|
||||
@@ -145,4 +146,5 @@ public interface TenantService {
|
||||
*/
|
||||
void validTenant(Long id);
|
||||
|
||||
void resetPassword(ResetPasswordReqVO reqVO);
|
||||
}
|
||||
|
@@ -4,16 +4,19 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.common.pojo.PageResult;
|
||||
import pc.exam.pp.framework.common.util.collection.CollectionUtils;
|
||||
import pc.exam.pp.framework.common.util.date.DateUtils;
|
||||
import pc.exam.pp.framework.common.util.object.BeanUtils;
|
||||
import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import pc.exam.pp.framework.tenant.config.TenantProperties;
|
||||
import pc.exam.pp.framework.tenant.core.context.TenantContextHolder;
|
||||
import pc.exam.pp.framework.tenant.core.util.TenantUtils;
|
||||
import pc.exam.pp.module.exam.utils.rabbitmq.RabbitmqUtils;
|
||||
import pc.exam.pp.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.ResetPasswordReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.tenant.vo.tenant.TenantSpecialtyPointsVO;
|
||||
@@ -23,8 +26,10 @@ import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantPackageDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantSpcialtyDO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import pc.exam.pp.module.system.dal.mysql.tenant.TenantMapper;
|
||||
import pc.exam.pp.module.system.dal.mysql.tenant.TenantSpecialtyMapper;
|
||||
import pc.exam.pp.module.system.dal.mysql.user.AdminUserMapper;
|
||||
import pc.exam.pp.module.system.enums.permission.RoleCodeEnum;
|
||||
import pc.exam.pp.module.system.enums.permission.RoleTypeEnum;
|
||||
import pc.exam.pp.module.system.service.permission.MenuService;
|
||||
@@ -81,7 +86,10 @@ public class TenantServiceImpl implements TenantService {
|
||||
private MenuService menuService;
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Resource
|
||||
private AdminUserMapper userMapper;
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Override
|
||||
public List<Long> getTenantIdList() {
|
||||
List<TenantDO> tenants = tenantMapper.selectList();
|
||||
@@ -102,6 +110,13 @@ public class TenantServiceImpl implements TenantService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(ResetPasswordReqVO reqVO) {
|
||||
AdminUserDO adminUserDO=new AdminUserDO();
|
||||
String newPassword = passwordEncoder.encode(reqVO.getPassword());
|
||||
userMapper.updateByIdToPassword(newPassword,reqVO.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
||||
public Long createTenant(TenantSaveReqVO createReqVO) {
|
||||
@@ -276,7 +291,19 @@ public class TenantServiceImpl implements TenantService {
|
||||
|
||||
@Override
|
||||
public PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO) {
|
||||
return tenantMapper.selectPage(pageReqVO);
|
||||
PageResult<TenantDO> tenantDOPageResult = tenantMapper.selectPage(pageReqVO);
|
||||
List<TenantDO> list = tenantDOPageResult.getList();
|
||||
if (list!=null&&list.size()>0){
|
||||
for (TenantDO tenantDO : list) {
|
||||
Long contactUserId = tenantDO.getContactUserId();
|
||||
String userName= userMapper.selectOneById(contactUserId);
|
||||
if (userName != null) {
|
||||
tenantDO.setUsername(userName); //设置管理员账号
|
||||
}
|
||||
}
|
||||
}
|
||||
tenantDOPageResult.setList(list);
|
||||
return tenantDOPageResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -840,17 +840,19 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyAll();
|
||||
} else {
|
||||
// 查询部分数据
|
||||
List<SpecialtyQueryVo> specialtyList = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
for (SpecialtyQueryVo specialtyQueryVo : specialtyList) {
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
// 查询题型
|
||||
if (specialtyQueryVo.getAncestors().contains(",")) {
|
||||
List<SpecialtyQueryVo> specialtyLists = examSpecialtyMapper.selectExamSpecialtyByParentId(specialtyQueryVo.getId());
|
||||
for (SpecialtyQueryVo specialtyQueryVosInfo : specialtyLists) {
|
||||
specialtyQueryVos.add(specialtyQueryVosInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
|
||||
// List<SpecialtyQueryVo> specialtyList = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
// for (SpecialtyQueryVo specialtyQueryVo : specialtyList) {
|
||||
// specialtyQueryVos.add(specialtyQueryVo);
|
||||
// // 查询题型
|
||||
// if (specialtyQueryVo.getAncestors().contains(",")) {
|
||||
// List<SpecialtyQueryVo> specialtyLists = examSpecialtyMapper.selectExamSpecialtyByParentId(specialtyQueryVo.getId());
|
||||
// for (SpecialtyQueryVo specialtyQueryVosInfo : specialtyLists) {
|
||||
// specialtyQueryVos.add(specialtyQueryVosInfo);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -940,17 +942,18 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyAll();
|
||||
} else {
|
||||
// 查询部分数据
|
||||
List<SpecialtyQueryVo> specialtyList = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
for (SpecialtyQueryVo specialtyQueryVo : specialtyList) {
|
||||
specialtyQueryVos.add(specialtyQueryVo);
|
||||
// 查询题型
|
||||
if (specialtyQueryVo.getAncestors().contains(",")) {
|
||||
List<SpecialtyQueryVo> specialtyLists = examSpecialtyMapper.selectExamSpecialtyByParentId(specialtyQueryVo.getId());
|
||||
for (SpecialtyQueryVo specialtyQueryVosInfo : specialtyLists) {
|
||||
specialtyQueryVos.add(specialtyQueryVosInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
specialtyQueryVos = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
// List<SpecialtyQueryVo> specialtyList = examSpecialtyMapper.selectExamSpecialtyByids(adminUserDO.getSpecialtyIds());
|
||||
// for (SpecialtyQueryVo specialtyQueryVo : specialtyList) {
|
||||
// specialtyQueryVos.add(specialtyQueryVo);
|
||||
// // 查询题型
|
||||
// if (specialtyQueryVo.getAncestors().contains(",")) {
|
||||
// List<SpecialtyQueryVo> specialtyLists = examSpecialtyMapper.selectExamSpecialtyByParentId(specialtyQueryVo.getId());
|
||||
// for (SpecialtyQueryVo specialtyQueryVosInfo : specialtyLists) {
|
||||
// specialtyQueryVos.add(specialtyQueryVosInfo);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,161 @@
|
||||
package pc.exam.pp.module.system.util.oauth2;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class MacUtils {
|
||||
|
||||
public static String getFirstNonLoopbackMac() {
|
||||
try {
|
||||
// 先尝试按本机 InetAddress 对应的网卡
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
NetworkInterface ni = NetworkInterface.getByInetAddress(localHost);
|
||||
if (ni != null) {
|
||||
byte[] mac = ni.getHardwareAddress();
|
||||
if (mac != null && mac.length > 0) {
|
||||
return formatMac(mac);
|
||||
}
|
||||
}
|
||||
|
||||
// 否则遍历所有网卡,返回第一个符合条件的
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
for (NetworkInterface netIf : Collections.list(interfaces)) {
|
||||
try {
|
||||
if (netIf == null) continue;
|
||||
if (netIf.isLoopback() || netIf.isVirtual() || !netIf.isUp()) continue;
|
||||
byte[] mac = netIf.getHardwareAddress();
|
||||
if (mac != null && mac.length > 0) {
|
||||
return formatMac(mac);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// 忽略单个网卡异常,继续下一个
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 可选:记录日志
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有网卡的 MAC 地址映射:网卡名 -> MAC 字符串(若无 MAC 则不包含该网卡)。
|
||||
*/
|
||||
public static Map<String, String> getAllMacs() {
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
for (NetworkInterface netIf : Collections.list(interfaces)) {
|
||||
try {
|
||||
if (netIf == null) continue;
|
||||
byte[] mac = netIf.getHardwareAddress();
|
||||
if (mac != null && mac.length > 0) {
|
||||
result.put(netIf.getName(), formatMac(mac));
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取最可能的物理(全局唯一)MAC 地址,格式 AA:BB:CC:DD:EE:FF
|
||||
* 返回 Optional.empty() 表示未能找到。
|
||||
*/
|
||||
public static String getPhysicalMac() {
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
if (interfaces == null) return "";
|
||||
|
||||
List<NetworkInterface> list = Collections.list(interfaces);
|
||||
|
||||
// 排序:把更有可能的真实物理网卡放到前面(优先有IPv4地址且不是虚拟)
|
||||
list.sort(Comparator.comparingInt(MacUtils::scoreInterface).reversed());
|
||||
|
||||
String fallback = null;
|
||||
|
||||
for (NetworkInterface ni : list) {
|
||||
try {
|
||||
if (ni == null) continue;
|
||||
|
||||
// 基本过滤
|
||||
if (ni.isLoopback()) continue;
|
||||
if (!ni.isUp()) continue;
|
||||
if (ni.isVirtual()) continue;
|
||||
if (ni.isPointToPoint()) continue;
|
||||
|
||||
String name = ni.getName() == null ? "" : ni.getName().toLowerCase();
|
||||
String display = ni.getDisplayName() == null ? "" : ni.getDisplayName().toLowerCase();
|
||||
|
||||
// 跳过常见虚拟或容器接口
|
||||
if (name.startsWith("veth") || name.startsWith("vmnet") || name.startsWith("docker")
|
||||
|| name.startsWith("br-") || name.startsWith("virbr") || name.startsWith("vbox")
|
||||
|| name.startsWith("tun") || name.startsWith("tap")
|
||||
|| name.startsWith("lo") || name.contains("virtual") || display.contains("virtual")
|
||||
|| (name.startsWith("wlx") && name.contains("virtual"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] mac = ni.getHardwareAddress();
|
||||
if (mac == null || mac.length != 6) continue;
|
||||
|
||||
String macStr = formatMac(mac);
|
||||
|
||||
// 检查是否全局唯一 MAC(locally-administered bit == 0)
|
||||
boolean locallyAdministered = (mac[0] & 0x02) != 0;
|
||||
boolean multicast = (mac[0] & 0x01) != 0;
|
||||
|
||||
if (multicast) continue;
|
||||
|
||||
if (!locallyAdministered) {
|
||||
// 厂商分配的全局唯一 MAC
|
||||
return macStr;
|
||||
} else if (fallback == null) {
|
||||
fallback = macStr;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// 若未找到全局唯一 MAC,则返回第一个符合条件的
|
||||
return fallback != null ? fallback : "";
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据接口是否有 IP、是否有名字等打分,便于把好接口排前面
|
||||
*/
|
||||
private static int scoreInterface(NetworkInterface ni) {
|
||||
int score = 0;
|
||||
try {
|
||||
if (ni == null) return score;
|
||||
if (ni.getHardwareAddress() != null) score += 10;
|
||||
if (!ni.isVirtual()) score += 5;
|
||||
if (ni.getInterfaceAddresses() != null && !ni.getInterfaceAddresses().isEmpty()) score += 3;
|
||||
String name = ni.getName() == null ? "" : ni.getName().toLowerCase();
|
||||
if (name.startsWith("eth") || name.startsWith("en") || name.startsWith("wlan") || name.startsWith("wl")) score += 2;
|
||||
} catch (Exception ignore) {}
|
||||
return score;
|
||||
}
|
||||
/**
|
||||
* 把 byte[] mac 格式化为 "AA-BB-CC-DD-EE-FF"
|
||||
*/
|
||||
private static String formatMac(byte[] mac) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
sb.append(String.format("%02X", mac[i]));
|
||||
if (i < mac.length - 1) sb.append("-");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
public static String normalizeMac(String mac) {
|
||||
return mac == null ? "" : mac.replaceAll("[-:]", "").toUpperCase();
|
||||
}
|
||||
}
|
@@ -20,5 +20,16 @@
|
||||
LEFT JOIN exam_class ec ON ec.id = su.class_id
|
||||
WHERE stc.user_id = #{id}
|
||||
</select>
|
||||
<select id="selectOneById" resultType="java.lang.String">
|
||||
select username
|
||||
from system_users
|
||||
where id =#{id}
|
||||
|
||||
</select>
|
||||
<update id="updateByIdToPassword">
|
||||
UPDATE system_users
|
||||
SET password = #{password}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
@@ -0,0 +1,49 @@
|
||||
package pc.exam.pp.server.config;
|
||||
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import pc.exam.pp.module.system.util.oauth2.MacUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MacValidator {
|
||||
|
||||
private final SystemMacProperties macProperties;
|
||||
|
||||
public MacValidator(SystemMacProperties macProperties) {
|
||||
this.macProperties = macProperties;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void validateMac() {
|
||||
try {
|
||||
String localMac = String.valueOf(MacUtils.getPhysicalMac());
|
||||
if (localMac == null || localMac.isEmpty()) {
|
||||
throw new IllegalStateException("无法获取本机 MAC 地址!");
|
||||
}
|
||||
|
||||
String allowed = macProperties.getAllowedMac();
|
||||
if (allowed == null || allowed.isEmpty()) {
|
||||
throw new IllegalStateException("系统未配置允许的 MAC 地址!");
|
||||
}
|
||||
|
||||
boolean match = normalize(allowed).equals(normalize(localMac));
|
||||
if (!match) {
|
||||
throw new IllegalStateException("该机器 MAC 地址未授权!本机:" + localMac);
|
||||
}
|
||||
|
||||
log.info("✅ MAC 验证通过,本机 MAC: {}", localMac);
|
||||
} catch (Exception e) {
|
||||
log.error("❌ MAC 验证失败: {}", e.getMessage());
|
||||
System.exit(1); // 阻止启动
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String mac) {
|
||||
return mac == null ? "" : mac.replaceAll("[-:]", "").toUpperCase();
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package pc.exam.pp.server.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "system") // 对应 application.yml 中的 system: 节点
|
||||
public class SystemMacProperties {
|
||||
|
||||
/**
|
||||
* 允许的 MAC 地址列表
|
||||
*/
|
||||
private String allowedMac;
|
||||
}
|
@@ -73,7 +73,7 @@ spring:
|
||||
redis:
|
||||
host: 115.120.213.238 # 地址
|
||||
port: 6379 # 端口
|
||||
database: 0 # 数据库索引
|
||||
database: 1 # 数据库索引
|
||||
password: sadjklasnfasd # 密码,建议生产环境开启
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
@@ -263,3 +263,5 @@ justauth:
|
||||
pf4j:
|
||||
# pluginsDir: /tmp/
|
||||
pluginsDir: ../plugins
|
||||
system:
|
||||
allowed-mac: E4-54-E8-25-F6-14
|
||||
|
Reference in New Issue
Block a user