guyue
5 天以前 e285517df2a3cb206282a41f958c80044422a552
基本增删改
17个文件已删除
41个文件已添加
18个文件已修改
3254 ■■■■ 已修改文件
pom.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/config/Swagger2Config.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/config/WebClientConfig.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/AuthController.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/CollectController.java 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/OrderController.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/PlatformController.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/QuestionController.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/TypeController.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/controller/baseController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/CallwordMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/KeywordMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/OrderMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/PlatformMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/PlatfromMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/QuestionMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/ReferenceMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/ResultMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/TypeMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/mapper/UserMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/KeywordDto.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/OrderDto.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/SearchTaskRequest.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/SearchTaskResponse.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/TaskCancelResponse.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/TaskResultResponse.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/dto/TaskStatusResponse.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Callword.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Keyword.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Order.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Platform.java 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Platfrom.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Question.java 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Reference.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Result.java 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/Type.java 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/entity/User.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/model/excel/PlatformExcel.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/CallwordService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/KeywordService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/OrderService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/PlatformExcelService.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/PlatformService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/PlatfromService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/QuestionService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/ReferenceService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/ResultService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/TypeService.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/UserService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/CallwordServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/OrderServiceImpl.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/PlatformServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/PlatfromServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/QuestionServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/ReferenceServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/ResultServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/TypeServiceImpl.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/service/impl/UserServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/linghu/utils/JwtUtils.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/CallwordMapper.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/KeywordMapper.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/OrderMapper.xml 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/PlatformMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/PlatfromMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/QuestionMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ReferenceMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ResultMapper.xml 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/TypeMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/UserMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/keywordMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | 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
@@ -52,6 +52,39 @@
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- EasyExcel依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.12.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.12.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId> <!-- 或 jjwt-gson -->
            <version>0.12.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
