Compare commits

...

4 Commits

Author SHA1 Message Date
huababa1
24210dd1b7 【修改】表格修改项 2025-10-18 15:28:35 +08:00
DESKTOP-9ERGOBP\任维炳
a7fd185889 【新增】 添加删除用户所有任务,添加查询已经存在ws列表 2025-10-13 23:39:44 +08:00
hyc
3eb97cb736 Merge pull request '【修改】文字考点,' (#6) from hyc into master
Reviewed-on: #6
2025-10-13 19:08:26 +08:00
hyc
6f7832d65e Merge pull request '【修改】文字考点,' (#7) from hyc into master
Reviewed-on: #7
2025-10-12 19:15:07 +08:00
44 changed files with 972 additions and 99 deletions

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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]")

View File

@@ -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("");
}

View File

@@ -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;
}

View File

@@ -46,6 +46,8 @@ public class EducationPaperTask extends TenantBaseDO
private String taskType;
private String isOne;
/** 是否共享 */
private Integer share;
/** 是否为模板 */
//@Excel(name = "是否为模板")

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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"));

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);
//构建试卷

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -119,5 +119,7 @@ public interface IEducationPaperTaskService
void checkType(PaperQueUpdateDTO dto);
PageResult<EducationPaperTask> selectEducationPaperTaskListlistMoBan(PaperTaskPageVo educationPaperTask);
}

View File

@@ -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}

View File

@@ -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>

View File

@@ -73,7 +73,6 @@
where stu_id =#{stuId}
and task_id = #{taskId}
and deleted = '0'
and exam_status = '0'
</select>

View File

@@ -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">

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)){

View File

@@ -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/字符宽,可根据字体调整

View File

@@ -1686,7 +1686,7 @@ public class SectionPage {
}
// 横向匹配
if (Math.abs(width - sh) <= tol && Math.abs(height - sw) <= tol) {
return entry.getKey() + " (横向)";
return entry.getKey();
}
}

View File

@@ -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) {

View File

@@ -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("密码重置成功!");
}
}

View File

@@ -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; // 新密码
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
// }
// }
// }
}
}
}

View File

@@ -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);
// 检查是否全局唯一 MAClocally-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();
}
}

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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