huliguo
2 天以前 d8143b9121bbe941f116230eaa5524ab2cc12a66
新增
2个文件已添加
22个文件已修改
497 ■■■■ 已修改文件
src/main/java/com/linghu/config/MyBatisPlusConfig.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/AuthController.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/CollectController.java 110 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/KeywordController.java 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/QuestionController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/SectionalizationController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/UserController.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/UserMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/ExportGetResultDTO.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/ExportStaticsDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Sectionalization.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/User.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/vo/GetTimeVO.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/vo/KeywordStaticsListVO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/vo/KeywordStaticsVO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/vo/SectionalizationUserVO.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/vo/UserPageVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/SectionalizationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/SectionalizationServiceImpl.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/timeTask/ScheduledTasks.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/utils/OpenCryptUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/UserMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/keywordMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/config/MyBatisPlusConfig.java
@@ -1,18 +1,24 @@
package com.linghu.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@MapperScan("com.linghu.mapper")
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件,这里可指定数据库类型(如 MySQL),也可默认
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}
src/main/java/com/linghu/controller/AuthController.java
@@ -63,15 +63,15 @@
        return ResponseEntity.ok(decrypt);
    }
//    @GetMapping("/getToken")
//    @ApiOperation(value = "获取token")
//    public ResponseEntity<?> getToken(@RequestBody User user) {
//        // 创建用户对
//
//        // 创建JwtUtils对象,并生成JWT令牌
//        OpenCryptUtil openCryptUtil = new OpenCryptUtil();
//        String decrypt = openCryptUtil.encrypt(user);
//        // 返回JWT令牌
//        return ResponseEntity.ok(decrypt);
//    }
    @GetMapping("/getToken")
    @ApiOperation(value = "获取token")
    public ResponseEntity<?> getToken( String user) {
        // 创建用户对
        // 创建JwtUtils对象,并生成JWT令牌
        OpenCryptUtil openCryptUtil = new OpenCryptUtil();
        String decrypt = openCryptUtil.encrypt(user);
        // 返回JWT令牌
        return ResponseEntity.ok(decrypt);
    }
}
src/main/java/com/linghu/controller/CollectController.java
@@ -47,6 +47,7 @@
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@RestController
@RequestMapping("/collect")
@@ -206,10 +207,11 @@
       int maxConcurrentUsers = searchTaskRequest.getConfig() != null ?
               searchTaskRequest.getConfig().getMax_concurrent_users() : 3;
       List<List<UserDto>> userBatches = splitUsersIntoBatches(searchTaskRequest.getUsers(), maxConcurrentUsers);
       // 获取 keywordId
       Integer keywordId = searchTaskRequest.getKeyword_id();
       //分割
       List<List<UserDto>> userBatches = splitUsersIntoBatches(searchTaskRequest.getUsers(), maxConcurrentUsers,keywordId);
       return Flux.fromIterable(userBatches)
               .flatMap(batch -> {
@@ -255,7 +257,15 @@
                .then();
    }
    private List<List<UserDto>> splitUsersIntoBatches(List<UserDto> users, int batchSize) {
    private List<List<UserDto>> splitUsersIntoBatches(List<UserDto> users, int batchSize,Integer keywordId) {
        Keyword keyword = keywordService.getById(keywordId);
        if (null==keyword.getNum()){
            keyword.setNum(0);
        }
        keyword.setNum(keyword.getNum()+1);
        keywordService.updateById(keyword);
        List<List<UserDto>> batches = new ArrayList<>();
        for (int i = 0; i < users.size(); i += batchSize) {
            batches.add(users.subList(i, Math.min(i + batchSize, users.size())));
@@ -485,7 +495,7 @@
                // 3. 收集所有需要更新的问题和引用
                List<Question> questionsToUpdate = new ArrayList<>();
                List<Reference> allReferences = new ArrayList<>();
                List<Reference> resultList = new ArrayList<>();
                // 遍历结果
                for (UserResult userResult : result.getResults()) {
                    for (QuestionResult questionResult : userResult.getQuestions_results()) {
@@ -511,17 +521,6 @@
                                questionsToUpdate.add(question);
                                //如果查询结果不为空查询num
                                Integer maxNumByKeywordId = referenceService.getMaxNumByKeywordId(keyword.getKeyword_id());
                               if (maxNumByKeywordId != null){
                                   maxNumByKeywordId++;
                               }else {
                                   maxNumByKeywordId = 1;
                               }
                                // 收集引用数据,处理空集合情况
                                Integer finalMaxNumByKeywordId = maxNumByKeywordId;
                                List<Reference> references =
                                        Optional.ofNullable(questionResult.getReferences())
                                                .orElse(Collections.emptyList())
@@ -532,30 +531,38 @@
                                                    reference.setTitle(ref.getTitle());
                                                    reference.setUrl(ref.getUrl());
                                                    reference.setDomain(ref.getDomain());
                                                    reference.setNum(finalMaxNumByKeywordId);
                                                    reference.setNum(keyword.getNum());
                                                    reference.setTask_id(result.getTask_id());
                                                    reference.setKeyword_id(keyword.getKeyword_id());
                                                    //域名和平台id映射
                                                    reference.setCreate_time(LocalDateTime.now());
                                                    Platform platform = platformService.getPlatformByDomain(reference.getDomain());
//                                                    if (platform == null) {
//                                                        throw new RuntimeException("未找到对应的平台: " + reference.getDomain());
//                                                    }
                                                    if (platform != null){
                                                    if (platform == null) {
                                                        //平台为空 创建平台 类型为“默认”
                                                        Type type = typeService.getOne(new LambdaQueryWrapper<Type>().eq(Type::getType_name,"默认"));
                                                        if (type == null) {
                                                            Type newType = new Type();
                                                            newType.setType_name("默认");
                                                            typeService.save(newType);
                                                            type = newType;
                                                        }
                                                        Platform platform1 = new Platform();
                                                        platform1.setDomain(reference.getDomain());
                                                        platform1.setPlatform_name(reference.getDomain());
                                                        platform1.setType_id(type.getType_id());
                                                        platformService.save(platform1);
                                                        reference.setType_id(type.getType_id());
                                                        reference.setPlatform_id(platform1.getPlatform_id());
                                                    }
                                                    else {
                                                        reference.setPlatform_id(platform.getPlatform_id());
                                                        Type type = typeService.getById(platform.getType_id());
//                                                    if (type == null) {
//                                                        throw new RuntimeException("未找到对应的类型: " + reference.getDomain());
//                                                    }
                                                        if (type != null){
                                                            reference.setType_id(type.getType_id());
                                                        }
                                                    }
                                                    // 根据 domain 查询类型
                                                    return reference;
                                                })
                                                .collect(Collectors.toList());
@@ -564,6 +571,53 @@
                                if (!references.isEmpty()) {
                                    allReferences.addAll(references);
                                }
                                //取数据库中当前关键词的当前轮次的当前问题id结果拿出来
                                List<Reference> dbList = referenceService.list(new LambdaQueryWrapper<Reference>().eq(Reference::getKeyword_id, keyword.getKeyword_id())
                                        .eq(Reference::getNum, keyword.getNum())
                                        .eq(Reference::getQuestion_id, question.getQuestion_id())
                                );
                                // 1. 合并两个列表
                                List<Reference> combinedList = new ArrayList<>();
                                combinedList.addAll(allReferences);
                                combinedList.addAll(dbList);
                                // 2. 创建复合键的Map,用于统计完全匹配的记录
                                Map<String, List<Reference>> compositeKeyMap = combinedList.stream()
                                        .collect(Collectors.groupingBy(
                                                ref -> ref.getTitle() + "|" + ref.getUrl() + "|" + ref.getDomain()
                                        ));
                                // 3. 处理每组重复记录
                                compositeKeyMap.forEach((key, refGroup) -> {
                                    // 3.1 找出组内有ID的记录(优先从dbList中获取)
                                    Optional<Reference> existingRecord = refGroup.stream()
                                            .filter(ref -> ref.getReference_id() != null)
                                            .findFirst();
                                    // 3.2 统计该组的重复次数(总数-1)
                                    int repetitionCount = refGroup.size() - 1;
                                    // 3.3 决定最终保留的记录
                                    Reference recordToSave;
                                    if (existingRecord.isPresent()) {
                                        // 使用已有ID的记录并更新重复次数
                                        recordToSave = existingRecord.get();
                                        recordToSave.setRepetition_num(
                                                (recordToSave.getRepetition_num() == null ? 0 : recordToSave.getRepetition_num())
                                                        + repetitionCount
                                        );
                                    } else {
                                        // 没有ID记录则取第一条并设置重复次数
                                        recordToSave = refGroup.get(0);
                                        recordToSave.setRepetition_num(repetitionCount);
                                    }
                                    resultList.add(recordToSave);
                                });
                                referenceService.saveOrUpdateBatch(resultList);
                            }
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
@@ -578,7 +632,7 @@
                    questionService.updateBatchById(questionsToUpdate);
                    System.out.println("成功批量更新 " + questionsToUpdate.size() + " 个问题");
                }
                referenceService.saveBatch(allReferences);
                // 5. 批量插入引用,使用流式分批处理
//                if (!allReferences.isEmpty()) {
//                    int batchSize = 1000;
src/main/java/com/linghu/controller/KeywordController.java
@@ -75,14 +75,58 @@
    @ApiOperation(value = "EChart图")
    public ResponseResult<KeywordStaticsListVO> statics(@RequestParam("id") Integer keywordId,
            @RequestParam(value = "questionId", required = false) Integer questionId) {
            //
        return keywordService.statics(keywordId, questionId);
    }
    @GetMapping("/getTime")
    @ApiOperation(value = "查看时间")
    public ResponseResult<GetTimeVO> getTime(@RequestParam("id") Integer keywordId,@RequestParam(value = "questionId", required = false) Integer questionId) {
        //
        GetTimeVO vo = new GetTimeVO();
        Keyword keyword = keywordService.getById(keywordId);
        LambdaQueryWrapper<Reference> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Reference::getKeyword_id, keywordId);
        if (questionId != null) {
            queryWrapper.eq(Reference::getQuestion_id, questionId);
        }
        queryWrapper.eq(Reference::getNum,keyword.getNum());
        List<Reference> list = referenceService.list(queryWrapper);
        if (null != list && !list.isEmpty()) {
            vo.setNow(list.get(0).getCreate_time());
        }
        //首次
        LambdaQueryWrapper<Reference> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(Reference::getKeyword_id, keywordId);
        if (questionId != null) {
            queryWrapper2.eq(Reference::getQuestion_id, questionId);
        }
        queryWrapper2.eq(Reference::getNum,1);
        List<Reference> list2 = referenceService.list(queryWrapper2);
        if (null != list2 && !list2.isEmpty()) {
            vo.setFirst(list2.get(0).getCreate_time());
        }
        return ResponseResult.success(vo);
    }
    @PostMapping(value = "/exportStatics")
    @ApiOperation(value = "EChart图导出")
    public ResponseEntity<byte[]> exportStatics(@RequestBody ExportStaticsDTO exportStaticsDTO) {
        Keyword keyword = keywordMapper.selectById(exportStaticsDTO.getKeywordId());
        List<KeywordStaticsVO> voList = keywordMapper.statics(exportStaticsDTO.getKeywordId(), exportStaticsDTO.getQuestionId(), keyword.getNum());
        List<KeywordStaticsVO> voList=new ArrayList<>();
        if (exportStaticsDTO.getIsFirst()==0){
            voList = keywordMapper.statics(exportStaticsDTO.getKeywordId(), exportStaticsDTO.getQuestionId(), keyword.getNum());
        }else {
            voList = keywordMapper.statics(exportStaticsDTO.getKeywordId(), exportStaticsDTO.getQuestionId(), 1);
        }
        // 3. 导出Excel
        ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -112,14 +156,10 @@
                    keyword.getNum() , typeId);
            return ResponseResult.success(result);
        }
        if (isNow > 0 && keyword.getNum()>isNow){
            List<PlatformProportionVO> result = keywordMapper.getResultByTypeId(keywordId, questionId,
                    keyword.getNum() - isNow, typeId);
        }else {
            List<PlatformProportionVO> result = keywordMapper.getResultByTypeId(keywordId, questionId, 1, typeId);
            return ResponseResult.success(result);
        }else {
            return ResponseResult.success(new ArrayList<>());
        }
    }