src/main/java/com/linghu/config/Swagger2Config.java
@@ -5,11 +5,22 @@
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
@EnableSwagger2  // 开启Swagger2
@@ -29,10 +40,58 @@
                .apis(RequestHandlerSelectors.basePackage("com.linghu.controller"))
                // 匹配所有路径
                .paths(PathSelectors.any())
                .build()
                // 添加安全方案配置
                .securitySchemes(Arrays.asList(securityScheme()))
                .securityContexts(Arrays.asList(securityContext()))
                // 添加全局参数(header中的token参数)
                .globalOperationParameters(globalParameters());
    }
    /**
     * 配置JWT安全方案
     */
    private ApiKey securityScheme() {
        return new ApiKey("BearerToken", "Authorization", "header");
    }
    /**
     * 配置安全上下文
     */
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .build();
    }
    /**
     * 默认的安全引用
     */
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        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() {
@@ -40,7 +99,6 @@
                .title("灵狐GEO系统 接口文档")  // 文档标题
                .description("使用 Swagger2 生成的API文档")  // 文档描述
                .version("1.0.0")  // 版本号
                .build();
    }
}
src/main/java/com/linghu/config/WebClientConfig.java
New file
@@ -0,0 +1,17 @@
package com.linghu.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
    @Value("${linghu.url}")
    private String baseUrl;
    @Bean
    public WebClient webClient() {
        return WebClient.create(baseUrl);
    }
}
src/main/java/com/linghu/controller/AuthController.java
New file
@@ -0,0 +1,46 @@
package com.linghu.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.linghu.model.entity.User;
import com.linghu.utils.JwtUtils;
@RestController
@RequestMapping("/auth")
public class AuthController {
    @Value("${jwt.secret}")
    private String secretKey;
    @PostMapping("/login")
    public ResponseEntity<?> externalLogin(
            @RequestBody User user) {
        // 生成JWT令牌
        JwtUtils jwtUtils = new JwtUtils(secretKey, 3600);
        String token = jwtUtils.generateToken(user);
        Map<String, String> response = new HashMap<>();
        response.put("token", token);
        // 返回JWT令牌
        return ResponseEntity.ok(response);
    }
    // 获取用户信息
    @PostMapping("/getUserInfo")
    public ResponseEntity<?> getUserInfo(@RequestParam String token) {
        // 解析JWT令牌,获取用户信息
        JwtUtils jwtUtils = new JwtUtils(secretKey, 3600);
        User user = jwtUtils.parseToken(token);
        // 返回用户信息
        return ResponseEntity.ok(user);
    }
}
src/main/java/com/linghu/controller/CollectController.java
New file
@@ -0,0 +1,295 @@
package com.linghu.controller;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.linghu.model.common.ResponseResult;
import com.linghu.model.dto.SearchTaskRequest;
import com.linghu.model.entity.Keyword;
import com.linghu.model.entity.Question;
import com.linghu.model.entity.User;
import com.linghu.service.KeywordService;
import com.linghu.service.QuestionService;
import com.linghu.service.ReferenceService;
import com.linghu.utils.JwtUtils;
import com.linghu.model.dto.SearchTaskResponse;
import com.linghu.model.dto.TaskStatusResponse;
import com.linghu.model.dto.TaskCancelResponse;
import io.jsonwebtoken.lang.Collections;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import reactor.core.publisher.Mono;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.HttpStatus;
import com.linghu.model.dto.TaskResultResponse;
import com.linghu.model.dto.TaskResultResponse.QuestionResult;
import com.linghu.model.dto.TaskResultResponse.UserResult;
import com.linghu.model.entity.Reference;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/collect")
@Api(value = "采集接口", tags = "采集管理")
public class CollectController {
    @Autowired
    private ReferenceService referenceService;
    @Value("${linghu.url}")
    private String baseUrl;
    @Autowired
    private WebClient webClient;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private KeywordService keywordService;
    @Autowired
    private QuestionService questionService;
    @PostMapping("/search")
    @ApiOperation(value = "开始采集")
    public Mono<ResponseResult<SearchTaskResponse>> createSearchTask(
            @RequestBody SearchTaskRequest searchTaskRequest,
            HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        User user = jwtUtils.parseToken(token);
        List<User> users = new ArrayList<>();
        users.add(user);
        searchTaskRequest.setUsers(users);
        return webClient.post()
                .uri(baseUrl + "/search")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(searchTaskRequest)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<ResponseResult<SearchTaskResponse>>() {
                })
                .flatMap(responseResult -> {
                    // 提取任务ID
                    SearchTaskResponse taskResponse = responseResult.getData();
                    if (taskResponse != null && taskResponse.getTask_id() != null) {
                        // 保存任务ID到关键词
                        LambdaUpdateWrapper<Keyword> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.eq(Keyword::getKeyword_id, searchTaskRequest.getKeyword_id());
                        updateWrapper.set(Keyword::getTask_id, taskResponse.getTask_id());
                        keywordService.update(updateWrapper);
                        // 可选:更新响应中的其他信息
                        // taskResponse.setMessage("任务已提交并保存,ID: " + taskResponse.getTaskId());
                    }
                    return Mono.just(responseResult);
                })
                .onErrorResume(e -> {
                    return Mono.just(ResponseResult.error("调用失败: " + e.getMessage()));
                });
    }
    @ApiOperation(value = "查询任务状态")
    @GetMapping("/status")
    public Mono<TaskStatusResponse> getTaskStatus(String taskId) {
        return webClient.get()
                .uri(baseUrl + "/tasks/" + taskId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError, response -> response.bodyToMono(String.class)
                        .flatMap(errorBody -> Mono.error(new RuntimeException("任务不存在: " + errorBody))))
                .bodyToMono(TaskStatusResponse.class)
                .flatMap(result -> {
                    TaskStatusResponse taskStatusResponse = result;
                    if (taskStatusResponse != null && taskStatusResponse.getStatus() != null) {
                        List<Question> updateQuestions = taskStatusResponse.getQuestions_status().stream()
                                .map(qs -> {
                                    Question question = new Question();
                                    question.setQuestion_id(qs.getQuestion_id());
                                    question.setStatus(qs.getStatus());
                                    return question;
                                }).collect(Collectors.toList());
                        questionService.updateBatchById(updateQuestions);
                    }
                    return Mono.just(result);
                });
    }
    @PostMapping("/cancel/{taskId}")
    @ApiOperation(value = "取消任务")
    public Mono<ResponseResult<TaskCancelResponse>> cancelTask(@PathVariable String taskId) {
        return webClient.post()
                .uri(baseUrl + "/tasks/" + taskId + "/cancel")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(Collections.emptyMap()) // 添加空请求体
                .retrieve()
                .onStatus(HttpStatus::isError, 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(TaskCancelResponse.class)
                .map(data -> ResponseResult.success(data))
                .onErrorResume(e -> {
                    if (e.getMessage().contains("任务不存在")) {
                        return Mono.just(ResponseResult.error(404, "任务不存在"));
                    } else if (e.getMessage().contains("无法取消")) {
                        return Mono.just(ResponseResult.error(400, "任务已完成,无法取消"));
                    }
                    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<>();
    // 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);
    // // 转换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()));
    // });
    // });
    // // 批量更新和插入
    // if (!updateQuestions.isEmpty()) {
    // questionService.updateBatchById(updateQuestions);
    // }
    // if (!references.isEmpty()) {
    // referenceService.saveBatch(references);
    // }
    // return Mono.just(ResponseResult.success(result));
    // })
    // .onErrorResume(e -> Mono.just(ResponseResult.error(e.getMessage())));
    // }
    // @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 -> {
    // return Mono.just(ResponseResult.error(e.getMessage()));
    // });
    // }
    // 更新问题和引用数据
    // 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);
    // // 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);
    // // 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 (!references.isEmpty()) {
    // referenceService.saveBatch(references);
    // }
    // }
    // }
    // });
    // }
}
src/main/java/com/linghu/controller/OrderController.java
New file
@@ -0,0 +1,157 @@
package com.linghu.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.dto.OrderDto;
import com.linghu.service.OrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
 * 订单管理接口
 */
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;
    /**
     * 新增订单
     */
    @PostMapping
    public ResponseResult<Order> add(@RequestBody OrderDto orderDto) {
        //将dto转entity
        Order order = new Order();
        BeanUtils.copyProperties(orderDto, order);
        if (order.getClient_name() == null || order.getClient_name().trim().isEmpty()) {
            return ResponseResult.error("客户名称不能为空");
        }
        // 生成订单ID:日期+当天的订单数量(如:202507060001)
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String dateStr = dateFormat.format(new Date());
        // 查询当天订单数量
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(Order::getOrder_id, dateStr);
        long count = orderService.count(queryWrapper);
        // 生成订单ID
        String orderId = String.format("%s%04d", dateStr, count + 1);
        order.setOrder_id(orderId);
        // 设置初始状态
        order.setStatus(1); // 待处理
        order.setDel_flag(0); // 未删除
        order.setCreate_time(new Date());
        //保存关键词
        boolean saveOrderWithKeywords = orderService.saveOrderWithKeywords(orderDto);
        if (orderService.save(order)) {
            return ResponseResult.success(order);
        }
        return ResponseResult.error("添加订单失败");
    }
    /**
     * 删除订单(逻辑删除)
     */
    @DeleteMapping("/{orderId}")
    public ResponseResult<Void> delete(@PathVariable String orderId) {
        Order order = orderService.getById(orderId);
        if (order == null) {
            return ResponseResult.error("订单不存在");
        }
        order.setDel_flag(1);
        order.setUpdate_time(new Date());
        if (orderService.updateById(order)) {
            return ResponseResult.success();
        }
        return ResponseResult.error("删除订单失败");
    }
    /**
     * 更新订单
     */
    @PutMapping
    public ResponseResult<Void> update(@RequestBody Order order) {
        if (order.getOrder_id() == null) {
            return ResponseResult.error("订单ID不能为空");
        }
        if (order.getClient_name() == null || order.getClient_name().trim().isEmpty()) {
            return ResponseResult.error("客户名称不能为空");
        }
        Order existingOrder = orderService.getById(order.getOrder_id());
        if (existingOrder == null) {
            return ResponseResult.error("订单不存在");
        }
        order.setUpdate_time(new Date());
        if (orderService.updateById(order)) {
            return ResponseResult.success();
        }
        return ResponseResult.error("更新订单失败");
    }
    /**
     * 根据ID查询订单
     */
    @GetMapping("/{orderId}")
    public ResponseResult<Order> getById(@PathVariable String orderId) {
        Order order = orderService.getById(orderId);
        if (order == null || order.getDel_flag() == 1) {
            return ResponseResult.error("订单不存在");
        }
        return ResponseResult.success(order);
    }
    /**
     * 查询订单列表
     */
    @GetMapping
    public ResponseResult<List<Order>> list(
            @RequestParam(required = false) Integer pageNum,
            @RequestParam(required = false) Integer pageSize,
            @RequestParam(required = false) String clientName,
            @RequestParam(required = false) Integer status) {
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getDel_flag, 0); // 只查询未删除的订单
        // 添加查询条件
        if (clientName != null && !clientName.trim().isEmpty()) {
            queryWrapper.like(Order::getClient_name, clientName);
        }
        if (status != null) {
            queryWrapper.eq(Order::getStatus, status);
        }
        // 分页查询
        if (pageNum != null && pageSize != null) {
            Page<Order> pageInfo = new Page<>(pageNum, pageSize);
            Page<Order> result = orderService.page(pageInfo, queryWrapper);
            return ResponseResult.success(result.getRecords());
        }
        // 不分页
        List<Order> list = orderService.list(queryWrapper);
        return ResponseResult.success(list);
    }
}
src/main/java/com/linghu/controller/PlatformController.java
New file
@@ -0,0 +1,192 @@
package com.linghu.controller;
import com.alibaba.excel.EasyExcel;
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.entity.Platform;
import com.linghu.model.entity.Type;
import com.linghu.model.excel.PlatformExcel;
import com.linghu.service.PlatformService;
import com.linghu.service.TypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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.Date;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/platform")
@Api(value = "平台相关接口", tags = "设置-平台")
public class PlatformController {
    @Autowired
    private PlatformService platformService;
    @Autowired
    private TypeService typeService;
    @PostMapping
    @ApiOperation(value = "添加平台")
    public ResponseResult<Platform> add(@RequestBody Platform platform) {
        // 校验平台名称和域名不能为空
        if (!StringUtils.hasText(platform.getPlatform_name())) {
            return ResponseResult.error("平台名称不能为空");
        }
        if (!StringUtils.hasText(platform.getDomain())) {
            return ResponseResult.error("平台域名不能为空");
        }
        boolean success = platformService.save(platform);
        if (success) {
            return ResponseResult.success(platform);
        }
        return ResponseResult.error("添加平台失败");
    }
    @DeleteMapping("/{platformId}")
    public ResponseResult<Void> delete(@PathVariable Integer platformId) {
        boolean success = platformService.removeById(platformId);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("删除平台失败");
    }
    @PutMapping
    public ResponseResult<Void> update(@RequestBody Platform platform) {
        // 校验平台名称和域名不能为空
        if (!StringUtils.hasText(platform.getPlatform_name())) {
            return ResponseResult.error("平台名称不能为空");
        }
        if (!StringUtils.hasText(platform.getDomain())) {
            return ResponseResult.error("平台域名不能为空");
        }
        boolean success = platformService.updateById(platform);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("更新平台失败");
    }
    @GetMapping("/{platformId}")
    public ResponseResult<Platform> getById(@PathVariable Integer platformId) {
        Platform platform = platformService.getById(platformId);
        if (platform != null) {
            return ResponseResult.success(platform);
        }
        return ResponseResult.error("平台不存在");
    }
    @GetMapping("/list")
    public ResponseResult<List<Platform>> list(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer pageSize) {
        if (page != null && pageSize != null) {
            Page<Platform> pageInfo = new Page<>(page, pageSize);
            Page<Platform> result = platformService.page(pageInfo);
            return ResponseResult.success(result.getRecords());
        } else {
            List<Platform> list = platformService.list();
            return ResponseResult.success(list);
        }
    }
    @GetMapping("/download")
    @ApiOperation("下载平台模板")
    public ResponseEntity<byte[]> downloadTemplate() throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        EasyExcel.write(out, PlatformExcel.class).sheet("平台模板").doWrite(new ArrayList<>());
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=platform_template.xlsx")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(out.toByteArray());
    }
    @PostMapping("/import")
    @ApiOperation("导入平台数据")
    public ResponseResult<String> importPlatforms(@RequestParam("file") MultipartFile file) {
        try {
            // 检查文件是否为空
            if (file.isEmpty()) {
                return ResponseResult.error("上传文件不能为空");
            }
            // 读取Excel数据
            List<PlatformExcel> excelList = EasyExcel.read(file.getInputStream())
                    .head(PlatformExcel.class)
                    .sheet()
                    .doReadSync();
            // 数据转换与验证
            List<Platform> platforms = new ArrayList<>();
            List<String> errorMessages = new ArrayList<>();
            for (PlatformExcel excel : excelList) {
                // 检查必要字段
                if (!StringUtils.hasText(excel.getPlatform_name())) {
                    errorMessages.add("平台名称不能为空");
                    continue;
                }
                if (!StringUtils.hasText(excel.getType_name())) {
                    errorMessages.add("平台类型不能为空");
                    continue;
                }
                if (!StringUtils.hasText(excel.getDomain())) {
                    errorMessages.add("平台域名不能为空");
                    continue;
                }
                // 查找类型
                Type typeByName = typeService.getTypeByName(excel.getType_name());
                if (typeByName == null) {
                    errorMessages.add("未知的平台类型: " + excel.getType_name());
                    continue;
                }
                // 构建平台对象
                Platform platform = new Platform();
                platform.setPlatform_name(excel.getPlatform_name());
                platform.setDomain(excel.getDomain());
                platform.setType_id(typeByName.getType_id());
                // 设置创建时间(解决之前的数据库错误)
                platform.setCreate_time(new Date());
                platforms.add(platform);
            }
            // 处理错误
            if (!errorMessages.isEmpty()) {
                return ResponseResult.error("数据验证失败: " + String.join("; ", errorMessages));
            }
            // 批量保存
            if (!platforms.isEmpty()) {
                platformService.saveBatch(platforms);
                return ResponseResult.success("成功导入" + platforms.size() + "条数据");
            } else {
                return ResponseResult.error("没有有效数据可导入");
            }
        } catch (Exception e) {
            // 记录详细异常信息
            return ResponseResult.error("文件解析失败:" + e.getMessage());
        }
    }
}
src/main/java/com/linghu/controller/QuestionController.java
New file
@@ -0,0 +1,112 @@
package com.linghu.controller;
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.entity.Question;
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;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/question")
@Api(value = "提问词相关接口", tags = "设置-提问词")
public class QuestionController {
    @Autowired
    private QuestionService questionService;
    @PostMapping
    @ApiOperation(value = "添加提问词")
    @Transactional
    public ResponseResult<List<Question>> add(@RequestBody KeywordDto keywordDto) {
        List<Question> questionList = Arrays.stream(keywordDto.getQuestions().split("\\n"))
                .filter(q -> !q.trim().isEmpty())
                .map(q -> {
                    Question question = new Question();
                    question.setKeyword_id(keywordDto.getKeyword_id());
                    question.setQuestion(q.trim());
                    question.setStatus("pending");
                    return question;
                }).collect(Collectors.toList());
        boolean success = questionService.saveBatch(questionList);
        if (success) {
            return ResponseResult.success(questionList);
        }
        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);
    // 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("更新提问词失败");
    }
    @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")
    // @Transactional
    // public ResponseResult<Void> batchDelete(@RequestBody List<Integer>
    // questionIds) {
    // List<Question> questions = questionIds.stream().map(id -> {
    // Question question = new Question();
    // question.setQuestion_id(id);
    // return question;
    // }).collect(Collectors.toList());
    // boolean success = questionService.updateBatchById(questions);
    // if (success) {
    // return ResponseResult.success();
    // }
    // return ResponseResult.error("批量删除提问词失败");
    // }
    @GetMapping("/list")
    public ResponseResult<List<Question>> list() {
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        List<Question> list = questionService.list(queryWrapper);
        return ResponseResult.success(list);
    }
}
src/main/java/com/linghu/controller/TypeController.java
@@ -10,6 +10,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@RestController
@@ -23,7 +24,7 @@
    @PostMapping
    @ApiOperation(value = "添加类型")
    public ResponseResult<Type> add(@RequestBody Type type) {
        type.setDelFlag(0);
        type.setDel_flag(0);
        boolean success = typeService.save(type);
        if (success) {
            return ResponseResult.success(type);
@@ -33,6 +34,8 @@
    @PostMapping("/batch")
    public ResponseResult<Void> batchAdd(@RequestBody List<Type> types) {
        types.forEach(type -> type.setDel_flag(0));
        boolean success = typeService.saveBatch(types);
        if (success) {
            return ResponseResult.success();
@@ -43,22 +46,13 @@
    @DeleteMapping("/{typeId}")
    public ResponseResult<Void> delete(@PathVariable Integer typeId) {
        Type type = new Type();
        type.setTypeId(typeId);
        type.setDelFlag(1);
        type.setType_id(typeId);
        type.setDel_flag(1);
        boolean success = typeService.updateById(type);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("删除类型失败");
    }
    @DeleteMapping("/batch")
    public ResponseResult<Void> batchDelete(@RequestBody List<Integer> typeIds) {
        boolean success = typeService.removeBatchByIds(typeIds);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("批量删除类型失败");
    }
    @PutMapping
@@ -82,29 +76,41 @@
    @GetMapping("/{typeId}")
    public ResponseResult<Type> getById(@PathVariable Integer typeId) {
        Type type = typeService.getById(typeId);
        if (type != null && type.getDelFlag() != 1) {
        if (type != null && type.getDel_flag() != 1) {
            return ResponseResult.success(type);
        }
        return ResponseResult.error("类型不存在");
    }
    @GetMapping("/list")
    public ResponseResult<?> list(
            @RequestParam(required = false) Integer pageNum,
            @RequestParam(required = false) Integer pageSize,
            @RequestParam(required = false) String typeName) {
        // 不传分页参数则返回全部数据
        if (pageNum == null || pageSize == null) {
            List<Type> types = typeService.listAllAvailable();
            return ResponseResult.success(types);
    @DeleteMapping("/batch")
    public ResponseResult<Void> batchDelete(@RequestBody List<Integer> typeIds) {
        List<Type> types = typeIds.stream().map(id -> {
            Type type = new Type();
            type.setType_id(id);
            type.setDel_flag(1);
            return type;
        }).collect(java.util.stream.Collectors.toList());
        boolean success = typeService.updateBatchById(types);
        if (success) {
            return ResponseResult.success();
        }
        return ResponseResult.error("批量删除类型失败");
        }
    @GetMapping("/list")
    public ResponseResult<List<Type>> list(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer pageSize) {
        LambdaQueryWrapper<Type> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Type::getDelFlag, 0)
                .like(typeName != null, Type::getTypeName, typeName);
        queryWrapper.eq(Type::getDel_flag, 0);
        Page<Type> page = typeService.page(new Page<>(pageNum, pageSize), queryWrapper);
        return ResponseResult.success(page);
        if (page != null && pageSize != null) {
            Page<Type> pageInfo = new Page<>(page, pageSize);
            Page<Type> result = typeService.page(pageInfo, queryWrapper);
            return ResponseResult.success(result.getRecords());
        } else {
            List<Type> list = typeService.list(queryWrapper);
            return ResponseResult.success(list);
        }
    }
}
src/main/java/com/linghu/controller/baseController.java
File was deleted
src/main/java/com/linghu/mapper/CallwordMapper.java
File was deleted
src/main/java/com/linghu/mapper/KeywordMapper.java
@@ -6,8 +6,8 @@
/**
* @author xy
* @description 针对表【keyword】的数据库操作Mapper
* @createDate 2025-07-02 16:32:19
* @Entity generator.entity.Keyword
* @createDate 2025-07-04 20:17:33
* @Entity com.linghu.model.entity.Keyword
*/
public interface KeywordMapper extends BaseMapper<Keyword> {
src/main/java/com/linghu/mapper/OrderMapper.java
@@ -6,8 +6,8 @@
/**
* @author xy
* @description 针对表【order】的数据库操作Mapper
* @createDate 2025-07-02 16:32:19
* @Entity generator.entity.Order
* @createDate 2025-07-04 20:17:33
* @Entity com.linghu.model.entity.Order
*/
public interface OrderMapper extends BaseMapper<Order> {
src/main/java/com/linghu/mapper/PlatformMapper.java
New file
@@ -0,0 +1,14 @@
package com.linghu.mapper;
import com.linghu.model.entity.Platform;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
 * @author xy
 * @description 针对表【platfrom】的数据库操作Mapper
 * @createDate 2025-07-04 20:17:33
 * @Entity com.linghu.model.entity.Platfrom
 */
public interface PlatformMapper extends BaseMapper<Platform> {
}
src/main/java/com/linghu/mapper/PlatfromMapper.java
File was deleted
src/main/java/com/linghu/mapper/QuestionMapper.java
New file
@@ -0,0 +1,18 @@
package com.linghu.mapper;
import com.linghu.model.entity.Question;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author xy
* @description 针对表【question】的数据库操作Mapper
* @createDate 2025-07-04 20:17:33
* @Entity com.linghu.model.entity.Question
*/
public interface QuestionMapper extends BaseMapper<Question> {
}
src/main/java/com/linghu/mapper/ReferenceMapper.java
New file
@@ -0,0 +1,18 @@
package com.linghu.mapper;
import com.linghu.model.entity.Reference;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author xy
* @description 针对表【reference】的数据库操作Mapper
* @createDate 2025-07-04 20:17:33
* @Entity com.linghu.model.entity.Reference
*/
public interface ReferenceMapper extends BaseMapper<Reference> {
}
src/main/java/com/linghu/mapper/ResultMapper.java
File was deleted
src/main/java/com/linghu/mapper/TypeMapper.java
@@ -6,8 +6,8 @@
/**
* @author xy
* @description 针对表【type】的数据库操作Mapper
* @createDate 2025-07-02 16:32:19
* @Entity generator.entity.Type
* @createDate 2025-07-04 20:10:31
* @Entity com.linghu.model.entity.Type
*/
public interface TypeMapper extends BaseMapper<Type> {
src/main/java/com/linghu/mapper/UserMapper.java
New file
@@ -0,0 +1,18 @@
package com.linghu.mapper;
import com.linghu.model.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author xy
* @description 针对表【user】的数据库操作Mapper
* @createDate 2025-07-07 10:26:00
* @Entity com.linghu.model.entity.User
*/
public interface UserMapper extends BaseMapper<User> {
}
src/main/java/com/linghu/model/dto/KeywordDto.java
New file
@@ -0,0 +1,14 @@
package com.linghu.model.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import com.linghu.model.entity.Keyword;
@EqualsAndHashCode(callSuper = true)
@Data
public class KeywordDto extends Keyword {
    /**
     * 提问词列表,用换行符分隔
     */
    private String questions;
}
src/main/java/com/linghu/model/dto/OrderDto.java
New file
@@ -0,0 +1,17 @@
package com.linghu.model.dto;
import com.linghu.model.entity.Order;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 订单数据传输对象,扩展Order实体
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class OrderDto extends Order {
    /**
     * 关键词列表,用换行符分隔
     */
    private String keywords;
}
src/main/java/com/linghu/model/dto/SearchTaskRequest.java
New file
@@ -0,0 +1,37 @@
package com.linghu.model.dto;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.*;
import com.linghu.model.entity.User;
import java.util.List;
@Data
public class SearchTaskRequest {
    @Valid
    @NotEmpty(message = "用户列表不能为空")
    private List<User> users;
    @NotEmpty(message = "问题列表不能为空")
    private List<String> questions;
    @Valid
    private ConfigDTO config;
    private Boolean save_to_database = false;
    private String webhook_url;
    private Integer keyword_id;
    @Data
    public static class ConfigDTO {
        @Min(value = 1, message = "最大并发用户数至少为1")
        private Integer max_concurrent_users = 3;
        @Min(value = 0, message = "用户启动延迟不能为负数")
        private Integer user_start_delay = 1;
        private Boolean headless = true;
    }
}
src/main/java/com/linghu/model/dto/SearchTaskResponse.java
New file
@@ -0,0 +1,11 @@
package com.linghu.model.dto;
import lombok.Data;
@Data
public class SearchTaskResponse {
    private String task_id;
    private String status;
    private String message;
}
src/main/java/com/linghu/model/dto/TaskCancelResponse.java
New file
@@ -0,0 +1,16 @@
package com.linghu.model.dto;
import lombok.Data;
@Data
public class TaskCancelResponse {
    private String task_id;
    private String status;
    private String message;
    public TaskCancelResponse(String taskId, String status, String message) {
        this.task_id = taskId;
        this.status = status;
        this.message = message;
    }
}
src/main/java/com/linghu/model/dto/TaskResultResponse.java
New file
@@ -0,0 +1,53 @@
package com.linghu.model.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.util.Date;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TaskResultResponse {
    private String task_id;
    private Integer total_users;
    private Integer total_questions;
    private Integer successful_users;
    private Date total_duration;
    private List<UserResult> results;
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class UserResult {
        private String user_name;
        private String user_email;
        private String status;
        private List<QuestionResult> questions_results;
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class QuestionResult {
        private String question;
        private String response;
        private String status;
        private Integer extracted_count;
        private Date timestamp;
        private String error;
        private List<Reference> references;
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Reference {
        private String title;
        private String url;
        private String domain;
    }
}
src/main/java/com/linghu/model/dto/TaskStatusResponse.java
New file
@@ -0,0 +1,34 @@
package com.linghu.model.dto;
import java.util.List;
import lombok.Data;
@Data
public class TaskStatusResponse {
    private String task_id;
    private String status;
    private double progress;
    private String message;
    private String start_time;
    private String end_time;
    private int users_count;
    private int questions_count;
    private boolean save_to_database;
    private String webhook_url;
    private List<QuestionStatus> questions_status;
    @Data
    public static class QuestionStatus {
        private int question_id;
        private String question;
        private String user_name;
        private String user_email;
        private String status;
        private String timestamp;
        private int extracted_count;
        // Getters and Setters
    }
}
src/main/java/com/linghu/model/entity/Callword.java
File was deleted
src/main/java/com/linghu/model/entity/Keyword.java
@@ -18,22 +18,32 @@
     * 关键词
     */
    @TableId(type = IdType.AUTO)
    private Integer keywordId;
    private Integer keyword_id;
    /**
     * 关联订单id
     */
    private String orderId;
    private String order_id;
    /**
     * 关键词名称
     */
    private String keywordName;
    private String keyword_name;
    /**
     * 采集轮数
     */
    private Integer num;
    /**
     * 任务唯一标识符
     */
    private String task_id;
    /**
     * 任务状态(notSubmitted:待处理;submitted:已提交 ;  )
     */
    private String status;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
@@ -50,20 +60,24 @@
            return false;
        }
        Keyword other = (Keyword) that;
        return (this.getKeywordId() == null ? other.getKeywordId() == null : this.getKeywordId().equals(other.getKeywordId()))
            && (this.getOrderId() == null ? other.getOrderId() == null : this.getOrderId().equals(other.getOrderId()))
            && (this.getKeywordName() == null ? other.getKeywordName() == null : this.getKeywordName().equals(other.getKeywordName()))
            && (this.getNum() == null ? other.getNum() == null : this.getNum().equals(other.getNum()));
        return (this.getKeyword_id() == null ? other.getKeyword_id() == null : this.getKeyword_id().equals(other.getKeyword_id()))
            && (this.getOrder_id() == null ? other.getOrder_id() == null : this.getOrder_id().equals(other.getOrder_id()))
            && (this.getKeyword_name() == null ? other.getKeyword_name() == null : this.getKeyword_name().equals(other.getKeyword_name()))
            && (this.getNum() == null ? other.getNum() == null : this.getNum().equals(other.getNum()))
            && (this.getTask_id() == null ? other.getTask_id() == null : this.getTask_id().equals(other.getTask_id()))
            && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getKeywordId() == null) ? 0 : getKeywordId().hashCode());
        result = prime * result + ((getOrderId() == null) ? 0 : getOrderId().hashCode());
        result = prime * result + ((getKeywordName() == null) ? 0 : getKeywordName().hashCode());
        result = prime * result + ((getKeyword_id() == null) ? 0 : getKeyword_id().hashCode());
        result = prime * result + ((getOrder_id() == null) ? 0 : getOrder_id().hashCode());
        result = prime * result + ((getKeyword_name() == null) ? 0 : getKeyword_name().hashCode());
        result = prime * result + ((getNum() == null) ? 0 : getNum().hashCode());
        result = prime * result + ((getTask_id() == null) ? 0 : getTask_id().hashCode());
        result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
        return result;
    }
@@ -73,10 +87,12 @@
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", keywordId=").append(keywordId);
        sb.append(", orderId=").append(orderId);
        sb.append(", keywordName=").append(keywordName);
        sb.append(", keyword_id=").append(keyword_id);
        sb.append(", order_id=").append(order_id);
        sb.append(", keyword_name=").append(keyword_name);
        sb.append(", num=").append(num);
        sb.append(", task_id=").append(task_id);
        sb.append(", status=").append(status);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
src/main/java/com/linghu/model/entity/Order.java
@@ -1,6 +1,5 @@
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;
@@ -16,15 +15,15 @@
@Data
public class Order implements Serializable {
    /**
     * 订单id,格式:日期-数量
     * 订单id,格式:日期-数量(202506100001)
     */
    @TableId
    private String orderId;
    private String order_id;
    /**
     * 客户名称
     */
    private String clientName;
    private String client_name;
    /**
     * 状态 1-待处理,2-执行中,3-已完成
@@ -34,27 +33,27 @@
    /**
     * 0-未删除 1-已删除
     */
    private Integer delFlag;
    private Integer del_flag;
    /**
     * 提交人
     */
    private String createBy;
    private String create_by;
    /**
     * 创建时间
     */
    private Date createTime;
    private Date create_time;
    /**
     * 
     */
    private String updateBy;
    private String update_by;
    /**
     * 
     */
    private Date updateTime;
    private Date update_time;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
@@ -71,28 +70,28 @@
            return false;
        }
        Order other = (Order) that;
        return (this.getOrderId() == null ? other.getOrderId() == null : this.getOrderId().equals(other.getOrderId()))
            && (this.getClientName() == null ? other.getClientName() == null : this.getClientName().equals(other.getClientName()))
        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.getDelFlag() == null ? other.getDelFlag() == null : this.getDelFlag().equals(other.getDelFlag()))
            && (this.getCreateBy() == null ? other.getCreateBy() == null : this.getCreateBy().equals(other.getCreateBy()))
            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
            && (this.getUpdateBy() == null ? other.getUpdateBy() == null : this.getUpdateBy().equals(other.getUpdateBy()))
            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
            && (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
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getOrderId() == null) ? 0 : getOrderId().hashCode());
        result = prime * result + ((getClientName() == null) ? 0 : getClientName().hashCode());
        result = prime * result + ((getOrder_id() == null) ? 0 : getOrder_id().hashCode());
        result = prime * result + ((getClient_name() == null) ? 0 : getClient_name().hashCode());
        result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
        result = prime * result + ((getDelFlag() == null) ? 0 : getDelFlag().hashCode());
        result = prime * result + ((getCreateBy() == null) ? 0 : getCreateBy().hashCode());
        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
        result = prime * result + ((getUpdateBy() == null) ? 0 : getUpdateBy().hashCode());
        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
        result = prime * result + ((getDel_flag() == null) ? 0 : getDel_flag().hashCode());
        result = prime * result + ((getCreate_by() == null) ? 0 : getCreate_by().hashCode());
        result = prime * result + ((getCreate_time() == null) ? 0 : getCreate_time().hashCode());
        result = prime * result + ((getUpdate_by() == null) ? 0 : getUpdate_by().hashCode());
        result = prime * result + ((getUpdate_time() == null) ? 0 : getUpdate_time().hashCode());
        return result;
    }
@@ -102,14 +101,14 @@
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", orderId=").append(orderId);
        sb.append(", clientName=").append(clientName);
        sb.append(", order_id=").append(order_id);
        sb.append(", client_name=").append(client_name);
        sb.append(", status=").append(status);
        sb.append(", delFlag=").append(delFlag);
        sb.append(", createBy=").append(createBy);
        sb.append(", createTime=").append(createTime);
        sb.append(", updateBy=").append(updateBy);
        sb.append(", updateTime=").append(updateTime);
        sb.append(", del_flag=").append(del_flag);
        sb.append(", create_by=").append(create_by);
        sb.append(", create_time=").append(create_time);
        sb.append(", update_by=").append(update_by);
        sb.append(", update_time=").append(update_time);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
src/main/java/com/linghu/model/entity/Platform.java
New file
@@ -0,0 +1,133 @@
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;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
 *
 * @TableName platfrom
 */
@TableName(value = "platform")
@Data
public class Platform implements Serializable {
    /**
     * 平台id
     */
    @TableId(type = IdType.AUTO)
    private Integer platform_id;
    /**
     * 类型id
     */
    private Integer type_id;
    /**
     * 平台名称
     */
    private String platform_name;
    /**
     * 平台域名
     */
    private String domain;
    /**
     *
     */
    private Date create_time;
    /**
     *
     */
    private String create_by;
    /**
     *
     */
    private Date update_time;
    /**
     *
     */
    private String update_by;
    /**
     * 0-未删除,1-已删除
     */
    private Integer del_flag;
    @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;
        }
        Platform other = (Platform) that;
        return (this.getPlatform_id() == null ? other.getPlatform_id() == null
                : this.getPlatform_id().equals(other.getPlatform_id()))
                && (this.getType_id() == null ? other.getType_id() == null
                        : 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.getCreate_time() == null ? other.getCreate_time() == null
                        : this.getCreate_time().equals(other.getCreate_time()))
                && (this.getCreate_by() == null ? other.getCreate_by() == null
                        : this.getCreate_by().equals(other.getCreate_by()))
                && (this.getUpdate_time() == null ? other.getUpdate_time() == null
                        : this.getUpdate_time().equals(other.getUpdate_time()))
                && (this.getUpdate_by() == null ? other.getUpdate_by() == null
                        : this.getUpdate_by().equals(other.getUpdate_by()))
                && (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 + ((getPlatform_id() == null) ? 0 : getPlatform_id().hashCode());
        result = prime * result + ((getType_id() == null) ? 0 : getType_id().hashCode());
        result = prime * result + ((getPlatform_name() == null) ? 0 : getPlatform_name().hashCode());
        result = prime * result + ((getDomain() == null) ? 0 : getDomain().hashCode());
        result = prime * result + ((getCreate_time() == null) ? 0 : getCreate_time().hashCode());
        result = prime * result + ((getCreate_by() == null) ? 0 : getCreate_by().hashCode());
        result = prime * result + ((getUpdate_time() == null) ? 0 : getUpdate_time().hashCode());
        result = prime * result + ((getUpdate_by() == null) ? 0 : getUpdate_by().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(", platform_id=").append(platform_id);
        sb.append(", type_id=").append(type_id);
        sb.append(", platform_name=").append(platform_name);
        sb.append(", domain=").append(domain);
        sb.append(", create_time=").append(create_time);
        sb.append(", create_by=").append(create_by);
        sb.append(", update_time=").append(update_time);
        sb.append(", update_by=").append(update_by);
        sb.append(", del_flag=").append(del_flag);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
src/main/java/com/linghu/model/entity/Platfrom.java
File was deleted
src/main/java/com/linghu/model/entity/Question.java
New file
@@ -0,0 +1,133 @@
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;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
 *
 * @TableName question
 */
@TableName(value ="question")
@Data
public class Question implements Serializable {
    /**
     * 提问词id
     */
    @TableId(type = IdType.AUTO)
    private Integer question_id;
    /**
     * 关键词id
     */
    private Integer keyword_id;
    /**
     * 提问词
     */
    private String question;
    /**
     * 提示词状态,(pending:待处理;processing:处理中 ; success:处理成功;failed:处理失败  )
     */
    private String status;
    /**
     * 提交人
     */
    private String user_name;
    /**
     * 提交人邮箱
     */
    private String user_email;
    /**
     * 采集时间
     */
    private Date timestamp;
    /**
     * 提取的引用数量
     */
    private Integer extracted_count;
    /**
     * AI回复内容
     */
    private String response;
    /**
     * 错误信息
     */
    private String error;
    @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;
        }
        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()))
            && (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.getError() == null ? other.getError() == null : this.getError().equals(other.getError()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getQuestion_id() == null) ? 0 : getQuestion_id().hashCode());
        result = prime * result + ((getKeyword_id() == null) ? 0 : getKeyword_id().hashCode());
        result = prime * result + ((getQuestion() == null) ? 0 : getQuestion().hashCode());
        result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
        result = prime * result + ((getUser_name() == null) ? 0 : getUser_name().hashCode());
        result = prime * result + ((getUser_email() == null) ? 0 : getUser_email().hashCode());
        result = prime * result + ((getTimestamp() == null) ? 0 : getTimestamp().hashCode());
        result = prime * result + ((getExtracted_count() == null) ? 0 : getExtracted_count().hashCode());
        result = prime * result + ((getResponse() == null) ? 0 : getResponse().hashCode());
        result = prime * result + ((getError() == null) ? 0 : getError().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", question_id=").append(question_id);
        sb.append(", keyword_id=").append(keyword_id);
        sb.append(", question=").append(question);
        sb.append(", status=").append(status);
        sb.append(", user_name=").append(user_name);
        sb.append(", user_email=").append(user_email);
        sb.append(", timestamp=").append(timestamp);
        sb.append(", extracted_count=").append(extracted_count);
        sb.append(", response=").append(response);
        sb.append(", error=").append(error);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
src/main/java/com/linghu/model/entity/Reference.java
New file
@@ -0,0 +1,165 @@
package com.linghu.model.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
 *
 * @TableName reference
 */
@TableName(value = "reference")
@Data
public class Reference implements Serializable {
    /**
     * 结果id
     */
    @TableId
    private Integer reference_id;
    /**
     * 类型id
     */
    private Integer type_id;
    /**
     * 平台id
     */
    private Integer platform_id;
    /**
     * 标题
     */
    private String title;
    /**
     * 重复次数
     */
    private Integer repetition_num;
    /**
     * 创建时间
     */
    private Date create_time;
    /**
     * 采集轮数
     */
    private Integer num;
    /**
     * 来源url
     */
    private String url;
    /**
     * 域名
     */
    private String domain;
    /**
     * 任务id
     */
    private String task_id;
    /**
     * 关键词id
     */
    private Integer keyword_id;
    /**
     * 问题id
     */
    private Integer question_id;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    public Reference(Integer question_id, String title, String url, String domain, Integer keyword_id, String task_id) {
        this.question_id = question_id;
        this.title = title;
        this.url = url;
        this.domain = domain;
        this.task_id = task_id;
        this.keyword_id = keyword_id;
    }
    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        Reference other = (Reference) that;
        return (this.getReference_id() == null ? other.getReference_id() == null
                : this.getReference_id().equals(other.getReference_id()))
                && (this.getType_id() == null ? other.getType_id() == null
                        : this.getType_id().equals(other.getType_id()))
                && (this.getPlatform_id() == null ? other.getPlatform_id() == null
                        : this.getPlatform_id().equals(other.getPlatform_id()))
                && (this.getTitle() == null ? other.getTitle() == null : this.getTitle().equals(other.getTitle()))
                && (this.getRepetition_num() == null ? other.getRepetition_num() == null
                        : this.getRepetition_num().equals(other.getRepetition_num()))
                && (this.getCreate_time() == null ? other.getCreate_time() == null
                        : this.getCreate_time().equals(other.getCreate_time()))
                && (this.getNum() == null ? other.getNum() == null : this.getNum().equals(other.getNum()))
                && (this.getUrl() == null ? other.getUrl() == null : this.getUrl().equals(other.getUrl()))
                && (this.getDomain() == null ? other.getDomain() == null : this.getDomain().equals(other.getDomain()))
                && (this.getTask_id() == null ? other.getTask_id() == null
                        : this.getTask_id().equals(other.getTask_id()))
                && (this.getKeyword_id() == null ? other.getKeyword_id() == null
                        : this.getKeyword_id().equals(other.getKeyword_id()))
                && (this.getQuestion_id() == null ? other.getQuestion_id() == null
                        : this.getQuestion_id().equals(other.getQuestion_id()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getReference_id() == null) ? 0 : getReference_id().hashCode());
        result = prime * result + ((getType_id() == null) ? 0 : getType_id().hashCode());
        result = prime * result + ((getPlatform_id() == null) ? 0 : getPlatform_id().hashCode());
        result = prime * result + ((getTitle() == null) ? 0 : getTitle().hashCode());
        result = prime * result + ((getRepetition_num() == null) ? 0 : getRepetition_num().hashCode());
        result = prime * result + ((getCreate_time() == null) ? 0 : getCreate_time().hashCode());
        result = prime * result + ((getNum() == null) ? 0 : getNum().hashCode());
        result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
        result = prime * result + ((getDomain() == null) ? 0 : getDomain().hashCode());
        result = prime * result + ((getTask_id() == null) ? 0 : getTask_id().hashCode());
        result = prime * result + ((getKeyword_id() == null) ? 0 : getKeyword_id().hashCode());
        result = prime * result + ((getQuestion_id() == null) ? 0 : getQuestion_id().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", reference_id=").append(reference_id);
        sb.append(", type_id=").append(type_id);
        sb.append(", platform_id=").append(platform_id);
        sb.append(", title=").append(title);
        sb.append(", repetition_num=").append(repetition_num);
        sb.append(", create_time=").append(create_time);
        sb.append(", num=").append(num);
        sb.append(", url=").append(url);
        sb.append(", domain=").append(domain);
        sb.append(", task_id=").append(task_id);
        sb.append(", keyword_id=").append(keyword_id);
        sb.append(", question_id=").append(question_id);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
src/main/java/com/linghu/model/entity/Result.java
File was deleted
src/main/java/com/linghu/model/entity/Type.java
@@ -18,59 +18,59 @@
     * 类型
     */
    @TableId(type = IdType.AUTO)
    private Integer typeId;
    private Integer type_id;
    /**
     * 名字
     */
    private String typeName;
    private String type_name;
    /**
     * 0-未删除 1-删除
     */
    private Integer delFlag;
    private Integer del_flag;
    @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.getTypeId() == null ? other.getTypeId() == null : this.getTypeId().equals(other.getTypeId()))
            && (this.getTypeName() == null ? other.getTypeName() == null : this.getTypeName().equals(other.getTypeName()))
            && (this.getDelFlag() == null ? other.getDelFlag() == null : this.getDelFlag().equals(other.getDelFlag()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getTypeId() == null) ? 0 : getTypeId().hashCode());
        result = prime * result + ((getTypeName() == null) ? 0 : getTypeName().hashCode());
        result = prime * result + ((getDelFlag() == null) ? 0 : getDelFlag().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", typeId=").append(typeId);
        sb.append(", typeName=").append(typeName);
        sb.append(", delFlag=").append(delFlag);
        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/entity/User.java
New file
@@ -0,0 +1,104 @@
package com.linghu.model.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Data;
/**
 *
 * @TableName user
 */
@TableName(value = "user")
@Data
public class User implements Serializable {
    /**
     * 用户id
     */
    @TableId
    private Integer user_id;
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    private String user_name;
    /**
     * 用户邮箱
     */
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String user_email;
    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度至少6位")
    private String password;
    /**
     * 手机号
     */
    private Integer phone;
    @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;
        }
        User other = (User) that;
        return (this.getUser_id() == null ? other.getUser_id() == null : this.getUser_id().equals(other.getUser_id()))
                && (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.getPassword() == null ? other.getPassword() == null
                        : this.getPassword().equals(other.getPassword()))
                && (this.getPhone() == null ? other.getPhone() == null : this.getPhone().equals(other.getPhone()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getUser_id() == null) ? 0 : getUser_id().hashCode());
        result = prime * result + ((getUser_name() == null) ? 0 : getUser_name().hashCode());
        result = prime * result + ((getUser_email() == null) ? 0 : getUser_email().hashCode());
        result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode());
        result = prime * result + ((getPhone() == null) ? 0 : getPhone().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", user_id=").append(user_id);
        sb.append(", user_name=").append(user_name);
        sb.append(", user_email=").append(user_email);
        sb.append(", password=").append(password);
        sb.append(", phone=").append(phone);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
