| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package com.lingyue.document.controller;
- import com.lingyue.common.domain.AjaxResult;
- import com.lingyue.document.dto.StructuredDocumentDTO;
- import com.lingyue.document.entity.DocumentBlock;
- import com.lingyue.document.entity.DocumentBlock.TextElement;
- import com.lingyue.document.service.StructuredDocumentService;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import lombok.Data;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.bind.annotation.*;
- import java.util.List;
- /**
- * 结构化文档控制器(参考飞书设计)
- * 提供编辑器所需的结构化文档和实体标注接口
- *
- * 核心设计:
- * - 文档由 Block 树组成
- * - 实体作为 TextElement 嵌入块中
- * - 编辑实体 = 修改块的 elements 数组
- *
- * @author lingyue
- * @since 2026-01-21
- */
- @Slf4j
- @RestController
- @RequestMapping("/api/v1/documents")
- @RequiredArgsConstructor
- @Tag(name = "结构化文档", description = "文档编辑器接口(参考飞书设计)")
- public class StructuredDocumentController {
-
- private final StructuredDocumentService structuredDocumentService;
-
- /**
- * 获取结构化文档
- */
- @GetMapping("/{documentId}/structured")
- @Operation(summary = "获取结构化文档", description = "获取带实体标注的结构化文档,用于编辑器渲染")
- public AjaxResult<?> getStructuredDocument(
- @Parameter(description = "文档ID", required = true)
- @PathVariable String documentId) {
-
- StructuredDocumentDTO document = structuredDocumentService.getStructuredDocument(documentId);
- if (document == null) {
- return AjaxResult.error("文档不存在: " + documentId);
- }
-
- return AjaxResult.success(document);
- }
-
- // ==================== 块操作 ====================
-
- /**
- * 更新块的元素
- */
- @PutMapping("/{documentId}/blocks/{blockId}/elements")
- @Operation(summary = "更新块元素", description = "更新块的 elements 数组")
- public AjaxResult<?> updateBlockElements(
- @PathVariable String documentId,
- @PathVariable String blockId,
- @RequestBody UpdateElementsRequest request) {
-
- try {
- structuredDocumentService.updateBlockElements(blockId, request.getElements());
- return AjaxResult.success("更新成功");
- } catch (Exception e) {
- log.error("更新块元素失败: blockId={}", blockId, e);
- return AjaxResult.error("更新失败: " + e.getMessage());
- }
- }
-
- /**
- * 创建新块
- */
- @PostMapping("/{documentId}/blocks")
- @Operation(summary = "创建块", description = "在文档中创建新块")
- public AjaxResult<?> createBlock(
- @PathVariable String documentId,
- @RequestBody CreateBlockRequest request) {
-
- try {
- DocumentBlock block = structuredDocumentService.createBlock(
- documentId,
- request.getParentId(),
- request.getIndex(),
- request.getBlockType(),
- request.getElements()
- );
- return AjaxResult.success("创建成功", block);
- } catch (Exception e) {
- log.error("创建块失败: documentId={}", documentId, e);
- return AjaxResult.error("创建失败: " + e.getMessage());
- }
- }
-
- /**
- * 删除块
- */
- @DeleteMapping("/{documentId}/blocks/{blockId}")
- @Operation(summary = "删除块", description = "删除指定块及其子块")
- public AjaxResult<?> deleteBlock(
- @PathVariable String documentId,
- @PathVariable String blockId) {
-
- structuredDocumentService.deleteBlock(blockId);
- return AjaxResult.success("删除成功");
- }
-
- // ==================== 实体操作 ====================
-
- /**
- * 标记实体(将文本转为实体)
- */
- @PostMapping("/{documentId}/blocks/{blockId}/mark-entity")
- @Operation(summary = "标记实体", description = "将块中的文本片段标记为实体")
- public AjaxResult<?> markEntity(
- @PathVariable String documentId,
- @PathVariable String blockId,
- @RequestBody MarkEntityRequest request) {
-
- try {
- String entityId = structuredDocumentService.markEntity(
- blockId,
- request.getElementIndex(),
- request.getStartOffset(),
- request.getEndOffset(),
- request.getEntityType()
- );
- return AjaxResult.success("标记成功", entityId);
- } catch (Exception e) {
- log.error("标记实体失败: blockId={}", blockId, e);
- return AjaxResult.error("标记失败: " + e.getMessage());
- }
- }
-
- /**
- * 取消实体标记(将实体还原为文本)
- */
- @DeleteMapping("/{documentId}/blocks/{blockId}/entities/{entityId}")
- @Operation(summary = "取消实体标记", description = "将实体还原为普通文本")
- public AjaxResult<?> unmarkEntity(
- @PathVariable String documentId,
- @PathVariable String blockId,
- @PathVariable String entityId) {
-
- structuredDocumentService.unmarkEntity(blockId, entityId);
- return AjaxResult.success("取消成功");
- }
-
- /**
- * 更新实体类型
- */
- @PutMapping("/{documentId}/blocks/{blockId}/entities/{entityId}")
- @Operation(summary = "更新实体", description = "更新实体类型")
- public AjaxResult<?> updateEntity(
- @PathVariable String documentId,
- @PathVariable String blockId,
- @PathVariable String entityId,
- @RequestBody UpdateEntityRequest request) {
-
- structuredDocumentService.updateEntityType(blockId, entityId, request.getEntityType());
- return AjaxResult.success("更新成功");
- }
-
- /**
- * 确认实体
- */
- @PostMapping("/{documentId}/blocks/{blockId}/entities/{entityId}/confirm")
- @Operation(summary = "确认实体", description = "确认实体标注正确")
- public AjaxResult<?> confirmEntity(
- @PathVariable String documentId,
- @PathVariable String blockId,
- @PathVariable String entityId) {
-
- structuredDocumentService.confirmEntity(blockId, entityId);
- return AjaxResult.success("确认成功");
- }
-
- // ==================== 请求 DTO ====================
-
- @Data
- public static class UpdateElementsRequest {
- private List<TextElement> elements;
- }
-
- @Data
- public static class CreateBlockRequest {
- private String parentId;
- private Integer index;
- private String blockType;
- private List<TextElement> elements;
- }
-
- @Data
- public static class MarkEntityRequest {
- /** 要标记的元素在 elements 数组中的索引 */
- private Integer elementIndex;
- /** 在该元素文本中的起始位置 */
- private Integer startOffset;
- /** 在该元素文本中的结束位置 */
- private Integer endOffset;
- /** 实体类型 */
- private String entityType;
- }
-
- @Data
- public static class UpdateEntityRequest {
- private String entityType;
- }
- }
|