@@ -131,8 +171,18 @@
    @ApiOperation(value = "导出:根据类别查看")
    public ResponseEntity<byte[]> exportGetResultByTypeId(@RequestBody ExportGetResultDTO dto) {
        Keyword keyword = keywordService.getById(dto.getKeywordId());
        List<PlatformProportionVO> result = keywordMapper.getResultByTypeId(dto.getKeywordId(), dto.getQuestionId(),
                keyword.getNum() - dto.getIsNow(), dto.getTypeId());
        List<PlatformProportionVO> result =new ArrayList<>();
        if (dto.getIsNow()==0){
            result = keywordMapper.getResultByTypeId(dto.getKeywordId(), dto.getQuestionId(),
                    keyword.getNum() , dto.getTypeId());
        }else {
            result = keywordMapper.getResultByTypeId(dto.getKeywordId(), dto.getQuestionId(),
                    1 , dto.getTypeId());
        }
        // 3. 导出Excel
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        EasyExcel.write(out, PlatformProportionVO.class)
@@ -160,15 +210,12 @@
            List<ResultListVO> result = keywordMapper.getResultByPlatformId(keywordId, questionId, keyword.getNum(),
                    platformId);
            return ResponseResult.success(result);
        }
        if (isNow > 0 && keyword.getNum()>isNow){
        List<ResultListVO> result = keywordMapper.getResultByPlatformId(keywordId, questionId, keyword.getNum() - isNow,
                platformId);
        return ResponseResult.success(result);
        }else {
            return ResponseResult.success(new ArrayList<>());
            List<ResultListVO> result = keywordMapper.getResultByPlatformId(keywordId, questionId, 1,
                    platformId);
            return ResponseResult.success(result);
        }
    }
    /**
@@ -178,8 +225,14 @@
    @ApiOperation(value = "导出:根据平台查看")
    public ResponseEntity<byte[]> exportGetResultByPlatformId(@RequestBody ExportGetResultByPlatformIdDTO dto) {
        Keyword keyword = keywordService.getById(dto.getKeywordId());
        List<ResultListVO> result = keywordMapper.getResultByPlatformId(dto.getKeywordId(), dto.getQuestionId(), keyword.getNum() - dto.getIsNow(),
        List<ResultListVO> result=new ArrayList<>();
        if (dto.getIsNow()==0){
            result = keywordMapper.getResultByPlatformId(dto.getKeywordId(), dto.getQuestionId(), keyword.getNum(),
                dto.getPlatformId());
        }else {
            result = keywordMapper.getResultByPlatformId(dto.getKeywordId(), dto.getQuestionId(), 1,
                    dto.getPlatformId());
        }
        // 3. 导出Excel
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        EasyExcel.write(out, ResultListVO.class)
src/main/java/com/linghu/controller/QuestionController.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@RestController
@@ -91,13 +92,11 @@
                    return question;
                }).collect(Collectors.toList());
        boolean success = questionService.saveBatch(questionList);
         questionService.saveBatch(questionList);
         return ResponseResult.success();
        if(success) {
            return ResponseResult.success(questionList);
        }
        return ResponseResult.error("更新提问词失败");
    }
//    @PutMapping
src/main/java/com/linghu/controller/SectionalizationController.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.entity.Sectionalization;
import com.linghu.model.vo.SectionalizationUserVO;
import com.linghu.service.SectionalizationService;
import com.linghu.service.UserService;
import io.swagger.annotations.Api;
@@ -75,4 +76,14 @@
    }
    /**
     * 列表和底下用户数据
     */
    @GetMapping("/sectionalizationUser")
    @ApiOperation(value = "获取分组列表和底下用户数据")
    public ResponseResult<List<SectionalizationUserVO>> sectionalizationUser() {
        List<SectionalizationUserVO> list = sectionalizationService.SectionalizationUser();
        return ResponseResult.success(list);
    }
}
src/main/java/com/linghu/controller/UserController.java
@@ -5,11 +5,10 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.entity.Sectionalization;
import com.linghu.model.entity.Type;
import com.linghu.model.entity.User;
import com.linghu.model.excel.KeywordExcel;
import com.linghu.model.excel.UserExcel;
import com.linghu.model.vo.UserPageVO;
import com.linghu.service.SectionalizationService;
import com.linghu.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -17,12 +16,16 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/user")
@@ -42,6 +45,7 @@
        if (list != null && list.size() > 0) {
            return ResponseResult.error("该邮箱已存在");
        }
        user.setStatus("正常");
        userService.save(user);
        return ResponseResult.success();