src/main/java/com/linghu/model/excel/PlatformExcel.java
New file
@@ -0,0 +1,16 @@
package com.linghu.model.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class PlatformExcel {
    @ExcelProperty("平台名称")
    private String platform_name;
    @ExcelProperty("发布网址")
    private String domain;
    @ExcelProperty("类型名称")
    private String type_name;
}
src/main/java/com/linghu/service/CallwordService.java
File was deleted
src/main/java/com/linghu/service/KeywordService.java
@@ -6,7 +6,7 @@
/**
* @author xy
* @description 针对表【keyword】的数据库操作Service
* @createDate 2025-07-02 16:32:19
* @createDate 2025-07-04 20:17:33
*/
public interface KeywordService extends IService<Keyword> {
src/main/java/com/linghu/service/OrderService.java
@@ -1,13 +1,22 @@
package com.linghu.service;
import com.linghu.model.entity.Order;
import com.linghu.model.dto.OrderDto;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author xy
* @description 针对表【order】的数据库操作Service
* @createDate 2025-07-02 16:32:19
 * @createDate 2025-07-04 20:17:33
*/
public interface OrderService extends IService<Order> {
    boolean updateOrderWithKeywords(OrderDto orderDto, Integer currentStatus);
    /**
     * 保存订单及其关键词
     *
     * @param orderDto 订单数据传输对象
     * @return 是否保存成功
     */
    boolean saveOrderWithKeywords(OrderDto orderDto);
}
src/main/java/com/linghu/service/PlatformExcelService.java
New file
@@ -0,0 +1,86 @@
package com.linghu.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.linghu.model.entity.Platform;
import com.linghu.model.entity.Type;
import com.linghu.model.excel.PlatformExcel;
import com.linghu.service.TypeService;
import com.linghu.service.PlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Service
public class PlatformExcelService {
    @Autowired
    private PlatformService platformService;
    @Autowired
    private TypeService typeService;
    /**
     * 下载平台导入模板
     */
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("平台导入模板", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), PlatformExcel.class).sheet("平台信息").doWrite(new ArrayList<>());
    }
    /**
     * 导入平台信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void importPlatform(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), PlatformExcel.class, new ReadListener<PlatformExcel>() {
            private List<Platform> platforms = new ArrayList<>();
            @Override
            public void invoke(PlatformExcel data, AnalysisContext context) {
                // 根据类型名称获取类型ID
                Type type = typeService.getTypeByName(data.getType_name());
                if (type == null) {
                    throw new RuntimeException("类型名称不存在:" + data.getType_name());
                }
                Platform platform = new Platform();
                platform.setPlatform_name(data.getPlatform_name());
                platform.setDomain(data.getDomain());
                platform.setType_id(type.getType_id());
                platform.setCreate_time(new Date());
                platform.setDel_flag(0);
                platforms.add(platform);
                // 每100条保存一次
                if (platforms.size() >= 100) {
                    saveData();
                    platforms.clear();
                }
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                saveData();
            }
            private void saveData() {
                if (!platforms.isEmpty()) {
                    platformService.saveBatch(platforms);
                }
            }
        }).sheet().doRead();
    }
}
src/main/java/com/linghu/service/PlatformService.java
New file
@@ -0,0 +1,13 @@
package com.linghu.service;
import com.linghu.model.entity.Platform;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * @author xy
 * @description 针对表【platfrom】的数据库操作Service
 * @createDate 2025-07-04 20:17:33
 */
