guyue
4 天以前 89f8649e8cf9bc12b9e29abb0adc4f9b77273143
第三方接口
1 文件已重命名
4个文件已删除
4个文件已添加
22个文件已修改
951 ■■■■■ 已修改文件
pom.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/config/Swagger2Config.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/AuthController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/CollectController.java 345 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/OrderController.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/PlatformController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/QuestionController.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/TypeController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/listener/KeywordExcelListener.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/OrderMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/HealthResponse.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/KeywordDto.java 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/OrderDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/TaskListResponse.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/TaskResultResponse.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Orders.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Platform.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Question.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Reference.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Type.java 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/excel/KeywordExcel.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/KeywordService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/OrderService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/PlatformExcelService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/OrderServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/OrderMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/schema.sql 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sql/keyword.sql 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sql/question.sql 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sql/reference.sql 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -84,7 +84,16 @@
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.13.4</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
src/main/java/com/linghu/config/Swagger2Config.java
@@ -21,53 +21,37 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
@EnableSwagger2 // 开启Swagger2
@EnableSwagger2
public class Swagger2Config {
    /**
     * 配置Swagger2核心对象Docket
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                // 配置API文档基本信息
                .apiInfo(apiInfo())
                // 选择需要生成文档的接口
                .select()
                // 扫描指定包下的接口(替换为你的Controller包路径)
                .apis(RequestHandlerSelectors.basePackage("com.linghu.controller"))
                // 匹配所有路径
                .paths(PathSelectors.any())
                .build()
                // 添加安全方案配置
                .securitySchemes(Arrays.asList(securityScheme()))
                .securityContexts(Arrays.asList(securityContext()))
                // 添加全局参数(header中的token参数)
                .globalOperationParameters(globalParameters());
                // 重点修改:使用 securitySchemes + securityContext 替代全局参数
                .securitySchemes(Arrays.asList(apiKey()))  // 添加安全方案
                .securityContexts(Arrays.asList(securityContext())); // 应用安全上下文
    }
    /**
     * 配置JWT安全方案
     */
    private ApiKey securityScheme() {
    // 1. 定义安全方案(在Swagger UI顶部添加Authorize按钮)
    private ApiKey apiKey() {
        return new ApiKey("BearerToken", "Authorization", "header");
    }
    /**
     * 配置安全上下文
     */
    // 2. 配置安全上下文(全局生效)
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .forPaths(PathSelectors.any()) // 对所有路径生效
                .build();
    }
    /**
     * 默认的安全引用
     */
    // 3. 设置默认授权范围
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
@@ -75,30 +59,11 @@
        return Arrays.asList(new SecurityReference("BearerToken", authorizationScopes));
    }
    /**
     * 配置全局参数
     */
    private List<Parameter> globalParameters() {
        List<Parameter> parameters = new ArrayList<>();
        parameters.add(new ParameterBuilder()
                .name("Authorization")
                .description("JWT Token (格式: Bearer [token])")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false)
                .build());
        return parameters;
    }
    /**
     * http://127.0.0.1:8080/swagger-ui.html
     * 配置API文档基本信息(标题、描述、作者等)
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("灵狐GEO系统 接口文档") // 文档标题
                .description("使用 Swagger2 生成的API文档") // 文档描述
                .version("1.0.0") // 版本号
                .title("灵狐GEO系统 接口文档")
                .description("使用 Swagger2 生成的API文档")
                .version("1.0.0")
                .build();
    }
}
src/main/java/com/linghu/controller/AuthController.java
@@ -14,6 +14,10 @@
import com.linghu.model.entity.User;
import com.linghu.utils.JwtUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@Api(value = "认证接口", tags = "认证管理")
@RestController
@RequestMapping("/auth")
public class AuthController {
@@ -21,6 +25,7 @@
    private String secretKey;
    @PostMapping("/login")
    @ApiOperation(value = "外部登录")
    public ResponseEntity<?> externalLogin(
            @RequestBody User user) {
@@ -36,6 +41,7 @@
    // 获取用户信息
    @PostMapping("/getUserInfo")
    @ApiOperation(value = "获取用户信息")
    public ResponseEntity<?> getUserInfo(@RequestParam String token) {
        // 解析JWT令牌,获取用户信息
        JwtUtils jwtUtils = new JwtUtils(secretKey, 3600);
src/main/java/com/linghu/controller/CollectController.java
@@ -1,6 +1,7 @@
package com.linghu.controller;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -17,8 +18,10 @@
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.dto.HealthResponse;
import com.linghu.model.dto.SearchTaskRequest;
import com.linghu.model.entity.Keyword;
import com.linghu.model.entity.Question;
@@ -30,6 +33,7 @@
import com.linghu.model.dto.SearchTaskResponse;
import com.linghu.model.dto.TaskStatusResponse;
import com.linghu.model.dto.TaskCancelResponse;
import com.linghu.model.dto.TaskListResponse;
import io.jsonwebtoken.lang.Collections;
import io.swagger.annotations.Api;
@@ -158,138 +162,235 @@
                    return Mono.just(ResponseResult.error(500, "取消任务失败: " + e.getMessage()));
                });
    }
    // @ApiOperation(value = "获取任务结果")
    // @GetMapping("/tasks/{taskId}/result")
    // public Mono<ResponseResult<TaskResultResponse>> getTaskResult(@PathVariable
    // String taskId) {
    // return webClient.get()
    // .uri(baseUrl + "/tasks/" + taskId + "/result")
    // .retrieve()
    // .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class)
    // .flatMap(errorBody -> Mono.error(new RuntimeException("获取结果失败: " +
    // errorBody))))
    // .bodyToMono(TaskResultResponse.class)
    // .flatMap(result -> {
    // // 更新keyword状态
    // LambdaUpdateWrapper<Keyword> keywordWrapper = new LambdaUpdateWrapper<>();
    // keywordWrapper.eq(Keyword::getTask_id, taskId)
    // .set(Keyword::getStatus, "completed");
    // keywordService.update(keywordWrapper);
    // // 更新question信息并收集references
    // List<Question> updateQuestions = new ArrayList<>();
    // List<Reference> references = new ArrayList<>();
    @ApiOperation(value = "获取任务结果")
    @GetMapping("/tasks/{taskId}")
    public Mono<ResponseResult<TaskResultResponse>> getTaskResult(@PathVariable String taskId) {
        return webClient.get()
                .uri(baseUrl + "/tasks/" + taskId + "/result")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError, response -> {
                    if (response.statusCode() == HttpStatus.NOT_FOUND) {
                        return response.bodyToMono(String.class)
                                .flatMap(errorBody -> Mono.error(new RuntimeException("任务不存在")));
                    } else if (response.statusCode() == HttpStatus.BAD_REQUEST) {
                        return response.bodyToMono(String.class)
                                .flatMap(errorBody -> Mono.error(new RuntimeException("任务未完成,无法获取结果")));
                    }
                    return response.createException().flatMap(Mono::error);
                })
                .bodyToMono(new ParameterizedTypeReference<ResponseResult<TaskResultResponse>>() {
                })
                .flatMap(responseResult -> {
                    TaskResultResponse result = responseResult.getData();
                    if (result != null && result.getResults() != null) {
                        return updateQuestionAndReference(result)
                                .thenReturn(responseResult);
                    }
                    return Mono.just(responseResult);
                })
                .onErrorResume(e -> {
                    System.out.println("获取任务结果失败");
                    return Mono.just(ResponseResult.error(e.getMessage()));
                });
    }
    // result.getResults().forEach(userResult -> {
    // userResult.getQuestions_results().forEach(qResult -> {
    // Question question = new Question();
    // question.setQuestion_id(qResult.getQuestion_id());
    // question.setResponse(qResult.getResponse());
    // question.setStatus(qResult.getStatus());
    // updateQuestions.add(question);
    /*
     * private Mono<Void> updateQuestionAndReference(TaskResultResponse result) {
     * return Mono.fromRunnable(() -> {
     * // 1. 更新关键词状态
     * LambdaUpdateWrapper<Keyword> keywordUpdate = new LambdaUpdateWrapper<>();
     * keywordUpdate.eq(Keyword::getTask_id, result.getTask_id())
     * .set(Keyword::getStatus, "completed");
     * keywordService.update(keywordUpdate);
     *
     * // 查询关键词ID
     * LambdaQueryWrapper<Keyword> keywordQuery = new LambdaQueryWrapper<>();
     * keywordQuery.eq(Keyword::getTask_id, result.getTask_id());
     * Keyword keyword = keywordService.getOne(keywordQuery);
     *
     * if (keyword == null) {
     * System.out.println("未找到关联的关键词,task_id: " + result.getTask_id());
     * return;
     * }
     *
     * // 2. 处理每个用户的问题结果
     * for (UserResult userResult : result.getResults()) {
     * for (QuestionResult questionResult : userResult.getQuestions_results()) {
     * // 2.1 查询问题ID
     * LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
     * queryWrapper.eq(Question::getQuestion, questionResult.getQuestion())
     * .eq(Question::getKeyword_id, keyword.getKeyword_id());
     * Question question = questionService.getOne(queryWrapper);
     *
     * if (question != null) {
     * // 更新问题状态
     * LambdaUpdateWrapper<Question> updateWrapper = new LambdaUpdateWrapper<>();
     * updateWrapper.eq(Question::getQuestion_id, question.getQuestion_id())
     * .set(Question::getStatus, questionResult.getStatus())
     * .set(Question::getResponse, questionResult.getResponse())
     * .set(Question::getExtracted_count, questionResult.getExtracted_count())
     * .set(Question::getError, questionResult.getError())
     * .set(Question::getTimestamp, LocalDateTime.parse(
     * questionResult.getTimestamp(),
     * DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")
     * ));
     * questionService.update(updateWrapper);
     *
     * // 2.2 保存引用数据
     * List<Reference> references = questionResult.getReferences().stream()
     * .map(ref -> {
     * Reference reference = new Reference();
     * reference.setQuestion_id(question.getQuestion_id());
     * reference.setTitle(ref.getTitle());
     * reference.setUrl(ref.getUrl());
     * reference.setDomain(ref.getDomain());
     * reference.setCreate_time(new Date());
     * return reference;
     * })
     * .collect(Collectors.toList());
     *
     * if (!references.isEmpty()) {
     * referenceService.saveBatch(references);
     * }
     * } else {
     * System.out.println("未找到匹配的问题,question " + question.getQuestion());
     *
     * }
     * }
     * }
     * });
     * }
     */
    // // 转换references
    // references.addAll(qResult.getReferences().stream()
    // .map(ref -> new Reference(
    // qResult.getQuestion_id(),
    // ref.getTitle(),
    // ref.getUrl(),
    // ref.getDomain(),
    // result.getTask_id(),
    // ))
    // .collect(Collectors.toList()));
    // });
    // });
    private Mono<Void> updateQuestionAndReference(TaskResultResponse result) {
        return Mono.fromRunnable(() -> {
            try {
                // 1. 更新关键词状态
                LambdaUpdateWrapper<Keyword> keywordUpdate = new LambdaUpdateWrapper<>();
                keywordUpdate.eq(Keyword::getTask_id, result.getTask_id())
                        .set(Keyword::getStatus, "completed");
                keywordService.update(keywordUpdate);
    // // 批量更新和插入
    // if (!updateQuestions.isEmpty()) {
    // questionService.updateBatchById(updateQuestions);
    // }
    // if (!references.isEmpty()) {
    // referenceService.saveBatch(references);
    // }
                // 查询关键词ID
                LambdaQueryWrapper<Keyword> keywordQuery = new LambdaQueryWrapper<>();
                keywordQuery.eq(Keyword::getTask_id, result.getTask_id());
                Keyword keyword = keywordService.getOne(keywordQuery);
    // return Mono.just(ResponseResult.success(result));
    // })
    // .onErrorResume(e -> Mono.just(ResponseResult.error(e.getMessage())));
    // }
                if (keyword == null) {
                    // log.error("未找到关联的关键词,task_id: {}", result.getTask_id());
                    System.out.println("未找到关联的关键词,task_id: " + result.getTask_id());
                    return;
                }
    // @ApiOperation(value = "获取任务结果")
    // @GetMapping("/tasks/{taskId}/result")
    // public Mono<ResponseResult<TaskResultResponse>>
    // getTaskResultlMono(@PathVariable String taskId) {
    // return webClient.get()
    // .uri(baseUrl + "/tasks/" + taskId + "/result")
    // .accept(MediaType.APPLICATION_JSON)
    // .retrieve()
    // .onStatus(HttpStatus::is4xxClientError, response -> {
    // if (response.statusCode() == HttpStatus.NOT_FOUND) {
    // return response.bodyToMono(String.class)
    // .flatMap(errorBody -> Mono.error(new RuntimeException("任务不存在")));
    // } else if (response.statusCode() == HttpStatus.BAD_REQUEST) {
    // return response.bodyToMono(String.class)
    // .flatMap(errorBody -> Mono.error(new RuntimeException("任务未完成,无法获取结果")));
    // }
    // return response.createException().flatMap(Mono::error);
    // })
    // .bodyToMono(new
    // ParameterizedTypeReference<ResponseResult<TaskResultResponse>>() {})
    // .flatMap(responseResult -> {
    // TaskResultResponse result = responseResult.getData();
    // if (result != null && result.getResults() != null) {
    // // 处理结果并更新数据库
    // return updateQuestionAndReference(result)
    // .thenReturn(responseResult);
    // }
    // return Mono.just(responseResult);
    // })
    // .onErrorResume(e -> {
                // 2. 批量查询所有问题(假设Question有task_id和keyword_id字段)
                LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Question::getKeyword_id, keyword.getKeyword_id());
                List<Question> questions = questionService.list(queryWrapper);
    // return Mono.just(ResponseResult.error(e.getMessage()));
    // });
    // }
                // 构建问题映射表,用于快速查找
                Map<String, Question> questionMap = questions.stream()
                        .collect(Collectors.toMap(Question::getQuestion, q -> q));
    // 更新问题和引用数据
    // private Mono<Void> updateQuestionAndReference(TaskResultResponse result) {
    // return Mono.fromRunnable(() -> {
    // // 1. 更新关键词状态
    // LambdaUpdateWrapper<Keyword> keywordUpdate = new LambdaUpdateWrapper<>();
    // keywordUpdate.eq(Keyword::getTask_id, result.getTask_id())
    // .set(Keyword::getStatus, "completed");
    // keywordService.update(keywordUpdate);
                // 3. 收集所有需要更新的问题和引用
                List<Question> questionsToUpdate = new ArrayList<>();
                List<Reference> allReferences = new ArrayList<>();
    // // 2. 处理每个用户的问题结果
    // for (UserResult userResult : result.getResults()) {
    // for (QuestionResult questionResult : userResult.getQuestions_results()) {
    // // 2.1 更新问题状态
    // LambdaUpdateWrapper<Question> questionUpdate = new LambdaUpdateWrapper<>();
    // questionUpdate.eq(Question::getTa, result.getTask_id())
    // .eq(Question::getContent, questionResult.getQuestion())
    // .set(Question::getStatus, questionResult.getStatus())
    // .set(Question::getResponse, questionResult.getResponse())
    // .set(Question::getProcessTime,
    // LocalDateTime.parse(questionResult.getTimestamp()));
    // questionService.update(questionUpdate);
                // 遍历结果,只收集数据不执行数据库操作
                for (UserResult userResult : result.getResults()) {
                    for (QuestionResult questionResult : userResult.getQuestions_results()) {
                        try {
                            Question question = questionMap.get(questionResult.getQuestion());
                            if (question != null) {
                                // 更新问题对象
                                question.setStatus(questionResult.getStatus());
                                question.setResponse(questionResult.getResponse());
                                question.setExtracted_count(questionResult.getExtracted_count());
                                question.setError(questionResult.getError());
    // // 2.2 保存引用数据
    // List<Reference> references = questionResult.getReferences().stream()
    // .map(ref -> {
    // Reference reference = new Reference();
    // reference.setQuestionId(questionService.getOne(questionUpdate).getId());
    // reference.setTitle(ref.getTitle());
    // reference.setUrl(ref.getUrl());
    // reference.setDomain(ref.getDomain());
    // reference.setCreateTime(LocalDateTime.now());
    // return reference;
    // })
    // .collect(Collectors.toList());
                                // 解析时间戳
                                if (questionResult.getTimestamp() != null) {
                                    DateTimeFormatter formatter = DateTimeFormatter
                                            .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
                                    question.setTimestamp(
                                            LocalDateTime.parse(questionResult.getTimestamp(), formatter));
                                }
    // if (!references.isEmpty()) {
    // referenceService.saveBatch(references);
    // }
    // }
    // }
    // });
    // }
                                questionsToUpdate.add(question);
                                // 收集引用数据
                                List<Reference> references = questionResult.getReferences().stream()
                                        .map(ref -> {
                                            Reference reference = new Reference();
                                            reference.setQuestion_id(question.getQuestion_id());
                                            reference.setTitle(ref.getTitle());
                                            reference.setUrl(ref.getUrl());
                                            reference.setDomain(ref.getDomain());
                                            reference.setCreate_time(LocalDateTime.now());
                                            return reference;
                                        })
                                        .collect(Collectors.toList());
                                allReferences.addAll(references);
                            } else {
                                // log.warn("未找到匹配的问题,question: {}, keyword_id: {}",
                                // questionResult.getQuestion(), keyword.getKeyword_id());
                            }
                        } catch (Exception e) {
                            // log.error("处理问题结果失败,question: {}, error: {}",
                            // questionResult.getQuestion(), e.getMessage(), e);
                        }
                    }
                }
                // 4. 批量更新问题
                if (!questionsToUpdate.isEmpty()) {
                    questionService.updateBatchById(questionsToUpdate);
                    // log.info("成功批量更新 {} 个问题", questionsToUpdate.size());
                }
                // 5. 批量插入引用
                if (!allReferences.isEmpty()) {
                    // 分批处理,每批1000条记录,避免内存溢出
                    int batchSize = 1000;
                    for (int i = 0; i < allReferences.size(); i += batchSize) {
                        List<Reference> batch = allReferences.subList(
                                i, Math.min(i + batchSize, allReferences.size()));
                        referenceService.saveBatch(batch);
                    }
                    // log.info("成功批量插入 {} 条引用数据", allReferences.size());
                }
            } catch (Exception e) {
                // log.error("更新问题和引用数据失败,task_id: {}, error: {}",
                // result.getTask_id(), e.getMessage(), e);
                throw new RuntimeException("更新问题和引用数据失败", e);
            }
        });
    }
    @GetMapping("/tasks/all")
    @ApiOperation(value = "获取所有任务列表")
    public Mono<ResponseResult<TaskListResponse>> getAllTasks() {
        return webClient.get()
                .uri(baseUrl + "/tasks")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<ResponseResult<TaskListResponse>>() {
                })
                .onErrorResume(e -> {
                    return Mono.just(ResponseResult.error("获取任务列表失败: " + e.getMessage()));
                });
    }
    @GetMapping("/health")
    public Mono<HealthResponse> checkThirdPartyHealth() {
        return webClient.get()
                .uri(baseUrl + "/health") // 假设第三方健康检查接口路径为/health
                .retrieve()
                .bodyToMono(HealthResponse.class)
                .onErrorResume(e -> Mono.just(
                        new HealthResponse("unhealthy", null, "", e.getMessage())));
    }
}
src/main/java/com/linghu/controller/OrderController.java
@@ -4,16 +4,18 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.util.BeanUtil;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.entity.Order;
import com.linghu.model.entity.Orders;
import com.linghu.model.dto.OrderDto;
import com.linghu.service.OrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
@@ -21,8 +23,8 @@
 * 订单管理接口
 */