@@ -52,8 +56,12 @@
     * 修改用户
     */
    @PutMapping
    @ApiOperation(value = "添加")
    @ApiOperation(value = "修改")
    public ResponseResult edit(@RequestBody User user) {
        User user1 = userService.getById(user.getUser_id());
        if (user1 == null) {
            return ResponseResult.error("该账户不存在");
        }
        List<User> list = userService.list(new LambdaQueryWrapper<User>()
                        .ne(User::getUser_id, user.getUser_id())
                .eq(User::getUser_email, user.getUser_email()));
@@ -80,22 +88,20 @@
     * 分页查询
     */
    @GetMapping
    @ApiOperation(value = "删除")
    @ApiOperation(value = "分页")
    public ResponseResult<Page<UserPageVO>> page(@RequestParam(value = "pageSize", required = false, defaultValue = "10")Integer pageSize,
                                                 @RequestParam(value = "pageNum", required = false,defaultValue = "1")Integer pageNum,
                                                 @RequestParam(value = "sectionalization_id",required = false)Integer sectionalization_id,
                                                 @RequestParam(value = "status" ,required = false)String status) {
        Page<UserPageVO> page = new Page<>(pageNum, pageSize);
        return ResponseResult.success( userService.getPage(page,sectionalization_id,status));
    }
    /**
     * 下载模板
     */
    @PostMapping("/downloadTemplate")
    @GetMapping("/downloadTemplate")
    @ApiOperation("下载模板")
    public ResponseEntity<byte[]> downloadTemplate() throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -111,7 +117,102 @@
    /**
     * 导入文件
     */
    // 导入文件
    @Autowired
    private SectionalizationService sectionalizationService;
    @PostMapping("/importUserExcel")
    @ApiOperation("导入用户数据")
    public ResponseResult importUserExcel(@RequestParam("file") MultipartFile file) {
        //查找出用户列表
        List<User> userList = userService.list();
        //名称
        Map<String, User> nameMap = userList.stream()
                .collect(Collectors.toMap(
                        User::getUser_name,  // Key映射
                        excel -> excel,  // Value映射
                        (oldValue, newValue) -> oldValue  // 键冲突处理(保留旧值)
                ));
        //查找出分组列表
        List<Sectionalization>  list = sectionalizationService.list();
        //分组
        Map<String, Sectionalization> sectionalizationMap = list.stream()
                .collect(Collectors.toMap(
                        Sectionalization::getSectionalization_name,  // Key映射
                        excel -> excel,  // Value映射
                        (oldValue, newValue) -> oldValue  // 键冲突处理(保留旧值)
                ));
        try {
            // 检查文件是否为空
            if (file.isEmpty()) {
                return ResponseResult.error("上传文件不能为空");
            }
            // 读取Excel数据
            List<UserExcel> excelList = EasyExcel.read(file.getInputStream())
                    .head(UserExcel.class)
                    .sheet()
                    .doReadSync();
            // 数据转换与验证
            List<String> errorMessages = new ArrayList<>();
            for (UserExcel excel : excelList) {
                // 检查必要字段
                if (!StringUtils.hasText(excel.getUser_name())) {
                    errorMessages.add("账户名不能为空");
                    continue;
                }
                if (!StringUtils.hasText(excel.getUser_email())) {
                    errorMessages.add("邮箱不能为空");
                    continue;
                }
                if (!StringUtils.hasText(String.valueOf(excel.getPassword()))) {
                    errorMessages.add("密码不能为空");
                    continue;
                }
                if (!StringUtils.hasText(excel.getSectionalization_name())) {
                    errorMessages.add("分组不能为空");
                    continue;
                }
                if (nameMap.containsKey(excel.getUser_name())){
                    errorMessages.add("用户名称重复");
                    continue;
                }
            }
            // 处理错误
            if (!errorMessages.isEmpty()) {
                return ResponseResult.error("数据验证失败: " + String.join("; ", errorMessages));
            }
            // 开始添加
            for (UserExcel excel : excelList) {
                User user = new User();
                if (sectionalizationMap.containsKey(excel.getSectionalization_name())) {
                    user.setSectionalization_id(sectionalizationMap.get(excel.getSectionalization_name()).getSectionalization_id());
                }else {
                    //新增
                    Sectionalization sectionalization = new Sectionalization();
                    sectionalization.setSectionalization_name(excel.getSectionalization_name());
                    sectionalizationService.save(sectionalization);
                    user.setSectionalization_id(sectionalization.getSectionalization_id());
                }
                user.setUser_email(excel.getUser_email());
                user.setUser_name(excel.getUser_name());
                user.setPassword(excel.getPassword());
                user.setStatus("正常");
                userService.save(user);
            }
            // 返回信息
            return ResponseResult.success();
        }
        catch (Exception e) {
            // 记录详细异常信息
            return ResponseResult.error("文件解析失败:" + e.getMessage());
        }
    }
src/main/java/com/linghu/mapper/UserMapper.java
@@ -14,7 +14,7 @@
*/
public interface UserMapper extends BaseMapper<User> {
    Page<UserPageVO> getPage(Page<UserPageVO> page, @Param("sectionalizationId") Integer sectionalizationId, @Param("status") String status);
    Page<UserPageVO> getPage(@Param("page") Page<UserPageVO> page, @Param("sectionalizationId") Integer sectionalizationId, @Param("status") String status);
}
src/main/java/com/linghu/model/dto/ExportGetResultDTO.java
@@ -9,6 +9,6 @@
    private Integer keywordId;
    private  Integer questionId;
    private Integer typeId;
    @ApiModelProperty("轮数 0:当前 1:前一轮")
    @ApiModelProperty("轮数 0:当前 1:首次")
    private Integer isNow;
}
src/main/java/com/linghu/model/dto/ExportStaticsDTO.java
@@ -9,4 +9,6 @@
    private Integer keywordId;
    @ApiModelProperty("提问词id")
    private  Integer questionId;
    @ApiModelProperty("是否首次 0-否 1- 是")
    private  Integer isFirst;
}
src/main/java/com/linghu/model/entity/Sectionalization.java
@@ -1,5 +1,6 @@
package com.linghu.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -14,7 +15,7 @@
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    @TableId
    @TableId(type = IdType.AUTO)
    private Integer sectionalization_id;
    @NotEmpty(message = "用户名不能为空")