public interface PlatformService extends IService<Platform> {
}
src/main/java/com/linghu/service/PlatfromService.java
File was deleted
src/main/java/com/linghu/service/QuestionService.java
New file
@@ -0,0 +1,13 @@
package com.linghu.service;
import com.linghu.model.entity.Question;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author xy
* @description 针对表【question】的数据库操作Service
* @createDate 2025-07-04 20:17:33
*/
public interface QuestionService extends IService<Question> {
}
src/main/java/com/linghu/service/ReferenceService.java
New file
@@ -0,0 +1,13 @@
package com.linghu.service;
import com.linghu.model.entity.Reference;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author xy
* @description 针对表【reference】的数据库操作Service
* @createDate 2025-07-04 20:17:33
*/
public interface ReferenceService extends IService<Reference> {
}
src/main/java/com/linghu/service/ResultService.java
File was deleted
src/main/java/com/linghu/service/TypeService.java
@@ -3,42 +3,13 @@
import com.linghu.model.entity.Type;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
 * @author xy
 * @description 针对表【type】的数据库操作Service
 * @createDate 2025-07-02 16:32:19
 * @createDate 2025-07-04 20:10:31
 */
public interface TypeService extends IService<Type> {
    /**
     * 批量添加类型
     *
     * @param types 类型列表
     * @return 是否成功
     */
    boolean saveBatch(List<Type> types);
    /**
     * 批量更新类型
     *
     * @param types 类型列表
     * @return 是否成功
     */
    boolean updateBatchById(List<Type> types);
    public Type getTypeByName(String typeName);
    /**
     * 批量删除类型
     *
     * @param typeIds 类型ID列表
     * @return 是否成功
     */
    boolean removeBatchByIds(List<Integer> typeIds);
    /**
     * 获取所有未删除的类型
     *
     * @return 类型列表
     */
    List<Type> listAllAvailable();
}
src/main/java/com/linghu/service/UserService.java
New file
@@ -0,0 +1,13 @@
package com.linghu.service;
import com.linghu.model.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author xy
* @description 针对表【user】的数据库操作Service
* @createDate 2025-07-07 10:26:00
*/
public interface UserService extends IService<User> {
}
src/main/java/com/linghu/service/impl/CallwordServiceImpl.java
File was deleted
src/main/java/com/linghu/service/impl/KeywordServiceImpl.java
@@ -9,7 +9,7 @@
/**
* @author xy
* @description 针对表【keyword】的数据库操作Service实现
* @createDate 2025-07-02 16:32:19
* @createDate 2025-07-04 20:17:33
*/
@Service
public class KeywordServiceImpl extends ServiceImpl<KeywordMapper, Keyword>
src/main/java/com/linghu/service/impl/OrderServiceImpl.java
@@ -1,22 +1,88 @@
package com.linghu.service.impl;
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.service.KeywordService;
import com.linghu.service.OrderService;
import com.linghu.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
/**
* @author xy
* @description 针对表【order】的数据库操作Service实现
* @createDate 2025-07-02 16:32:19
 * @createDate 2025-07-04 20:17:33
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
    implements OrderService{
    @Autowired
    private KeywordService keywordService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrderWithKeywords(OrderDto orderDto) {
        // 保存订单
        if (!this.save(orderDto)) {
            return false;
}
        // 如果有关键词,则保存关键词
        if (StringUtils.hasText(orderDto.getKeywords())) {
            String[] keywordArray = orderDto.getKeywords().split("\\n");
            for (String keywordName : keywordArray) {
                if (StringUtils.hasText(keywordName)) {
                    Keyword keyword = new Keyword();
                    keyword.setOrder_id(orderDto.getOrder_id());
                    keyword.setKeyword_name(keywordName.trim());
                    keyword.setStatus("notSubmitted");
                    // keyword.setNum(1); // 默认采集轮数为1
                    keywordService.save(keyword);
                }
            }
        }
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderWithKeywords(OrderDto orderDto, Integer currentStatus) {
        // 状态为2或3时禁止修改
        if (currentStatus >= 2) {
            throw new RuntimeException("执行中和已完成状态的订单不可修改");
        }
        // 更新订单基本信息
        if (!this.updateById(orderDto)) {
            return false;
        }
        // 删除旧关键词(当状态为1时允许修改关键词)
        keywordService.lambdaUpdate()
                .eq(Keyword::getOrder_id, orderDto.getOrder_id())
                .eq(Keyword::getStatus, "notSubmitted")
                .remove();
        // 保存新关键词
        if (StringUtils.hasText(orderDto.getKeywords())) {
            String[] keywordArray = orderDto.getKeywords().split("\\n");
            for (String keywordName : keywordArray) {
                if (StringUtils.hasText(keywordName)) {
                    Keyword keyword = new Keyword();
                    keyword.setOrder_id(orderDto.getOrder_id());
                    keyword.setKeyword_name(keywordName.trim());
                    keyword.setStatus("notSubmitted");
                    keywordService.save(keyword);
                }
            }
        }
        return true;
    }
}
src/main/java/com/linghu/service/impl/PlatformServiceImpl.java
New file
@@ -0,0 +1,18 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.entity.Platform;
import com.linghu.service.PlatformService;
import com.linghu.mapper.PlatformMapper;
import org.springframework.stereotype.Service;
/**
 * @author xy
 * @description 针对表【platfrom】的数据库操作Service实现
 * @createDate 2025-07-04 20:17:33
 */
