| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- package com.lingyue.document.controller;
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.lingyue.document.entity.Document;
- import com.lingyue.document.entity.DocumentElement;
- import com.lingyue.document.service.DocumentService;
- import com.lingyue.document.service.DocumentElementService;
- import com.lingyue.common.domain.AjaxResult;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import jakarta.validation.Valid;
- import jakarta.validation.constraints.NotEmpty;
- import lombok.Data;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.bind.annotation.*;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- /**
- * 文档控制器
- * 提供文档的 CRUD 操作
- *
- * @author lingyue
- * @since 2026-01-21
- */
- @Slf4j
- @RestController
- @RequestMapping("/api/v1/documents")
- @RequiredArgsConstructor
- @Tag(name = "文档管理", description = "文档 CRUD 接口")
- public class DocumentController {
-
- private final DocumentService documentService;
- private final DocumentElementService documentElementService;
-
- /**
- * 获取文档列表(分页)
- */
- @GetMapping
- @Operation(summary = "获取文档列表", description = "分页获取用户的文档列表")
- public AjaxResult<IPage<Document>> getDocuments(
- @Parameter(description = "用户ID", required = true)
- @RequestParam String userId,
- @Parameter(description = "页码,从1开始")
- @RequestParam(defaultValue = "1") Integer page,
- @Parameter(description = "每页数量")
- @RequestParam(defaultValue = "20") Integer size,
- @Parameter(description = "状态筛选")
- @RequestParam(required = false) String status,
- @Parameter(description = "关键词搜索")
- @RequestParam(required = false) String keyword) {
-
- log.info("获取文档列表: userId={}, page={}, size={}", userId, page, size);
-
- Page<Document> pageParam = new Page<>(page, size);
- IPage<Document> result = documentService.getDocumentsByUserId(userId, pageParam, status, keyword);
-
- return AjaxResult.success(result);
- }
-
- /**
- * 获取文档详情
- */
- @GetMapping("/{documentId}")
- @Operation(summary = "获取文档详情", description = "根据文档ID获取详情")
- public AjaxResult<?> getDocument(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- Document document = documentService.getDocumentById(documentId);
- if (document == null) {
- return AjaxResult.error("文档不存在: " + documentId);
- }
-
- return AjaxResult.success(document);
- }
-
- /**
- * 获取文档提取的文本内容
- */
- @GetMapping("/{documentId}/text")
- @Operation(summary = "获取文档文本", description = "获取文档解析后的文本内容")
- public AjaxResult<?> getDocumentText(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- try {
- String text = documentService.getDocumentText(documentId);
- if (text == null) {
- return AjaxResult.error("文档文本不存在或尚未解析完成");
- }
-
- DocumentTextResponse response = new DocumentTextResponse();
- response.setDocumentId(documentId);
- response.setText(text);
- response.setLength(text.length());
-
- return AjaxResult.success(response);
- } catch (Exception e) {
- log.error("获取文档文本失败: documentId={}", documentId, e);
- return AjaxResult.error("获取文档文本失败: " + e.getMessage());
- }
- }
-
- /**
- * 获取文档解析状态
- */
- @GetMapping("/{documentId}/parse-status")
- @Operation(summary = "获取解析状态", description = "获取文档的解析进度和状态")
- public AjaxResult<?> getParseStatus(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- Document document = documentService.getDocumentById(documentId);
- if (document == null) {
- return AjaxResult.error("文档不存在: " + documentId);
- }
-
- ParseStatusResponse response = new ParseStatusResponse();
- response.setDocumentId(documentId);
- response.setStatus(document.getParseStatus());
- response.setProgress(document.getParseProgress());
- response.setError(document.getParseError());
- response.setStartedAt(document.getParseStartedAt());
- response.setCompletedAt(document.getParseCompletedAt());
-
- return AjaxResult.success(response);
- }
-
- /**
- * 更新文档信息
- */
- @PutMapping("/{documentId}")
- @Operation(summary = "更新文档", description = "更新文档的名称、状态等信息")
- public AjaxResult<?> updateDocument(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId,
- @Valid @RequestBody UpdateDocumentRequest request) {
-
- try {
- Document document = documentService.updateDocument(documentId, request.getName(),
- request.getStatus(), request.getMetadata());
- log.info("更新文档成功: documentId={}", documentId);
- return AjaxResult.success("更新成功", document);
- } catch (Exception e) {
- log.error("更新文档失败: documentId={}", documentId, e);
- return AjaxResult.error("更新文档失败: " + e.getMessage());
- }
- }
-
- /**
- * 删除文档(级联删除所有关联数据)
- */
- @DeleteMapping("/{documentId}")
- @Operation(summary = "删除文档", description = "删除指定文档及其所有关联数据(图节点、向量、结构化元素等)")
- public AjaxResult<?> deleteDocument(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- try {
- documentService.deleteDocumentCascade(documentId);
- log.info("删除文档成功: documentId={}", documentId);
- return AjaxResult.success("删除成功");
- } catch (Exception e) {
- log.error("删除文档失败: documentId={}", documentId, e);
- return AjaxResult.error("删除文档失败: " + e.getMessage());
- }
- }
-
- /**
- * 批量删除文档
- */
- @PostMapping("/batch-delete")
- @Operation(summary = "批量删除文档", description = "批量删除多个文档及其关联数据")
- public AjaxResult<?> batchDeleteDocuments(
- @Valid @RequestBody BatchDeleteRequest request) {
-
- List<String> successIds = new ArrayList<>();
- List<String> failedIds = new ArrayList<>();
-
- for (String documentId : request.getDocumentIds()) {
- try {
- documentService.deleteDocumentCascade(documentId);
- successIds.add(documentId);
- } catch (Exception e) {
- log.error("批量删除文档失败: documentId={}, error={}", documentId, e.getMessage());
- failedIds.add(documentId);
- }
- }
-
- BatchDeleteResponse response = new BatchDeleteResponse();
- response.setSuccessIds(successIds);
- response.setFailedIds(failedIds);
- response.setSuccessCount(successIds.size());
- response.setFailedCount(failedIds.size());
-
- if (failedIds.isEmpty()) {
- return AjaxResult.success("批量删除成功", response);
- } else if (successIds.isEmpty()) {
- return AjaxResult.error("批量删除全部失败", response);
- } else {
- return AjaxResult.success("批量删除部分成功", response);
- }
- }
-
- /**
- * 获取文档的结构化内容
- * 包含段落、图片、表格,按原始顺序排列
- */
- @GetMapping("/{documentId}/elements")
- @Operation(summary = "获取文档结构化内容", description = "获取文档的段落、图片、表格等结构化元素,保持原始排版顺序")
- public AjaxResult<?> getDocumentElements(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- List<DocumentElement> elements = documentElementService.getElementsByDocumentId(documentId);
- if (elements.isEmpty()) {
- return AjaxResult.error("文档尚未进行结构化解析或无内容");
- }
-
- DocumentElementsResponse response = new DocumentElementsResponse();
- response.setDocumentId(documentId);
- response.setElements(elements);
- response.setStats(documentElementService.getElementStats(documentId));
-
- return AjaxResult.success(response);
- }
-
- /**
- * 获取文档中的所有图片
- */
- @GetMapping("/{documentId}/images")
- @Operation(summary = "获取文档图片列表", description = "获取文档中所有图片的信息和URL")
- public AjaxResult<?> getDocumentImages(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- List<DocumentElement> images = documentElementService.getImagesByDocumentId(documentId);
- return AjaxResult.success(images);
- }
-
- /**
- * 获取文档中的所有表格
- */
- @GetMapping("/{documentId}/tables")
- @Operation(summary = "获取文档表格列表", description = "获取文档中所有表格的数据")
- public AjaxResult<?> getDocumentTables(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- List<DocumentElement> tables = documentElementService.getTablesByDocumentId(documentId);
- return AjaxResult.success(tables);
- }
-
- // ==================== 请求/响应 DTO ====================
-
- @Data
- public static class DocumentTextResponse {
- private String documentId;
- private String text;
- private Integer length;
- }
-
- @Data
- public static class ParseStatusResponse {
- private String documentId;
- private String status;
- private Integer progress;
- private String error;
- private java.util.Date startedAt;
- private java.util.Date completedAt;
- }
-
- @Data
- public static class DocumentElementsResponse {
- private String documentId;
- private List<DocumentElement> elements;
- private Map<String, Object> stats;
- }
-
- @Data
- public static class UpdateDocumentRequest {
- private String name; // 文档名称
- private String status; // 状态(可选)
- private Object metadata; // 元数据(可选)
- }
-
- @Data
- public static class BatchDeleteRequest {
- @NotEmpty(message = "文档ID列表不能为空")
- private List<String> documentIds;
- }
-
- @Data
- public static class BatchDeleteResponse {
- private List<String> successIds;
- private List<String> failedIds;
- private int successCount;
- private int failedCount;
- }
- }
|