src/main/java/com/linghu/model/entity/User.java
@@ -1,5 +1,6 @@
package com.linghu.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -9,6 +10,7 @@
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@@ -21,7 +23,7 @@
    /**
     * 用户id
     */
    @TableId
    @TableId(type = IdType.AUTO)
    private Integer user_id;
    /**
@@ -47,6 +49,7 @@
    /**
     * 手机号
     */
    @ApiModelProperty(hidden = true)
    private Integer phone;
    /**
src/main/java/com/linghu/model/vo/GetTimeVO.java
New file
@@ -0,0 +1,21 @@
package com.linghu.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import sun.util.resources.LocaleData;
import java.time.LocalDateTime;
@Data
public class GetTimeVO {
    @ApiModelProperty("本次采集时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime now;
    @ApiModelProperty("首次采集时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime first;
}
src/main/java/com/linghu/model/vo/KeywordStaticsListVO.java
@@ -5,6 +5,7 @@
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
@@ -13,7 +14,7 @@
    @ApiModelProperty("当前统计记录")
    private List<KeywordStaticsVO> nowRecord;
    @ApiModelProperty("统计记录-前一次")
    @ApiModelProperty("统计记录-首次")
    private List<KeywordStaticsVO> beforeRecord;
}
src/main/java/com/linghu/model/vo/KeywordStaticsVO.java
@@ -1,5 +1,6 @@
package com.linghu.model.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -10,6 +11,9 @@
@Data
@ApiModel("关键词统计")
public class KeywordStaticsVO {
    @ApiModelProperty("发布平台id")
    @ExcelIgnore
    private String platform_id;
    @ApiModelProperty("发布平台")
    @ExcelProperty("发布平台")
    private String platform_name;
src/main/java/com/linghu/model/vo/SectionalizationUserVO.java
New file
@@ -0,0 +1,18 @@
package com.linghu.model.vo;
import com.linghu.model.entity.User;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class SectionalizationUserVO {
    @ApiModelProperty("分组id")
    private Integer sectionalization_id;
    @ApiModelProperty("分组名称")
    private String sectionalization_name;
    @ApiModelProperty("用户VO")
    private List<User> sectionalization_users;
}
src/main/java/com/linghu/model/vo/UserPageVO.java
@@ -10,10 +10,10 @@
    private Integer user_id;
    @ApiModelProperty("用户名")
    private Integer user_name;
    private String user_name;
    @ApiModelProperty("用户邮箱")
    private Integer user_email;
    private String user_email;
    @ApiModelProperty("密码")
    private String password;
@@ -21,6 +21,8 @@
    @ApiModelProperty("分组名称")
    private String sectionalization_name;
    @ApiModelProperty("分组名称")
    private Integer sectionalization_id;
    @ApiModelProperty("状态")
    private String status;
src/main/java/com/linghu/service/SectionalizationService.java
@@ -5,6 +5,7 @@
import com.linghu.model.dto.OrderDto;
import com.linghu.model.entity.Orders;
import com.linghu.model.entity.Sectionalization;
import com.linghu.model.vo.SectionalizationUserVO;
import java.util.List;
@@ -15,4 +16,5 @@
 */
