diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WordController.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WordController.java new file mode 100644 index 00000000..753545d2 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WordController.java @@ -0,0 +1,84 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import pc.exam.pp.framework.common.enums.CommonStatusEnum; +import pc.exam.pp.framework.common.pojo.CommonResult; +import pc.exam.pp.framework.common.util.object.BeanUtils; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordRespVO; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSimpleRespVO; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.service.wps_word.WpsWordLinkService; +import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptRespVO; +import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import pc.exam.pp.module.system.dal.dataobject.dept.DeptDO; + +import java.util.List; + +import static pc.exam.pp.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - wps_word") +@RestController +@RequestMapping("/wps/word") +@Validated +public class WordController { + + @Resource + private WpsWordLinkService wpsWordLinkService; + + @PostMapping("create") + @Operation(summary = "创建wps_word") + public CommonResult createWord(@Valid @RequestBody WordSaveReqVO createReqVO) { + Long wordId = wpsWordLinkService.createWord(createReqVO); + return success(wordId); + } + + @PutMapping("update") + @Operation(summary = "更新wps_word") + public CommonResult updateWord(@Valid @RequestBody WordSaveReqVO updateReqVO) { + wpsWordLinkService.updateWord(updateReqVO); + return success(true); + } + + @DeleteMapping("delete") + @Operation(summary = "删除wps_word") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult deleteWord(@RequestParam("id") Long id) { + wpsWordLinkService.deleteWord(id); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获取wps_word列表") + public CommonResult> getWordList(WordListReqVO reqVO) { + List list = wpsWordLinkService.getWordList(reqVO); + return success(BeanUtils.toBean(list, WordRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取wps_word精简信息列表", description = "只包含被开启的wps_word,主要用于前端的下拉选项") + public CommonResult> getSimpleWordList() { + List list = wpsWordLinkService.getWordList( + new WordListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + return success(BeanUtils.toBean(list, WordSimpleRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得wps_word信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getDept(@RequestParam("id") Long id) { + WpsWordLinkDO word = wpsWordLinkService.getWord(id); + return success(BeanUtils.toBean(word, WordRespVO.class)); + } + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WpsWordController.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WpsWordController.java new file mode 100644 index 00000000..0596ccbc --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/WpsWordController.java @@ -0,0 +1,40 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord; + +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import pc.exam.pp.framework.common.pojo.CommonResult; +import pc.exam.pp.module.judgement.service.wps_word.JudgementWpsWordService; +import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO; + +import java.io.IOException; +import java.util.List; + +/** + * wps word + * rwb + */ + +@RestController +@RequestMapping("/tool/wps_word") +@Tag( name = "WPSWORD") +@Validated +public class WpsWordController { + + @Autowired + private JudgementWpsWordService judgementWpsWordService; + + /** + * wps word + * @return 判分 + */ + @GetMapping("/run_wps_word") + public CommonResult> run_wps_word() throws Exception { + return CommonResult.success(judgementWpsWordService.ProgrammingWpsWord("1")); + } + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordListReqVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordListReqVO.java new file mode 100644 index 00000000..a814119d --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordListReqVO.java @@ -0,0 +1,21 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - WpsWord对应关系 Request VO") +@Data +public class WordListReqVO { + + @Schema(description = "节点名称模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + /** + * 类型 + */ + private Integer type; + + private Integer belongTo; +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordRespVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordRespVO.java new file mode 100644 index 00000000..98f9ccbf --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordRespVO.java @@ -0,0 +1,40 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 节点信息 Response VO") +@Data +public class WordRespVO { + + @Schema(description = "节点编号", example = "1024") + private Long id; + + @Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父节点 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer sort; + + @Schema(description = "节点方法") + private String nodeFunction; + + @Schema(description = "转中文") + private String toChinese; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + /** + * 类型 + */ + private Integer type; + private Integer belongTo; +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSaveReqVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSaveReqVO.java new file mode 100644 index 00000000..bfd9cb33 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSaveReqVO.java @@ -0,0 +1,47 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import pc.exam.pp.framework.common.enums.CommonStatusEnum; +import pc.exam.pp.framework.common.validation.InEnum; + +@Schema(description = "管理后台 - 节点创建/修改 Request VO") +@Data +public class WordSaveReqVO { + + @Schema(description = "节点编号", example = "1024") + private Long id; + + @Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "节点名称不能为空") + @Size(max = 30, message = "节点名称长度不能超过 30 个字符") + private String name; + /** + * 类型 + */ + private Integer type; + private Integer belongTo; + + @Schema(description = "父节点 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "节点方法") + private String nodeFunction; + + @Schema(description = "转中文") + private String toChinese; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSimpleRespVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSimpleRespVO.java new file mode 100644 index 00000000..18dd0ef4 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/WpsWord/vo/WordSimpleRespVO.java @@ -0,0 +1,27 @@ +package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 节点精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WordSimpleRespVO { + + @Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + /** + * 类型 + */ + private Integer type; + private Integer belongTo; +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/dataobject/wpsword/WpsWordLinkDO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/dataobject/wpsword/WpsWordLinkDO.java new file mode 100644 index 00000000..51bedb50 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/dataobject/wpsword/WpsWordLinkDO.java @@ -0,0 +1,67 @@ +package pc.exam.pp.module.judgement.dal.dataobject.wpsword; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import pc.exam.pp.framework.common.enums.CommonStatusEnum; +import pc.exam.pp.framework.tenant.core.db.TenantBaseDO; +import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO; + +import java.util.ArrayList; +import java.util.List; + +/** + * wps word关系对应表 + * + */ +@TableName("wps_word_link") +@Data +@EqualsAndHashCode(callSuper = true) +public class WpsWordLinkDO extends TenantBaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 部门ID + */ + @TableId + private Long id; + /** + * 部门名称 + */ + private String name; + /** + * 父部门ID + * + * 关联 {@link #id} + */ + private Long parentId; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 节点功能 + */ + private String nodeFunction; + /** + * 中文描述 + */ + private String toChinese; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 类型 + */ + private Integer type; + private String belongTo; + + @TableField(exist = false) + private List children = new ArrayList<>(); +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/mysql/wpsword/WpsWordLinkMapper.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/mysql/wpsword/WpsWordLinkMapper.java new file mode 100644 index 00000000..3115bf09 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/dal/mysql/wpsword/WpsWordLinkMapper.java @@ -0,0 +1,37 @@ +package pc.exam.pp.module.judgement.dal.mysql.wpsword; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX; +import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface WpsWordLinkMapper extends BaseMapperX { + + default List selectList(WordListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(WpsWordLinkDO::getName, reqVO.getName()) + .eqIfPresent(WpsWordLinkDO::getStatus, reqVO.getStatus())); + } + + default WpsWordLinkDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(WpsWordLinkDO::getParentId, parentId, WpsWordLinkDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(WpsWordLinkDO::getParentId, parentId); + } + + default List selectListByParentId(Collection parentIds) { + return selectList(WpsWordLinkDO::getParentId, parentIds); + } + + List selectTreeListByNodeFunction(); + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordService.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordService.java new file mode 100644 index 00000000..318e57e7 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordService.java @@ -0,0 +1,23 @@ +package pc.exam.pp.module.judgement.service.wps_word; + + + +import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO; + +import java.util.List; + +/** + * 判分逻辑集合(wps word) + * + * @author rwb + */ +public interface JudgementWpsWordService { + + /** + * 获取word文件内得考点及描述 + * @param path minio文件路径 + * @return 文件内得考点及描述 + * @throws Exception 异常 + */ + public List ProgrammingWpsWord(String path) throws Exception; +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordServiceImpl.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordServiceImpl.java new file mode 100644 index 00000000..6175f1ca --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/JudgementWpsWordServiceImpl.java @@ -0,0 +1,50 @@ +package pc.exam.pp.module.judgement.service.wps_word; + + + +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import pc.exam.pp.module.infra.dal.dataobject.config.ConfigDO; +import pc.exam.pp.module.infra.service.config.ConfigService; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper; +import pc.exam.pp.module.judgement.service.auto_tools.AutoToolsService; +import pc.exam.pp.module.judgement.utils.wps_word.WpsWordUtils; +import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO; + +import java.io.File; +import java.util.List; + +@Service +public class JudgementWpsWordServiceImpl implements JudgementWpsWordService { + + @Resource + WpsWordLinkMapper wpsWordLinkMapper; + + @Resource + AutoToolsService autoToolsService; + + @Resource + ConfigService configService; + + @Override + public List ProgrammingWpsWord(String path) throws Exception { + // 1、获取文件临时下载路径 + ConfigDO config = configService.getConfigByKey("file_down_path"); + // 2、下载文件并返回文件完整路径 + String pathName = autoToolsService.downloadStudentFile(path, config.getValue()); + // 3、创建word考点tree + WordListReqVO wordListReqVO = new WordListReqVO(); + wordListReqVO.setBelongTo(0); + List list = wpsWordLinkMapper.selectList(wordListReqVO); + // 4、docx文件读取并返回考点及说明信息 + List margins1 = WpsWordUtils.wps_word(pathName, list); + // 5、已经读取完得考点删除源文件 + File file = new File(pathName); + file.delete(); + return margins1; + } + + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkService.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkService.java new file mode 100644 index 00000000..6c1f9307 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkService.java @@ -0,0 +1,112 @@ +package pc.exam.pp.module.judgement.service.wps_word; + +import pc.exam.pp.framework.common.util.collection.CollectionUtils; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO; + +import java.util.*; + +/** + * 节点 Service 接口 + * + * @author 芋道源码 + */ +public interface WpsWordLinkService { + + /** + * 创建节点 + * + * @param createReqVO 节点信息 + * @return 节点编号 + */ + Long createWord(WordSaveReqVO createReqVO); + + /** + * 更新节点 + * + * @param updateReqVO 节点信息 + */ + void updateWord(WordSaveReqVO updateReqVO); + + /** + * 删除节点 + * + * @param id 节点编号 + */ + void deleteWord(Long id); + + /** + * 获得节点信息 + * + * @param id 节点编号 + * @return 节点信息 + */ + WpsWordLinkDO getWord(Long id); + + /** + * 获得节点信息数组 + * + * @param ids 节点编号数组 + * @return 节点信息数组 + */ + List getWordList(Collection ids); + + /** + * 筛选节点列表 + * + * @param reqVO 筛选条件请求 VO + * @return 节点列表 + */ + List getWordList(WordListReqVO reqVO); + + /** + * 获得指定编号的节点 Map + * + * @param ids 节点编号数组 + * @return 节点 Map + */ + default Map getWordMap(Collection ids) { + List list = getWordList(ids); + return CollectionUtils.convertMap(list, WpsWordLinkDO::getId); + } + + /** + * 获得指定节点的所有子节点 + * + * @param id 节点编号 + * @return 子节点列表 + */ + default List getChildWordList(Long id) { + return getChildWordList(Collections.singleton(id)); + } + + /** + * 获得指定节点的所有子节点 + * + * @param ids 节点编号数组 + * @return 子节点列表 + */ + List getChildWordList(Collection ids); + + /** + * 获得所有子节点,从缓存中 + * + * @param id 父节点编号 + * @return 子节点列表 + */ + Set getChildWordIdListFromCache(Long id); + + /** + * 校验节点们是否有效。如下情况,视为无效: + * 1. 节点编号不存在 + * 2. 节点被禁用 + * + * @param ids 角色编号数组 + */ + void validateWordList(Collection ids); + + List getWordTreeList(); + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkServiceImpl.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkServiceImpl.java new file mode 100644 index 00000000..a52f3a53 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/wps_word/WpsWordLinkServiceImpl.java @@ -0,0 +1,225 @@ +package pc.exam.pp.module.judgement.service.wps_word; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import pc.exam.pp.framework.common.enums.CommonStatusEnum; +import pc.exam.pp.framework.common.util.object.BeanUtils; +import pc.exam.pp.framework.datapermission.core.annotation.DataPermission; +import pc.exam.pp.framework.tenant.core.aop.TenantIgnore; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO; +import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper; +import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO; +import pc.exam.pp.module.system.dal.redis.RedisKeyConstants; + +import java.util.*; + +import static pc.exam.pp.framework.common.exception.util.ServiceExceptionUtil.exception; +import static pc.exam.pp.framework.common.util.collection.CollectionUtils.convertSet; +import static pc.exam.pp.module.system.enums.ErrorCodeConstants.*; + +/** + * 节点 Service 实现类 + * + */ +@Service +@Validated +@Slf4j +public class WpsWordLinkServiceImpl implements WpsWordLinkService { + + @Resource + private WpsWordLinkMapper wpsWordLinkMapper; + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存 + public Long createWord(WordSaveReqVO createReqVO) { + if (createReqVO.getParentId() == null) { + createReqVO.setParentId(WpsWordLinkDO.PARENT_ID_ROOT); + } + // 校验父节点的有效性 + validateParentWord(null, createReqVO.getParentId()); + // 校验节点名的唯一性 + validateWordNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入节点 + WpsWordLinkDO wpsWordLinkDO = BeanUtils.toBean(createReqVO, WpsWordLinkDO.class); + wpsWordLinkMapper.insert(wpsWordLinkDO); + return wpsWordLinkDO.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存 + public void updateWord(WordSaveReqVO updateReqVO) { + if (updateReqVO.getParentId() == null) { + updateReqVO.setParentId(WpsWordLinkDO.PARENT_ID_ROOT); + } + // 校验自己存在 + validateWordExists(updateReqVO.getId()); + // 校验父节点的有效性 + validateParentWord(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验节点名的唯一性 + validateWordNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新节点 + WpsWordLinkDO updateObj = BeanUtils.toBean(updateReqVO, WpsWordLinkDO.class); + wpsWordLinkMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存 + public void deleteWord(Long id) { + // 校验是否存在 + validateWordExists(id); + // 校验是否有子节点 + if (wpsWordLinkMapper.selectCountByParentId(id) > 0) { + throw exception(WORD_NOT_FOUND); + } + // 删除节点 + wpsWordLinkMapper.deleteById(id); + } + + @VisibleForTesting + void validateWordExists(Long id) { + if (id == null) { + return; + } + WpsWordLinkDO wpsWordLinkDO = wpsWordLinkMapper.selectById(id); + if (wpsWordLinkDO == null) { + throw exception(WORD_NOT_FOUND); + } + } + + @VisibleForTesting + void validateParentWord(Long id, Long parentId) { + if (parentId == null || WpsWordLinkDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父节点 + if (Objects.equals(id, parentId)) { + throw exception(DEPT_PARENT_ERROR); + } + // 2. 父节点不存在 + WpsWordLinkDO parentWord = wpsWordLinkMapper.selectById(parentId); + if (parentWord == null) { + throw exception(WORD_PARENT_NOT_EXITS); + } + // 3. 递归校验父节点,如果父节点是自己的子节点,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentWord.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(WORD_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父节点 + if (parentId == null || WpsWordLinkDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentWord = wpsWordLinkMapper.selectById(parentId); + if (parentWord == null) { + break; + } + } + } + + @VisibleForTesting + void validateWordNameUnique(Long id, Long parentId, String name) { + WpsWordLinkDO wpsWordLinkDO = wpsWordLinkMapper.selectByParentIdAndName(parentId, name); + if (wpsWordLinkDO == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的节点 + if (id == null) { + throw exception(WORD_NAME_DUPLICATE); + } + if (ObjectUtil.notEqual(wpsWordLinkDO.getId(), id)) { + throw exception(WORD_NAME_DUPLICATE); + } + } + + @Override + public WpsWordLinkDO getWord(Long id) { + return wpsWordLinkMapper.selectById(id); + } + + @Override + public List getWordList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return wpsWordLinkMapper.selectBatchIds(ids); + } + + @Override + public List getWordList(WordListReqVO reqVO) { + List list = wpsWordLinkMapper.selectList(reqVO); + list.sort(Comparator.comparing(WpsWordLinkDO::getSort)); + return list; + } + + @Override + public List getChildWordList(Collection ids) { + List children = new LinkedList<>(); + // 遍历每一层 + Collection parentIds = ids; + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子节点 + List words = wpsWordLinkMapper.selectListByParentId(parentIds); + // 1. 如果没有子节点,则结束遍历 + if (CollUtil.isEmpty(words)) { + break; + } + // 2. 如果有子节点,继续遍历 + children.addAll(words); + parentIds = convertSet(words, WpsWordLinkDO::getId); + } + return children; + } + + @Override + @DataPermission(enable = false) // 禁用数据权限,避免建立不正确的缓存 + @Cacheable(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST, key = "#id") + public Set getChildWordIdListFromCache(Long id) { + List children = getChildWordList(id); + return convertSet(children, WpsWordLinkDO::getId); + } + + @Override + public void validateWordList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得科室信息 + Map wordMap = getWordMap(ids); + // 校验 + ids.forEach(id -> { + WpsWordLinkDO word = wordMap.get(id); + if (word == null) { + throw exception(WORD_NOT_FOUND); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(word.getStatus())) { + throw exception(WORD_NOT_ENABLE, word.getName()); + } + }); + } + + @Override + @TenantIgnore + public List getWordTreeList() { + return wpsWordLinkMapper.selectTreeListByNodeFunction(); + } + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/count/TwipsToCmUtils.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/count/TwipsToCmUtils.java new file mode 100644 index 00000000..c8e15d6c --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/count/TwipsToCmUtils.java @@ -0,0 +1,21 @@ +package pc.exam.pp.module.judgement.utils.count; + +// 工具方法:twips 转厘米 +public class TwipsToCmUtils { + + // 工具方法:twips 转厘米(保留两位小数) + public static double convertTwipsToCm(String twipsStr) { + if (twipsStr == null || twipsStr.isEmpty()) { + return 0.0; + } + try { + int twips = Integer.parseInt(twipsStr); + double cm = twips * 2.54 / 1440; + // 四舍五入保留两位小数 + return Math.round(cm * 100.0) / 100.0; + } catch (NumberFormatException e) { + return 0.0; // 解析失败返回0 + } + } + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/TreeUtils.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/TreeUtils.java new file mode 100644 index 00000000..016e1bb0 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/TreeUtils.java @@ -0,0 +1,35 @@ +package pc.exam.pp.module.judgement.utils.tree; + +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TreeUtils { + + public static List buildTree(List flatList) { + Map nodeMap = new HashMap<>(); + List roots = new ArrayList<>(); + + // 先放入 map + for (WpsWordLinkDO node : flatList) { + nodeMap.put(Math.toIntExact(node.getId()), node); + } + + // 构建树关系 + for (WpsWordLinkDO node : flatList) { + if (node.getParentId() == 0) { + roots.add(node); + } else { + WpsWordLinkDO parent = nodeMap.get(node.getParentId().intValue()); + if (parent != null) { + parent.getChildren().add(node); + } + } + } + return roots; + } + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/vo/TreeVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/vo/TreeVO.java new file mode 100644 index 00000000..ba41d751 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/tree/vo/TreeVO.java @@ -0,0 +1,31 @@ +package pc.exam.pp.module.judgement.utils.tree.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; +import org.apache.ibatis.type.JdbcType; +import pc.exam.pp.framework.tenant.core.db.TenantBaseDO; + +import java.util.ArrayList; +import java.util.List; + + +@Data +public class TreeVO extends TenantBaseDO { + + private int id; + private int parentId; + private String name; + private String nodeFunction; + private String toChinese; + private int type; + private List children = new ArrayList<>(); + + public TreeVO(int id, int parentId, String name, String nodeFunction, String toChinese, int type) { + this.id = id; + this.parentId = parentId; + this.name = name; + this.nodeFunction = nodeFunction; + this.toChinese = toChinese; + this.type = type; + } +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/WpsWordUtils.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/WpsWordUtils.java new file mode 100644 index 00000000..fd01e2b8 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/WpsWordUtils.java @@ -0,0 +1,282 @@ +package pc.exam.pp.module.judgement.utils.wps_word; + +import jakarta.annotation.Resource; +import org.apache.poi.xwpf.usermodel.*; +import org.apache.xmlbeans.XmlCursor; +import org.apache.xmlbeans.XmlObject; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; +import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO; +import pc.exam.pp.module.judgement.utils.tree.TreeUtils; +import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO; +import java.io.FileInputStream; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.IntStream; + +public class WpsWordUtils { + /** + * 获取文档段落W:P标签得数量,判断出一个有多少段 + */ + public static List wps_word(String filePath, List wpsWordLinkDOS) throws Exception { + List wordVO = new ArrayList<>(); + int count = 0; + // 路径初始化 + String xmlpath = ""; + XWPFDocument document = new XWPFDocument(new FileInputStream(filePath)); + String xmlString = XmlUtil.getDocumentXml(document); + // 获取CTDocument对象 + XmlObject docXml = document.getDocument(); + List tree = TreeUtils.buildTree(wpsWordLinkDOS); // flatList 是你贴出的 JSON 解析出来的 + XmlObject xmlObject = document.getDocument(); // Word XML document + // 创建一个list,存放word读取的数据 + for (WpsWordLinkDO wpsWordLinkDO : tree) { + // 段落划分 根据w:p标签 + // 到达参数节点,构造 XPath 路径查询它的值 + String xpath = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' "; + xpath += "//"+wpsWordLinkDO.getName(); + XmlCursor cursor = docXml.newCursor(); + int index = 0; + cursor.selectPath(xpath); + String xpathName = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' "; + while (cursor.toNextSelection()) { + // 每一段进行赋值,进行判断 + XmlObject paraObj = cursor.getObject(); + String paraText = paraObj.xmlText(); +// System.out.println(paraText); +// System.out.println(cursor.getTextValue()); + index += 1; + for (WpsWordLinkDO root : wpsWordLinkDO.getChildren()) { + traverseTreeAndQueryXml(wordVO, wpsWordLinkDO.getName(), cursor.getTextValue(), xpathName, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1); + } + } + } + // 读取页眉的方法(需要通过页眉查询,水印,页眉文字等信息) + List headers = document.getHeaderList(); + for (XWPFHeader header : headers) { + if (!Objects.equals(header.getText(), "")) { + headerAndFooter(header, null, wordVO); + } + // 获取底层 XML 对象 + CTHdrFtr ctHdrFtr = header._getHdrFtr(); // ✅ 正确方法 + String xpath = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' "; + xpath += "//w:hdr/w:p/w:r/w:pict"; + XmlCursor cursor = ctHdrFtr.newCursor(); + cursor.selectPath(xpath); + while (cursor.toNextSelection()) { + // 查询 v:textpath 节点 + cursor.selectPath( + "declare namespace v='urn:schemas-microsoft-com:vml' " + + ".//v:textpath" + ); + while (cursor.toNextSelection()) { + XmlObject textpathObj = cursor.getObject(); + String xml = textpathObj.xmlText(); + WordVO attr_word = new WordVO(); + + // 提取属性值 + String stringAttr = cursor.getAttributeText(new javax.xml.namespace.QName("string")); + String styleAttr = cursor.getAttributeText(new javax.xml.namespace.QName("style")); + attr_word.setWordText("水印"); + List attr = new ArrayList<>(); + attr.add("水印文字 string 属性: " + stringAttr); + attr.add("水印 style 属性: " + styleAttr); + attr_word.setKeynoteChinese(attr); + List path = new ArrayList<>(); + path.add("name:"+stringAttr); + path.add("style:"+styleAttr); + attr_word.setExamKeynote(path); + wordVO.add(attr_word); + } + } + cursor.close(); + } + // 获取页脚 + List footers = document.getFooterList(); + for (XWPFFooter footer : footers) { + if (!Objects.equals(footer.getText(), "")) { + headerAndFooter(null, footer, wordVO); + } + } + // 邮件合并 + List email = getMailMergeFields(document); + if (!email.isEmpty()) { + // 使用了邮件合并功能 + WordVO email_word = new WordVO(); + email_word.setWordText("邮件合并"); + email_word.setExamKeynote(email); + email_word.setKeynoteChinese(email); + wordVO.add(email_word); + } + return wordVO; + } + // 页眉页脚 + public static void headerAndFooter(XWPFHeader header, XWPFFooter footer, List wordVO) { + if (header != null) { + for (XWPFParagraph para : header.getParagraphs()) { + for (XWPFRun run : para.getRuns()) { + String text = run.getText(0); + if (text != null) { + WordVO wordVO1 = new WordVO(); + wordVO1.setWordText("页眉:" + text); + List style_list = new ArrayList<>(); + style_list.add("字体: " + run.getFontFamily()); + style_list.add("字号: " + run.getFontSize()); + style_list.add("颜色: " + run.getColor()); + style_list.add("加粗: " + run.isBold()); + style_list.add("斜体: " + run.isItalic()); + wordVO1.setKeynoteChinese(style_list); + wordVO.add(wordVO1); + } + } + } + } + if (footer != null) { + for (XWPFParagraph para : footer.getParagraphs()) { + for (XWPFRun run : para.getRuns()) { + String text = run.getText(0); + if (text != null) { + WordVO wordVO1 = new WordVO(); + wordVO1.setWordText("页脚:" + text); + List style_list = new ArrayList<>(); + style_list.add("字体: " + run.getFontFamily()); + style_list.add("字号: " + run.getFontSize()); + style_list.add("颜色: " + run.getColor()); + style_list.add("加粗: " + run.isBold()); + style_list.add("斜体: " + run.isItalic()); + wordVO1.setKeynoteChinese(style_list); + wordVO.add(wordVO1); + } + } + } + } + + } + public static void traverseTreeAndQueryXml(List wordVOs, String firstTitle, String text, String xpath, WpsWordLinkDO node, XmlObject currentXml, List pathSoFar, List pathChinese, int index, int beginIndex) { + // 到达参数节点,构造 XPath 路径查询它的值 + if (beginIndex == 1) { + xpath += "//" + firstTitle + "[" + index + "]/"; + } + pathSoFar.add(node.getName()); + pathChinese.add(node.getToChinese() + index); + + if (node.getType() == 1) { +// pathSoFar.remove(0); + xpath += String.join("/", pathSoFar); +// System.out.println(xpath); + try (XmlCursor cursors = currentXml.newCursor()) { +// System.out.println(xpath); + cursors.selectPath(xpath); + if (cursors.toNextSelection()) { +// System.out.println(cursors.xmlText()); +// cursors.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' //@w:firstLine"); +// if (cursors.toNextSelection()) { +// String texts = cursors.getTextValue(); +// System.out.println("值:" + texts); +// } + + String text_value = cursors.getTextValue(); + if (!Objects.equals(text_value, "")) { + // 查找List里面是否已经存在相应文本的数据 + String finalText = text; + int list_index = IntStream.range(0, wordVOs.size()) + .filter(i -> finalText.equals(wordVOs.get(i).getWordText())) + .findFirst() + .orElse(-1); + // 判断在段落内的样式,如果出现样式,向上兼容,直接再出现样式标签 +// System.out.println(xpath); + if (xpath.indexOf("w:sectPr") > 0 && xpath.indexOf("w:p[") > 0) { + // 说明出现了文本页面设置,需要进行向上绑定 + // 在获取当前的数组长度,获取上面的属性 遍历已经存在的数据 + int tindex = 0; + for (WordVO woVo : wordVOs) { + // 判断标识是否为false,,代表没有进行赋值 + if (!woVo.getIsTrue()) { + WordVO wordVO = wordVOs.get(tindex); + wordVO.setWordText(wordVO.getWordText()); + woVo.setIsTrue(true); + List kchinese = woVo.getKeynoteChinese(); + List examKeynote = woVo.getExamKeynote(); + examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value); + kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value); + wordVO.setKeynoteChinese(kchinese); + wordVO.setExamKeynote(examKeynote); + wordVOs.set(tindex, woVo); + } + tindex += 1; + } + } else if (list_index < 0) { // 如果没有查询到了 + if (xpath.indexOf("w:sectPr[") > 0) { + // 页面属性 + // 文本 + text = "页面属性"; + } + if (!Objects.equals(text, "")) { + if (!text.contains("MERGEFIELD")) { + // 给标志符 + WordVO wordVO = new WordVO(); + wordVO.setWordText(text); + // 创建list进行存放数据 + List kchinese = new ArrayList<>(); + List examKeynote = new ArrayList<>(); + examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value); + + kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value); + // 组合完数据后进行存放数据 + wordVO.setKeynoteChinese(kchinese); + wordVO.setExamKeynote(examKeynote); + wordVO.setIsTrue(false); + wordVOs.add(wordVO); + } + } + } else { // 如果找到了 + WordVO wordVO = wordVOs.get(list_index); + List kchinese = wordVO.getKeynoteChinese(); + List examKeynote = wordVO.getExamKeynote(); + examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value); + kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value); + wordVO.setKeynoteChinese(kchinese); + wordVO.setExamKeynote(examKeynote); + wordVO.setIsTrue(false); + wordVOs.remove(list_index); + wordVOs.add(wordVO); + } +// System.out.println("文本:" + text + " 参数路径:" + String.join(" → ", pathChinese) + ",值:" + text_value); + } + } + } + } else { + for (WpsWordLinkDO child : node.getChildren()) { + traverseTreeAndQueryXml(wordVOs, firstTitle, text, xpath, child, currentXml, new ArrayList<>(pathSoFar), new ArrayList<>(pathChinese), index,2); + } + } + pathSoFar.remove(pathSoFar.size() - 1); + pathChinese.remove(pathChinese.size() - 1); + } + + /** + * 使用邮件合并 + */ + public static List getMailMergeFields(XWPFDocument document) { + List fieldNames = new ArrayList<>(); + for (XWPFParagraph paragraph : document.getParagraphs()) { + for (XWPFRun run : paragraph.getRuns()) { + // 获取底层 CTR 对象 + CTR ctr = run.getCTR(); + for (CTText instrText : ctr.getInstrTextList()) { + String text = instrText.getStringValue(); + if (text != null && text.contains("MERGEFIELD")) { + // 正则提取字段名 + Pattern pattern = Pattern.compile("MERGEFIELD\\s+\"?([^\"\\s]+)\"?"); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + String fieldName = matcher.group(1).trim(); + fieldNames.add(fieldName); + } + } + } + } + } + return fieldNames; + } +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/XmlUtil.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/XmlUtil.java new file mode 100644 index 00000000..92020e2a --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/XmlUtil.java @@ -0,0 +1,25 @@ +package pc.exam.pp.module.judgement.utils.wps_word; + +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.xmlbeans.XmlObject; + +import java.io.StringWriter; +import javax.xml.transform.*; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +public class XmlUtil { + public static String getDocumentXml(XWPFDocument doc) throws Exception { + XmlObject xml = doc.getDocument(); // 获取底层 CTDocument1(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1) + + // 转换为 DOM + org.w3c.dom.Node domNode = xml.getDomNode(); + Transformer tf = TransformerFactory.newInstance().newTransformer(); + tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + tf.setOutputProperty(OutputKeys.INDENT, "yes"); + + StringWriter writer = new StringWriter(); + tf.transform(new DOMSource(domNode), new StreamResult(writer)); + return writer.toString(); + } +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/vo/WordVO.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/vo/WordVO.java new file mode 100644 index 00000000..c85e7f61 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/vo/WordVO.java @@ -0,0 +1,24 @@ +package pc.exam.pp.module.judgement.utils.wps_word.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +public class WordVO { + + @Schema(description = "相关文本") + private String wordText; + + @Schema(description = "考试考点") + private List examKeynote; + + @Schema(description = "考点汉化") + private List keynoteChinese; + + @Schema(description = "是否有样式修饰") + private Boolean isTrue; + + +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/resources/mapper/wpsword/WpsWOrdLinkMapper.xml b/exam-module-judgement/exam-module-judgement-biz/src/main/resources/mapper/wpsword/WpsWOrdLinkMapper.xml new file mode 100644 index 00000000..409a9c72 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/resources/mapper/wpsword/WpsWOrdLinkMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/exam-module-system/exam-module-system-api/src/main/java/pc/exam/pp/module/system/enums/ErrorCodeConstants.java b/exam-module-system/exam-module-system-api/src/main/java/pc/exam/pp/module/system/enums/ErrorCodeConstants.java index 3bb28914..7094c5c5 100644 --- a/exam-module-system/exam-module-system-api/src/main/java/pc/exam/pp/module/system/enums/ErrorCodeConstants.java +++ b/exam-module-system/exam-module-system-api/src/main/java/pc/exam/pp/module/system/enums/ErrorCodeConstants.java @@ -174,4 +174,13 @@ public interface ErrorCodeConstants { ErrorCode STUDENT_USERNAME_LOGIN = new ErrorCode(1_002_029_002, "学生账号无法登陆!"); ErrorCode STUDENT_USERNAME_NOTLOGIN = new ErrorCode(1_002_029_003, "非学生账号无法登陆!"); + + // ========== WpsWOrd 1-002-030-000 ========== + ErrorCode WORD_NAME_DUPLICATE = new ErrorCode(1_002_030_000, "已经存在该名字的WORD节点"); + ErrorCode WORD_PARENT_NOT_EXITS = new ErrorCode(1_002_030_001,"父级WORD节点不存在"); + ErrorCode WORD_NOT_FOUND = new ErrorCode(1_002_030_002, "当前WORD节点不存在"); + ErrorCode WORD_EXITS_CHILDREN = new ErrorCode(1_002_030_003, "存在子WORD节点,无法删除"); + ErrorCode WORD_PARENT_ERROR = new ErrorCode(1_002_030_004, "不能设置自己为父WORD节点"); + ErrorCode WORD_NOT_ENABLE = new ErrorCode(1_002_030_006, "WORD节点({})不处于开启状态,不允许选择"); + ErrorCode WORD_PARENT_IS_CHILD = new ErrorCode(1_002_030_007, "不能设置自己的子WORD节点为父WORD节点"); } diff --git a/exam-module-system/exam-module-system-biz/src/main/java/pc/exam/pp/module/system/dal/redis/RedisKeyConstants.java b/exam-module-system/exam-module-system-biz/src/main/java/pc/exam/pp/module/system/dal/redis/RedisKeyConstants.java index 2e2792d7..acd0a3c8 100644 --- a/exam-module-system/exam-module-system-biz/src/main/java/pc/exam/pp/module/system/dal/redis/RedisKeyConstants.java +++ b/exam-module-system/exam-module-system-biz/src/main/java/pc/exam/pp/module/system/dal/redis/RedisKeyConstants.java @@ -17,6 +17,14 @@ public interface RedisKeyConstants { */ String DEPT_CHILDREN_ID_LIST = "dept_children_ids"; + /** + * 指定WPS_WORD的所有子WPS_WORD编号数组的缓存 + *

+ * KEY 格式:wps_word_children_ids:{id} + * VALUE 数据类型:String 子WPS_WORD编号集合 + */ + String WPS_WORD_CHILDREN_ID_LIST = "wps_word_children_ids"; + /** * 角色的缓存 *