@Service
public class PlatformServiceImpl extends ServiceImpl<PlatformMapper, Platform>
        implements PlatformService {
}
src/main/java/com/linghu/service/impl/PlatfromServiceImpl.java
File was deleted
src/main/java/com/linghu/service/impl/QuestionServiceImpl.java
New file
@@ -0,0 +1,22 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.entity.Question;
import com.linghu.service.QuestionService;
import com.linghu.mapper.QuestionMapper;
import org.springframework.stereotype.Service;
/**
* @author xy
* @description 针对表【question】的数据库操作Service实现
* @createDate 2025-07-04 20:17:33
*/
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question>
    implements QuestionService{
}
src/main/java/com/linghu/service/impl/ReferenceServiceImpl.java
New file
@@ -0,0 +1,22 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.entity.Reference;
import com.linghu.service.ReferenceService;
import com.linghu.mapper.ReferenceMapper;
import org.springframework.stereotype.Service;
/**
* @author xy
* @description 针对表【reference】的数据库操作Service实现
* @createDate 2025-07-04 20:17:33
*/
@Service
public class ReferenceServiceImpl extends ServiceImpl<ReferenceMapper, Reference>
    implements ReferenceService{
}
src/main/java/com/linghu/service/impl/ResultServiceImpl.java
File was deleted
src/main/java/com/linghu/service/impl/TypeServiceImpl.java
@@ -1,49 +1,33 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.entity.Type;
import com.linghu.service.TypeService;
import com.linghu.mapper.TypeMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.annotation.Resource;
/**
 * @author xy
 * @description 针对表【type】的数据库操作Service实现
 * @createDate 2025-07-02 16:32:19
 * @createDate 2025-07-04 20:10:31
 */