public interface SectionalizationService extends IService<Sectionalization> {
    List<SectionalizationUserVO> SectionalizationUser();
}
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java
@@ -41,7 +41,7 @@
        List<KeywordStaticsVO> statics = this.getBaseMapper().statics(keywordId, questionId, keyword.getNum());
        vo.setNowRecord(statics);
        if (keyword.getNum() > 1) {
            statics = this.getBaseMapper().statics(keywordId, questionId, keyword.getNum() - 1);
            statics = this.getBaseMapper().statics(keywordId, questionId, 1);
            vo.setBeforeRecord(statics);
        }
        return ResponseResult.success(vo);
src/main/java/com/linghu/service/impl/SectionalizationServiceImpl.java
@@ -1,13 +1,21 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.mapper.SectionalizationMapper;
import com.linghu.mapper.UserMapper;
import com.linghu.model.entity.Sectionalization;
import com.linghu.model.entity.User;
import com.linghu.model.vo.SectionalizationUserVO;
import com.linghu.service.SectionalizationService;
import com.linghu.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author xy
@@ -18,6 +26,50 @@
public class SectionalizationServiceImpl extends ServiceImpl<SectionalizationMapper, Sectionalization>
    implements SectionalizationService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public List<SectionalizationUserVO> SectionalizationUser() {
        // 1. 查询所有状态为"正常"的用户
        List<User> userList = userMapper.selectList(
                new LambdaQueryWrapper<User>()
                        .eq(User::getStatus, "正常")
        );
        // 2. 提取所有分组ID并去重
        List<Integer> sectionalizationIdList = userList.stream()
                .map(User::getSectionalization_id)
                .distinct()
                .collect(Collectors.toList());
        // 3. 查询这些分组的基本信息
        List<Sectionalization> sectionalizationList = this.baseMapper.selectList(
                new LambdaQueryWrapper<Sectionalization>()
                        .in(Sectionalization::getSectionalization_id, sectionalizationIdList)
        );
        // 4. 创建分组ID到分组名称的映射
        Map<Integer, String> sectionalizationNameMap = sectionalizationList.stream()
                .collect(Collectors.toMap(
                        Sectionalization::getSectionalization_id,
                        Sectionalization::getSectionalization_name
                ));
        // 5. 按分组ID对用户进行分组
        Map<Integer, List<User>> usersBySectionalization = userList.stream()
                .collect(Collectors.groupingBy(User::getSectionalization_id));
        // 6. 构建最终返回结果
        return sectionalizationIdList.stream()
                .map(id -> {
                    SectionalizationUserVO vo = new SectionalizationUserVO();
                    vo.setSectionalization_id(id);
                    vo.setSectionalization_name(sectionalizationNameMap.get(id));
                    vo.setSectionalization_users(usersBySectionalization.getOrDefault(id, Collections.emptyList()));
                    return vo;
                })
                .collect(Collectors.toList());
    }
}
src/main/java/com/linghu/timeTask/ScheduledTasks.java
@@ -62,8 +62,9 @@
                                    t.setStatus("completed");
                                    return t;
                                });
                    } else if (!"submit".equalsIgnoreCase(statusResponse.getStatus())
                            && !"running".equalsIgnoreCase(statusResponse.getStatus())) {
                    } else if (!"submitted".equalsIgnoreCase(statusResponse.getStatus())
                            && !"running".equalsIgnoreCase(statusResponse.getStatus())
                            && !"Error".equalsIgnoreCase(statusResponse.getStatus())) {
                        task.setStatus("false");
                        return Mono.just(task);
                    } else {
src/main/java/com/linghu/utils/OpenCryptUtil.java
@@ -32,7 +32,7 @@
    /**
     * AES加密(假设 open-crypt 默认使用AES-CBC模式)
     */
    public String encrypt(User user) {
    public String encrypt(String user) {
        try {
            // 调用 open-crypt 的加密方法(根据实际API调整)
            //user转为 json
src/main/resources/mapper/UserMapper.xml
@@ -25,6 +25,7 @@
            u.user_email,
            u.`password`,
            s.sectionalization_name,
        s.sectionalization_id,
            u.status
        FROM
            `user` u
src/main/resources/mapper/keywordMapper.xml
@@ -19,6 +19,7 @@
    </sql>
    <select id="statics" resultType="com.linghu.model.vo.KeywordStaticsVO">
        SELECT
        p.platform_id,
        p.platform_name,
        SUM( r.repetition_num ) AS total_repetitions,
        ROUND(