@RestController
@RequestMapping("/order")
@Api(value = "订单管理", tags = "订单管理")
@RequestMapping("/orders")
@Api(value = "订单管理接口", tags = "订单管理")
public class OrderController {
    @Autowired
@@ -32,9 +34,10 @@
     * 新增订单
     */
    @PostMapping
    public ResponseResult<Order> add(@RequestBody OrderDto orderDto) {
    @ApiOperation(value = "新增订单")
    public ResponseResult<Orders> add(@RequestBody OrderDto orderDto) {
        //将dto转entity
        Order order = new Order();
        Orders order = new Orders();
        BeanUtils.copyProperties(orderDto, order);
        if (order.getClient_name() == null || order.getClient_name().trim().isEmpty()) {
@@ -46,8 +49,8 @@
        String dateStr = dateFormat.format(new Date());
        // 查询当天订单数量
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(Order::getOrder_id, dateStr);
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(Orders::getOrder_id, dateStr);
        long count = orderService.count(queryWrapper);
        // 生成订单ID
@@ -57,12 +60,15 @@
        // 设置初始状态
        order.setStatus(1); // 待处理
        order.setDel_flag(0); // 未删除
        order.setCreate_time(new Date());
        order.setCreate_time(LocalDateTime.now());
        boolean save = orderService.save(order);
        //保存关键词
        boolean saveOrderWithKeywords = orderService.saveOrderWithKeywords(orderDto);
        boolean saveOrderWithKeywords = orderService.saveOrderWithKeywords(orderDto,order.getOrder_id());
        if (!saveOrderWithKeywords) {
            return ResponseResult.error("添加关键词失败");
        }
      
        if (orderService.save(order)) {
        if (save) {
            return ResponseResult.success(order);
        }
        return ResponseResult.error("添加订单失败");
@@ -72,26 +78,26 @@
     * 删除订单(逻辑删除)
     */
    @DeleteMapping("/{orderId}")
    @ApiOperation(value = "删除订单")
    public ResponseResult<Void> delete(@PathVariable String orderId) {
        Order order = orderService.getById(orderId);
        Orders order = orderService.getById(orderId);
        if (order == null) {
            return ResponseResult.error("订单不存在");
        }
        order.setDel_flag(1);
        order.setUpdate_time(new Date());
        order.setUpdate_time(LocalDateTime.now());
        boolean success = orderService.updateById(order);
        if (orderService.updateById(order)) {
            return ResponseResult.success();
        }
        return ResponseResult.error("删除订单失败");
        return success ? ResponseResult.success() : ResponseResult.error("删除订单失败");
    }
    /**
     * 更新订单
     */
    @PutMapping
    public ResponseResult<Void> update(@RequestBody Order order) {
    @ApiOperation(value = "更新订单")
    public ResponseResult<Void> update(@RequestBody Orders order) {
        if (order.getOrder_id() == null) {
            return ResponseResult.error("订单ID不能为空");
        }
@@ -99,12 +105,12 @@
            return ResponseResult.error("客户名称不能为空");
        }
        Order existingOrder = orderService.getById(order.getOrder_id());
        Orders existingOrder = orderService.getById(order.getOrder_id());
        if (existingOrder == null) {
            return ResponseResult.error("订单不存在");
        }
        order.setUpdate_time(new Date());
        order.setUpdate_time(LocalDateTime.now());
        if (orderService.updateById(order)) {
            return ResponseResult.success();
@@ -116,8 +122,9 @@
     * 根据ID查询订单
     */
    @GetMapping("/{orderId}")
    public ResponseResult<Order> getById(@PathVariable String orderId) {
        Order order = orderService.getById(orderId);
    @ApiOperation("根据ID查询订单")
    public ResponseResult<Orders> getById(@PathVariable String orderId) {
        Orders order = orderService.getById(orderId);
        if (order == null || order.getDel_flag() == 1) {
            return ResponseResult.error("订单不存在");
        }
@@ -128,32 +135,37 @@
     * 查询订单列表
     */
    @GetMapping
    public ResponseResult<List<Order>> list(
    @ApiOperation("查询订单列表")
    public ResponseResult<List<Orders>> list(
            @RequestParam(required = false) Integer pageNum,
            @RequestParam(required = false) Integer pageSize,
            @RequestParam(required = false) String clientName,
            @RequestParam(required = false) Integer status) {
            @RequestParam(required = false) Integer status,
            @RequestParam(required = false) String createTime) {
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getDel_flag, 0); // 只查询未删除的订单
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getDel_flag, 0); // 只查询未删除的订单
        // 添加查询条件
        if (clientName != null && !clientName.trim().isEmpty()) {
            queryWrapper.like(Order::getClient_name, clientName);
            queryWrapper.like(Orders::getClient_name, clientName);
        }
        if (status != null) {
            queryWrapper.eq(Order::getStatus, status);
            queryWrapper.eq(Orders::getStatus, status);
        }
        if (createTime != null) {
            queryWrapper.like(Orders::getCreate_time, createTime);
        }
        // 分页查询
        if (pageNum != null && pageSize != null) {
            Page<Order> pageInfo = new Page<>(pageNum, pageSize);
            Page<Order> result = orderService.page(pageInfo, queryWrapper);
            Page<Orders> pageInfo = new Page<>(pageNum, pageSize);
            Page<Orders> result = orderService.page(pageInfo, queryWrapper);
            return ResponseResult.success(result.getRecords());
        }
        // 不分页
        List<Order> list = orderService.list(queryWrapper);
        List<Orders> list = orderService.list(queryWrapper);
        return ResponseResult.success(list);
    }
}
src/main/java/com/linghu/controller/PlatformController.java
@@ -23,6 +23,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -57,6 +58,7 @@
    }
    @DeleteMapping("/{platformId}")
    @ApiOperation(value = "删除平台")
    public ResponseResult<Void> delete(@PathVariable Integer platformId) {
        boolean success = platformService.removeById(platformId);
        if (success) {
@@ -66,6 +68,7 @@
    }
    @PutMapping
    @ApiOperation(value = "更新平台")
    public ResponseResult<Void> update(@RequestBody Platform platform) {
        // 校验平台名称和域名不能为空
        if (!StringUtils.hasText(platform.getPlatform_name())) {
@@ -83,6 +86,7 @@
    }
    @GetMapping("/{platformId}")
    @ApiOperation("根据id获取平台")
    public ResponseResult<Platform> getById(@PathVariable Integer platformId) {
        Platform platform = platformService.getById(platformId);
        if (platform != null) {
@@ -92,6 +96,7 @@
    }
    @GetMapping("/list")
    @ApiOperation("查询平台列表,不传页数和大小就查全部")
    public ResponseResult<List<Platform>> list(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer pageSize) {
@@ -165,7 +170,7 @@
                platform.setType_id(typeByName.getType_id());
                // 设置创建时间(解决之前的数据库错误)
                platform.setCreate_time(new Date());
                platform.setCreate_time(LocalDateTime.now());
                platforms.add(platform);
            }
src/main/java/com/linghu/controller/QuestionController.java
@@ -3,14 +3,15 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.dto.KeywordDto;
import com.linghu.model.entity.Question;
import com.linghu.model.excel.KeywordExcel;
import com.linghu.service.QuestionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.linghu.model.dto.KeywordDto;
import java.util.Arrays;
import java.util.List;
@@ -47,42 +48,42 @@
        return ResponseResult.error("添加提问词失败");
    }
    // @DeleteMapping("/{questionId}")
    // public ResponseResult<Void> delete(@PathVariable Integer questionId) {
    // Question question = new Question();
    // question.setQuestion_id(questionId);
    // question.setDel_flag(1);
    // boolean success = questionService.updateById(question);
    @DeleteMapping("/{questionId}")
    @ApiOperation(value = "删除提问词")
    public ResponseResult<Void> delete(@PathVariable Integer questionId) {
        boolean success = questionService.removeById(questionId);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("删除提问词失败");
    }
    // @PutMapping
    // @Transactional
    // public ResponseResult<Void> update(@RequestBody List<Question> questions) {
    // boolean success = questionService.updateBatchById(questions);
    // // 不存在的问题id就新增
    // List<Question> newQuestions = questions.stream()
    // .filter(q -> q.getQuestion_id() == null)
    // .collect(Collectors.toList());
    // if (!newQuestions.isEmpty()) {
    // questionService.saveBatch(newQuestions);
    // }
    // if (success) {
    // return ResponseResult.success();
    // }
    // return ResponseResult.error("删除提问词失败");
    // return ResponseResult.error("更新提问词失败");
    // }
    @PutMapping
    @Transactional
    public ResponseResult<Void> update(@RequestBody List<Question> questions) {
        boolean success = questionService.updateBatchById(questions);
        // 不存在的问题id就新增
        List<Question> newQuestions = questions.stream()
                .filter(q -> q.getQuestion_id() == null)
                .collect(Collectors.toList());
        if (!newQuestions.isEmpty()) {
            questionService.saveBatch(newQuestions);
        }
    @ApiOperation(value = "修改提问词")
    public ResponseResult<Void> update(@RequestBody Question questions) {
        boolean success = questionService.updateById(questions);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("更新提问词失败");
    }
    @GetMapping("/{questionId}")
    public ResponseResult<Question> getById(@PathVariable Integer questionId) {
        Question question = questionService.getById(questionId);
        if (question != null) {
            return ResponseResult.success(question);
        }
        return ResponseResult.error("提问词不存在");
    }
    // @DeleteMapping("/batch")
@@ -103,8 +104,10 @@
    // }
    @GetMapping("/list")
    public ResponseResult<List<Question>> list() {
    @ApiOperation("根据关键词查询提问词列表")
    public ResponseResult<List<Question>> list(Integer keyword_id) {
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getKeyword_id, keyword_id);
        List<Question> list = questionService.list(queryWrapper);
        return ResponseResult.success(list);
src/main/java/com/linghu/controller/TypeController.java
@@ -33,6 +33,7 @@
    }
    @PostMapping("/batch")
    @ApiOperation(value = "批量添加类型")
    public ResponseResult<Void> batchAdd(@RequestBody List<Type> types) {
        types.forEach(type -> type.setDel_flag(0));
@@ -44,6 +45,7 @@
    }
    @DeleteMapping("/{typeId}")
    @ApiOperation(value = "删除类型")
    public ResponseResult<Void> delete(@PathVariable Integer typeId) {
        Type type = new Type();
        type.setType_id(typeId);
@@ -56,6 +58,7 @@
    }
    @PutMapping
    @ApiOperation(value = "更新类型")
    public ResponseResult<Void> update(@RequestBody Type type) {
        boolean success = typeService.updateById(type);
        if (success) {
@@ -65,6 +68,7 @@
    }
    @PutMapping("/batch")
    @ApiOperation(value = "批量更新类型")
    public ResponseResult<Void> batchUpdate(@RequestBody List<Type> types) {
        boolean success = typeService.updateBatchById(types);
        if (success) {
@@ -74,6 +78,7 @@
    }
    @GetMapping("/{typeId}")
    @ApiOperation(value = "根据ID查询类型")
    public ResponseResult<Type> getById(@PathVariable Integer typeId) {
        Type type = typeService.getById(typeId);
        if (type != null && type.getDel_flag() != 1) {
@@ -83,6 +88,7 @@
    }
    @DeleteMapping("/batch")
    @ApiOperation(value = "批量删除类型")
    public ResponseResult<Void> batchDelete(@RequestBody List<Integer> typeIds) {
        List<Type> types = typeIds.stream().map(id -> {
            Type type = new Type();
@@ -98,6 +104,7 @@
    }
    @GetMapping("/list")
    @ApiOperation(value = "查询类型列表,不传页数和大小就查全部")
    public ResponseResult<List<Type>> list(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer pageSize) {
src/main/java/com/linghu/listener/KeywordExcelListener.java
New file
@@ -0,0 +1,28 @@
package com.linghu.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.linghu.model.excel.KeywordExcel;
import java.util.ArrayList;
import java.util.List;
public class KeywordExcelListener implements ReadListener<KeywordExcel> {
    private final List<String> keywordList = new ArrayList<>();
    @Override
    public void invoke(KeywordExcel data, AnalysisContext context) {
        if (data.getKeyword_name() != null && !data.getKeyword_name().trim().isEmpty()) {
            keywordList.add(data.getKeyword_name().trim());
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 数据读取完成后的处理
    }
    public String getMergedKeywords() {
        return String.join("\n", keywordList);
    }
}
src/main/java/com/linghu/mapper/OrderMapper.java
@@ -1,6 +1,6 @@
package com.linghu.mapper;
import com.linghu.model.entity.Order;
import com.linghu.model.entity.Orders;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
@@ -9,7 +9,7 @@
* @createDate 2025-07-04 20:17:33
* @Entity com.linghu.model.entity.Order
*/
public interface OrderMapper extends BaseMapper<Order> {
public interface OrderMapper extends BaseMapper<Orders> {
}
src/main/java/com/linghu/model/dto/HealthResponse.java
New file
@@ -0,0 +1,22 @@
package com.linghu.model.dto;
import lombok.Data;
@Data
public class HealthResponse {
    private String status;
    private String timestamp;
    private String version;
    private String msg; // 自定义字段,用于封装错误信息
    public HealthResponse(String status, String timestamp, String version, String msg) {
        this.status = status;
        this.timestamp = timestamp;
        this.version = version;
        this.msg = msg;
    }
    public HealthResponse() {
        super();
    }
}
src/main/java/com/linghu/model/dto/KeywordDto.java
src/main/java/com/linghu/model/dto/OrderDto.java
@@ -1,6 +1,6 @@
package com.linghu.model.dto;
import com.linghu.model.entity.Order;
import com.linghu.model.entity.Orders;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -9,7 +9,7 @@
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class OrderDto extends Order {
public class OrderDto extends Orders {
    /**
     * 关键词列表,用换行符分隔
     */
src/main/java/com/linghu/model/dto/TaskListResponse.java
New file
@@ -0,0 +1,10 @@
package com.linghu.model.dto;
import java.util.Map;
import lombok.Data;
@Data
public class TaskListResponse {
    private Integer tasks_count;
    private Map<String, TaskStatusResponse> tasks;
}
src/main/java/com/linghu/model/dto/TaskResultResponse.java
@@ -37,7 +37,7 @@
        private String response;
        private String status;
        private Integer extracted_count;
        private Date timestamp;
        private String timestamp;
        private String error;
        private List<Reference> references;
    }
src/main/java/com/linghu/model/entity/Orders.java
File was renamed from src/main/java/com/linghu/model/entity/Order.java
@@ -3,17 +3,20 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
import java.time.LocalDateTime;
import lombok.Data;
/**
 * 
 * @TableName order
 */
@TableName(value ="order")
@TableName(value = "orders")
@Data
public class Order implements Serializable {
public class Orders implements Serializable {
    /**
     * 订单id,格式:日期-数量(202506100001)
     */
@@ -43,7 +46,8 @@
    /**
     * 创建时间
     */
    private Date create_time;
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
    private LocalDateTime create_time;
    /**
     * 
@@ -53,7 +57,8 @@
    /**
     * 
     */
    private Date update_time;
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
    private LocalDateTime update_time;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
@@ -69,15 +74,22 @@
        if (getClass() != that.getClass()) {
            return false;
        }
        Order other = (Order) that;
        return (this.getOrder_id() == null ? other.getOrder_id() == null : this.getOrder_id().equals(other.getOrder_id()))
            && (this.getClient_name() == null ? other.getClient_name() == null : this.getClient_name().equals(other.getClient_name()))
        Orders other = (Orders) that;
        return (this.getOrder_id() == null ? other.getOrder_id() == null
                : this.getOrder_id().equals(other.getOrder_id()))
                && (this.getClient_name() == null ? other.getClient_name() == null
                        : this.getClient_name().equals(other.getClient_name()))
            && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()))
            && (this.getDel_flag() == null ? other.getDel_flag() == null : this.getDel_flag().equals(other.getDel_flag()))
            && (this.getCreate_by() == null ? other.getCreate_by() == null : this.getCreate_by().equals(other.getCreate_by()))
            && (this.getCreate_time() == null ? other.getCreate_time() == null : this.getCreate_time().equals(other.getCreate_time()))
            && (this.getUpdate_by() == null ? other.getUpdate_by() == null : this.getUpdate_by().equals(other.getUpdate_by()))
            && (this.getUpdate_time() == null ? other.getUpdate_time() == null : this.getUpdate_time().equals(other.getUpdate_time()));
                && (this.getDel_flag() == null ? other.getDel_flag() == null
                        : this.getDel_flag().equals(other.getDel_flag()))
                && (this.getCreate_by() == null ? other.getCreate_by() == null
                        : this.getCreate_by().equals(other.getCreate_by()))
                && (this.getCreate_time() == null ? other.getCreate_time() == null
                        : this.getCreate_time().equals(other.getCreate_time()))
                && (this.getUpdate_by() == null ? other.getUpdate_by() == null
                        : this.getUpdate_by().equals(other.getUpdate_by()))
                && (this.getUpdate_time() == null ? other.getUpdate_time() == null
                        : this.getUpdate_time().equals(other.getUpdate_time()));
    }
    @Override
src/main/java/com/linghu/model/entity/Platform.java
@@ -5,8 +5,10 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
 * 
@@ -39,7 +41,8 @@
    /**
     * 
     */
    private Date create_time;
        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
        private LocalDateTime create_time;
    /**
     * 
@@ -49,7 +52,8 @@
    /**
     * 
     */
    private Date update_time;
        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
        private LocalDateTime update_time;
    /**
     * 
@@ -82,7 +86,8 @@
                        : this.getType_id().equals(other.getType_id()))
                && (this.getPlatform_name() == null ? other.getPlatform_name() == null
                        : this.getPlatform_name().equals(other.getPlatform_name()))
                && (this.getDomain() == null ? other.getDomain() == null : this.getDomain().equals(other.getDomain()))
                                && (this.getDomain() == null ? other.getDomain() == null
                                                : this.getDomain().equals(other.getDomain()))
                && (this.getCreate_time() == null ? other.getCreate_time() == null
                        : this.getCreate_time().equals(other.getCreate_time()))
                && (this.getCreate_by() == null ? other.getCreate_by() == null
src/main/java/com/linghu/model/entity/Question.java
@@ -5,8 +5,10 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
 * 
@@ -49,7 +51,8 @@
    /**
     * 采集时间
     */
    private Date timestamp;
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
    private LocalDateTime timestamp;
    /**
     * 提取的引用数量
@@ -81,15 +84,23 @@
            return false;
        }
        Question other = (Question) that;
        return (this.getQuestion_id() == null ? other.getQuestion_id() == null : this.getQuestion_id().equals(other.getQuestion_id()))
            && (this.getKeyword_id() == null ? other.getKeyword_id() == null : this.getKeyword_id().equals(other.getKeyword_id()))
            && (this.getQuestion() == null ? other.getQuestion() == null : this.getQuestion().equals(other.getQuestion()))
        return (this.getQuestion_id() == null ? other.getQuestion_id() == null
                : this.getQuestion_id().equals(other.getQuestion_id()))
                && (this.getKeyword_id() == null ? other.getKeyword_id() == null
                        : this.getKeyword_id().equals(other.getKeyword_id()))
                && (this.getQuestion() == null ? other.getQuestion() == null
                        : this.getQuestion().equals(other.getQuestion()))
            && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()))
            && (this.getUser_name() == null ? other.getUser_name() == null : this.getUser_name().equals(other.getUser_name()))
            && (this.getUser_email() == null ? other.getUser_email() == null : this.getUser_email().equals(other.getUser_email()))
            && (this.getTimestamp() == null ? other.getTimestamp() == null : this.getTimestamp().equals(other.getTimestamp()))
            && (this.getExtracted_count() == null ? other.getExtracted_count() == null : this.getExtracted_count().equals(other.getExtracted_count()))
            && (this.getResponse() == null ? other.getResponse() == null : this.getResponse().equals(other.getResponse()))
                && (this.getUser_name() == null ? other.getUser_name() == null
                        : this.getUser_name().equals(other.getUser_name()))
                && (this.getUser_email() == null ? other.getUser_email() == null
                        : this.getUser_email().equals(other.getUser_email()))
                && (this.getTimestamp() == null ? other.getTimestamp() == null
                        : this.getTimestamp().equals(other.getTimestamp()))
                && (this.getExtracted_count() == null ? other.getExtracted_count() == null
                        : this.getExtracted_count().equals(other.getExtracted_count()))
                && (this.getResponse() == null ? other.getResponse() == null
                        : this.getResponse().equals(other.getResponse()))
            && (this.getError() == null ? other.getError() == null : this.getError().equals(other.getError()));
    }
src/main/java/com/linghu/model/entity/Reference.java
@@ -4,8 +4,10 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
 * 
@@ -43,7 +45,8 @@
    /**
     * 创建时间
     */
    private Date create_time;
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS", timezone = "GMT+8")
    private LocalDateTime create_time;
    /**
     * 采集轮数
@@ -87,6 +90,10 @@
    }
    public Reference() {
        super();
    }
    @Override
    public boolean equals(Object that) {
        if (this == that) {
src/main/java/com/linghu/model/entity/Type.java
@@ -33,44 +33,44 @@
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
//    @Override
//    public boolean equals(Object that) {
//        if (this == that) {
//            return true;
//        }
//        if (that == null) {
//            return false;
//        }
//        if (getClass() != that.getClass()) {
//            return false;
//        }
//        Type other = (Type) that;
//        return (this.getType_id() == null ? other.getType_id() == null : this.getType_id().equals(other.getType_id()))
//            && (this.getType_name() == null ? other.getType_name() == null : this.getType_name().equals(other.getType_name()))
//            && (this.getDel_flag() == null ? other.getDel_flag() == null : this.getDel_flag().equals(other.getDel_flag()));
//    }
//
//    @Override
//    public int hashCode() {
//        final int prime = 31;
//        int result = 1;
//        result = prime * result + ((getType_id() == null) ? 0 : getType_id().hashCode());
//        result = prime * result + ((getType_name() == null) ? 0 : getType_name().hashCode());
//        result = prime * result + ((getDel_flag() == null) ? 0 : getDel_flag().hashCode());
//        return result;
//    }
//
//    @Override
//    public String toString() {
//        StringBuilder sb = new StringBuilder();
//        sb.append(getClass().getSimpleName());
//        sb.append(" [");
//        sb.append("Hash = ").append(hashCode());
//        sb.append(", type_id=").append(type_id);
//        sb.append(", type_name=").append(type_name);
//        sb.append(", del_flag=").append(del_flag);
//        sb.append(", serialVersionUID=").append(serialVersionUID);
//        sb.append("]");
//        return sb.toString();
//    }
    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        Type other = (Type) that;
        return (this.getType_id() == null ? other.getType_id() == null : this.getType_id().equals(other.getType_id()))
            && (this.getType_name() == null ? other.getType_name() == null : this.getType_name().equals(other.getType_name()))
            && (this.getDel_flag() == null ? other.getDel_flag() == null : this.getDel_flag().equals(other.getDel_flag()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getType_id() == null) ? 0 : getType_id().hashCode());
        result = prime * result + ((getType_name() == null) ? 0 : getType_name().hashCode());
        result = prime * result + ((getDel_flag() == null) ? 0 : getDel_flag().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", type_id=").append(type_id);
        sb.append(", type_name=").append(type_name);
        sb.append(", del_flag=").append(del_flag);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
src/main/java/com/linghu/model/excel/KeywordExcel.java
New file
@@ -0,0 +1,16 @@
package com.linghu.model.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import com.linghu.model.entity.Keyword;
@Data
public class KeywordExcel  {
    /**
     * 关键词列表,用换行符分隔
     */
    @ExcelProperty("关键词名称")
    private String keyword_name;
}
src/main/java/com/linghu/service/KeywordService.java
@@ -21,4 +21,5 @@
    ResponseResult<List<PlatformProportionVO>> getResultByTypeId(Integer keywordId, Integer questionId, Integer typeId);
    ResponseResult<List<ResultListVO>> getResultByPlatformId(Integer keywordId, Integer questionId, Integer platformId);
    List<Keyword> getKeywordsByOrderId(String orderId);
}
src/main/java/com/linghu/service/OrderService.java
@@ -1,6 +1,6 @@
package com.linghu.service;
import com.linghu.model.entity.Order;
import com.linghu.model.entity.Orders;
import com.linghu.model.dto.OrderDto;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -9,7 +9,7 @@
 * @description 针对表【order】的数据库操作Service
 * @createDate 2025-07-04 20:17:33
 */
public interface OrderService extends IService<Order> {
public interface OrderService extends IService<Orders> {
    boolean updateOrderWithKeywords(OrderDto orderDto, Integer currentStatus);
    /**
@@ -18,5 +18,5 @@
     * @param orderDto 订单数据传输对象
     * @return 是否保存成功
     */
    boolean saveOrderWithKeywords(OrderDto orderDto);
    boolean saveOrderWithKeywords(OrderDto orderDto,String order_id);
}
src/main/java/com/linghu/service/PlatformExcelService.java
@@ -16,6 +16,7 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -60,7 +61,7 @@
                platform.setPlatform_name(data.getPlatform_name());
                platform.setDomain(data.getDomain());
                platform.setType_id(type.getType_id());
                platform.setCreate_time(new Date());
                platform.setCreate_time(LocalDateTime.now());
                platform.setDel_flag(0);
                platforms.add(platform);
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java
@@ -1,5 +1,6 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.entity.Keyword;
@@ -7,6 +8,9 @@
import com.linghu.model.vo.KeywordStaticsListVO;
import com.linghu.service.KeywordService;
import com.linghu.mapper.KeywordMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -19,6 +23,8 @@
*/
@Service
public class KeywordServiceImpl extends ServiceImpl<KeywordMapper, Keyword> implements KeywordService{
    @Autowired
    private KeywordMapper keywordMapper;
    @Override
    public ResponseResult<KeywordStaticsListVO> statics(Integer keywordId, Integer questionId) {
@@ -70,8 +76,12 @@
    }
    @Override
    public List<Keyword> getKeywordsByOrderId(String orderId) {
        LambdaQueryWrapper<Keyword> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Keyword::getOrder_id, orderId);
        return keywordMapper.selectList(queryWrapper);
}
}
src/main/java/com/linghu/service/impl/OrderServiceImpl.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.dto.OrderDto;
import com.linghu.model.entity.Keyword;
import com.linghu.model.entity.Order;
import com.linghu.model.entity.Orders;
import com.linghu.service.KeywordService;
import com.linghu.service.OrderService;
import com.linghu.mapper.OrderMapper;
@@ -18,7 +18,7 @@
 * @createDate 2025-07-04 20:17:33
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders>
        implements OrderService {
    @Autowired
@@ -26,11 +26,8 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrderWithKeywords(OrderDto orderDto) {
        // 保存订单
        if (!this.save(orderDto)) {
            return false;
        }
    public boolean saveOrderWithKeywords(OrderDto orderDto,String order_id) {
        // 如果有关键词,则保存关键词
        if (StringUtils.hasText(orderDto.getKeywords())) {
@@ -38,7 +35,7 @@
            for (String keywordName : keywordArray) {
                if (StringUtils.hasText(keywordName)) {
                    Keyword keyword = new Keyword();
                    keyword.setOrder_id(orderDto.getOrder_id());
                    keyword.setOrder_id(order_id);
                    keyword.setKeyword_name(keywordName.trim());
                    keyword.setStatus("notSubmitted");
                    // keyword.setNum(1); // 默认采集轮数为1
src/main/resources/mapper/OrderMapper.xml
@@ -4,11 +4,11 @@
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.OrderMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Order">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Orders">
            <id property="order_id" column="order_id" jdbcType="VARCHAR"/>
            <result property="client_name" column="client_name" jdbcType="VARCHAR"/>
            <result property="status" column="status" jdbcType="TINYINT"/>
            <result property="del_flag" column="del_flag" jdbcType="TINYINT"/>
            <result property="status" column="status" jdbcType="INTEGER"/>
            <result property="del_flag" column="del_flag" jdbcType="INTEGER"/>
            <result property="create_by" column="create_by" jdbcType="VARCHAR"/>
            <result property="create_time" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="update_by" column="update_by" jdbcType="VARCHAR"/>
src/main/resources/schema.sql
File was deleted
src/main/resources/sql/keyword.sql
File was deleted
src/main/resources/sql/question.sql
File was deleted
src/main/resources/sql/reference.sql
File was deleted