@Service
public class TypeServiceImpl extends ServiceImpl<TypeMapper, Type>
        implements TypeService {
    @Resource
    private TypeMapper typeMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(List<Type> types) {
        types.forEach(type -> type.setDelFlag(0));
        return super.saveBatch(types);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchById(List<Type> types) {
        return super.updateBatchById(types);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatchByIds(List<Integer> typeIds) {
        List<Type> types = this.listByIds(typeIds);
        types.forEach(type -> type.setDelFlag(1));
        return this.updateBatchById(types);
    }
    @Override
    public List<Type> listAllAvailable() {
    public Type getTypeByName(String typeName) {
        // 查询
        LambdaQueryWrapper<Type> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Type::getDelFlag, 0);
        return this.list(queryWrapper);
        queryWrapper.eq(Type::getType_name, typeName);
        queryWrapper.eq(Type::getDel_flag, 0);
        return typeMapper.selectOne(queryWrapper);
    }
}
src/main/java/com/linghu/service/impl/UserServiceImpl.java
New file
@@ -0,0 +1,22 @@
package com.linghu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linghu.model.entity.User;
import com.linghu.service.UserService;
import com.linghu.mapper.UserMapper;
import org.springframework.stereotype.Service;
/**
* @author xy
* @description 针对表【user】的数据库操作Service实现
* @createDate 2025-07-07 10:26:00
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{
}
src/main/java/com/linghu/utils/JwtUtils.java
New file
@@ -0,0 +1,86 @@
package com.linghu.utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.linghu.model.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;
@Component
public class JwtUtils {
    @Value("${jwt.secret}")
    private final String secret;
    @Value("${jwt.expiration}")
    private final Long expiration;
    // 生成安全的密钥
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }
    // 通过构造函数注入配置值
    public JwtUtils(
            @Value("${jwt.secret}") String secret,
            @Value("${jwt.expiration}") long expiration) {
        this.secret = secret;
        this.expiration = expiration;
    }
    public String generateToken(User user) {
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
        return Jwts.builder()
                .setSubject(user.getUser_name())
                .claim("email", user.getUser_email())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }
    public User parseToken(String token)
            throws ExpiredJwtException, UnsupportedJwtException,
            MalformedJwtException, SignatureException, IllegalArgumentException {
        Claims claims = Jwts.parser()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
        // 创建User对象并填充数据
        User user = new User();
        user.setUser_name(claims.getSubject()); // 主题是用户名
        user.setUser_email(claims.get("email", String.class));
        // 添加角色信息(如果存在)
        // if (claims.containsKey("roles")) {
        // user.setRoles(claims.get("roles", String.class));
        // }
        return user;
    }
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
src/main/resources/application.yml
@@ -1,14 +1,29 @@
server:
  port: 8080
# JWT配置
jwt:
  secret: linghu-system-mySuperSecretKeyThatIsAtLeast-key-2024
  expiration: 3600
spring:
  datasource:
    url: jdbc:mysql://192.168.110.21:3306/linghu_geo_system?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
    # url: jdbc:mysql://127.0.0.1:3306/linghu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
    username: root
    password: "123456"
    driver-class-name: com.mysql.cj.jdbc.Driver
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher  # 使用 AntPathMatcher 替代 PathPatternMatcher
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: del_flag #默认deleted
      logic-delete-value: 1
      logic-not-delete-value: 0
  configuration:
    map-underscore-to-camel-case: false
linghu:
  url: http://182.92.208.99:8000/api/v1
src/main/resources/mapper/CallwordMapper.xml
File was deleted
src/main/resources/mapper/KeywordMapper.xml
File was deleted
src/main/resources/mapper/OrderMapper.xml
@@ -5,14 +5,14 @@
<mapper namespace="com.linghu.mapper.OrderMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Order">
            <id property="orderId" column="order_id" jdbcType="VARCHAR"/>
            <result property="clientName" column="client_name" jdbcType="VARCHAR"/>
            <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="delFlag" column="del_flag" jdbcType="TINYINT"/>
            <result property="createBy" column="create_by" jdbcType="VARCHAR"/>
            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
            <result property="del_flag" column="del_flag" jdbcType="TINYINT"/>
            <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"/>
            <result property="update_time" column="update_time" jdbcType="TIMESTAMP"/>
    </resultMap>
    <sql id="Base_Column_List">
src/main/resources/mapper/PlatformMapper.xml
New file
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.PlatformMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Platform">
            <id property="platform_id" column="platform_id" jdbcType="INTEGER"/>
            <result property="type_id" column="type_id" jdbcType="INTEGER"/>
            <result property="platform_name" column="platform_name" jdbcType="VARCHAR"/>
            <result property="domain" column="domain" jdbcType="VARCHAR"/>
            <result property="create_time" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="create_by" column="create_by" jdbcType="VARCHAR"/>
            <result property="update_time" column="update_time" jdbcType="TIMESTAMP"/>
            <result property="update_by" column="update_by" jdbcType="VARCHAR"/>
            <result property="del_flag" column="del_flag" jdbcType="TINYINT"/>
    </resultMap>
    <sql id="Base_Column_List">
        platform_id,type_id,platform_name,
        domain,create_time,create_by,
        update_time,update_by,del_flag
    </sql>
</mapper>
src/main/resources/mapper/PlatfromMapper.xml
File was deleted
src/main/resources/mapper/QuestionMapper.xml
New file
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.QuestionMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Question">
            <id property="question_id" column="question_id" jdbcType="INTEGER"/>
            <result property="keyword_id" column="keyword_id" jdbcType="INTEGER"/>
            <result property="question" column="question" jdbcType="VARCHAR"/>
            <result property="status" column="status" jdbcType="VARCHAR"/>
            <result property="user_name" column="user_name" jdbcType="VARCHAR"/>
            <result property="user_email" column="user_email" jdbcType="VARCHAR"/>
            <result property="timestamp" column="timestamp" jdbcType="TIMESTAMP"/>
            <result property="extracted_count" column="extracted_count" jdbcType="INTEGER"/>
            <result property="response" column="response" jdbcType="VARCHAR"/>
            <result property="error" column="error" jdbcType="VARCHAR"/>
    </resultMap>
    <sql id="Base_Column_List">
        question_id,keyword_id,question,
        status,user_name,user_email,
        timestamp,extracted_count,response,
        error
    </sql>
</mapper>
src/main/resources/mapper/ReferenceMapper.xml
New file
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.ReferenceMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Reference">
            <id property="reference_id" column="reference_id" jdbcType="INTEGER"/>
            <result property="type_id" column="type_id" jdbcType="INTEGER"/>
            <result property="platform_id" column="platform_id" jdbcType="INTEGER"/>
            <result property="title" column="title" jdbcType="VARCHAR"/>
            <result property="repetition_num" column="repetition_num" jdbcType="INTEGER"/>
            <result property="create_time" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="num" column="num" jdbcType="INTEGER"/>
            <result property="url" column="url" jdbcType="VARCHAR"/>
            <result property="domain" column="domain" jdbcType="VARCHAR"/>
            <result property="task_id" column="task_id" jdbcType="VARCHAR"/>
    </resultMap>
    <sql id="Base_Column_List">
        reference_id,type_id,platform_id,
        title,repetition_num,create_time,
        num,url,domain,
        task_id
    </sql>
</mapper>
src/main/resources/mapper/ResultMapper.xml
File was deleted
src/main/resources/mapper/TypeMapper.xml
@@ -5,9 +5,9 @@
<mapper namespace="com.linghu.mapper.TypeMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Type">
            <id property="typeId" column="type_id" jdbcType="INTEGER"/>
            <result property="typeName" column="type_name" jdbcType="VARCHAR"/>
            <result property="delFlag" column="del_flag" jdbcType="TINYINT"/>
            <id property="type_id" column="type_id" jdbcType="INTEGER"/>
            <result property="type_name" column="type_name" jdbcType="VARCHAR"/>
            <result property="del_flag" column="del_flag" jdbcType="TINYINT"/>
    </resultMap>
    <sql id="Base_Column_List">
src/main/resources/mapper/UserMapper.xml
New file
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.User">
            <id property="user_id" column="user_id" jdbcType="INTEGER"/>
            <result property="user_name" column="user_name" jdbcType="VARCHAR"/>
            <result property="user_email" column="user_email" jdbcType="VARCHAR"/>
            <result property="password" column="password" jdbcType="VARCHAR"/>
            <result property="phone" column="phone" jdbcType="INTEGER"/>
    </resultMap>
    <sql id="Base_Column_List">
        user_id,user_name,user_email,
        password,phone
    </sql>
</mapper>
src/main/resources/mapper/keywordMapper.xml
New file
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.linghu.mapper.KeywordMapper">
    <resultMap id="BaseResultMap" type="com.linghu.model.entity.Keyword">
            <id property="keyword_id" column="keyword_id" jdbcType="INTEGER"/>
            <result property="order_id" column="order_id" jdbcType="VARCHAR"/>
            <result property="keyword_name" column="keyword_name" jdbcType="VARCHAR"/>
            <result property="num" column="num" jdbcType="INTEGER"/>
            <result property="task_id" column="task_id" jdbcType="VARCHAR"/>
            <result property="status" column="status" jdbcType="VARCHAR"/>
    </resultMap>
    <sql id="Base_Column_List">
        keyword_id,order_id,keyword_name,
        num,task_id,status
    </sql>
</mapper>
src/main/resources/schema.sql
New file
@@ -0,0 +1,42 @@
-- 订单表
CREATE TABLE IF NOT EXISTS `order` (
  `order_id` varchar(20) NOT NULL COMMENT '订单ID',
  `client_name` varchar(100) NOT NULL COMMENT '客户名称',
  `status` int(1) NOT NULL DEFAULT 1 COMMENT '状态:1-待处理',
  `del_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除标记:0-未删除,1-已删除',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
-- 平台表
CREATE TABLE IF NOT EXISTS `platform` (
  `platform_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '平台ID',
  `platform_name` varchar(100) NOT NULL COMMENT '平台名称',
  `domain` varchar(100) NOT NULL COMMENT '平台域名',
  `del_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除标记:0-未删除,1-已删除',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`platform_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台表';
-- 类型表
CREATE TABLE IF NOT EXISTS `type` (
  `type_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '类型ID',
  `type_name` varchar(100) NOT NULL COMMENT '类型名称',
  `del_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除标记:0-未删除,1-已删除',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`type_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='类型表';
-- 提问词表
CREATE TABLE IF NOT EXISTS `question` (
  `question_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '提问词ID',
  `question` varchar(500) NOT NULL COMMENT '提问词内容',
  `status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '状态:pending-待处理',
  `del_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除标记:0-未删除,1-已删除',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提问词表';
src/main/resources/sql/keyword.sql
New file
@@ -0,0 +1,12 @@
CREATE TABLE `keyword` (
  `keyword_id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词',
  `order_id` VARCHAR(50) NOT NULL COMMENT '关联订单id',
  `keyword_name` VARCHAR(255) NOT NULL COMMENT '关键词名称',
  `num` INT DEFAULT 0 COMMENT '采集轮数',
  `task_id` VARCHAR(50) COMMENT '任务唯一标识符',
  `status` VARCHAR(50) DEFAULT 'notSubmitted' COMMENT '任务状态(notSubmitted:待处理;submitted:已提交)',
  `del_flag` INT DEFAULT 0 COMMENT '0-未删除 1-删除',
  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`keyword_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关键词表';
src/main/resources/sql/question.sql
New file
@@ -0,0 +1,14 @@
CREATE TABLE `question` (
  `question_id` varchar(255) NOT NULL COMMENT '提问词ID',
  `keyword_id` int(11) DEFAULT NULL COMMENT '关键词ID',
  `question` varchar(255) DEFAULT NULL COMMENT '提问词',
  `status` varchar(20) DEFAULT NULL COMMENT '提示词状态(pending:待处理;processing:处理中;success:处理成功;failed:处理失败)',
  `user_name` varchar(255) DEFAULT NULL COMMENT '提交人',
  `user_email` varchar(255) DEFAULT NULL COMMENT '提交人邮箱',
  `timestamp` datetime DEFAULT NULL COMMENT '采集时间',
  `extracted_count` int(11) DEFAULT NULL COMMENT '提取的引用数量',
  `response` text COMMENT 'AI回复内容',
  `error` text COMMENT '错误信息',
  PRIMARY KEY (`question_id`),
  KEY `idx_keyword_id` (`keyword_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提问词表';
src/main/resources/sql/reference.sql
New file
@@ -0,0 +1,17 @@
CREATE TABLE `reference` (
  `reference_id` int(11) NOT NULL COMMENT '结果ID',
  `type_id` int(11) DEFAULT NULL COMMENT '类型ID',
  `platform_id` int(11) DEFAULT NULL COMMENT '平台ID',
  `title` varchar(255) DEFAULT NULL COMMENT '标题',
  `repetition_num` int(11) DEFAULT NULL COMMENT '重复次数',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `num` int(11) DEFAULT NULL COMMENT '采集轮数',
  `url` varchar(255) DEFAULT NULL COMMENT '来源url',
  `domain` varchar(255) DEFAULT NULL COMMENT '域名',
  `task_id` varchar(255) DEFAULT NULL COMMENT '任务id',
  `keyword_id` int(11) DEFAULT NULL COMMENT '关键词id',
  PRIMARY KEY (`reference_id`),
  KEY `idx_type_id` (`type_id`),
  KEY `idx_platform_id` (`platform_id`),
  KEY `idx_keyword_id` (`keyword_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引用表';