From 83a412d3fd7d9630c27241362f36f5b116fca1a5 Mon Sep 17 00:00:00 2001 From: wh Date: Thu, 7 May 2026 16:00:17 +0800 Subject: [PATCH] =?UTF-8?q?QA=E9=97=AE=E7=AD=94=E5=AF=B9=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BB=A5=E5=8F=8A=E5=8E=86=E5=8F=B2=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=BD=92=E6=A1=A3=E7=AE=A1=E7=90=86=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AnnotationResultArchiveController.java | 9 ++ .../AnnotationResultHistoryResponse.java | 16 ++-- .../response/AnnotationResultResponse.java | 2 + .../dto/response/FileContentResponse.java | 11 +++ .../backend/entity/AnnotationResult.java | 7 ++ .../entity/AnnotationResultHistory.java | 35 ++++---- .../AnnotationResultArchiveService.java | 48 ++++++++++- .../service/AnnotationResultService.java | 51 ++++++++--- src/main/resources/sql/data.sql | 26 +++--- src/main/resources/sql/schema.sql | 84 +++++++++++-------- 10 files changed, 207 insertions(+), 82 deletions(-) create mode 100644 src/main/java/com/labelsys/backend/dto/response/FileContentResponse.java diff --git a/src/main/java/com/labelsys/backend/controller/AnnotationResultArchiveController.java b/src/main/java/com/labelsys/backend/controller/AnnotationResultArchiveController.java index 0669bc0..1fbcb85 100644 --- a/src/main/java/com/labelsys/backend/controller/AnnotationResultArchiveController.java +++ b/src/main/java/com/labelsys/backend/controller/AnnotationResultArchiveController.java @@ -4,6 +4,7 @@ import com.labelsys.backend.context.UserContext; import com.labelsys.backend.dto.common.PageResult; import com.labelsys.backend.dto.request.AnnotationResultHistoryPageQuery; import com.labelsys.backend.dto.response.AnnotationResultHistoryResponse; +import com.labelsys.backend.dto.response.FileContentResponse; import com.labelsys.backend.service.AnnotationResultArchiveService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -38,4 +39,12 @@ public class AnnotationResultArchiveController { @PathVariable Long id) { return ResponseEntity.ok(annotationResultArchiveService.getHistory(UserContext.requireUser(), id)); } + + @Operation(summary = "加载归档文件内容") + @GetMapping("/{id}/content") + public ResponseEntity loadFileContent( + @Parameter(description = "历史记录ID", example = "901") + @PathVariable Long id) { + return ResponseEntity.ok(annotationResultArchiveService.loadFileContent(UserContext.requireUser(), id)); + } } \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultHistoryResponse.java b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultHistoryResponse.java index 39636b7..025ec2d 100644 --- a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultHistoryResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultHistoryResponse.java @@ -7,14 +7,20 @@ import java.time.LocalDateTime; @Schema(description = "归档历史响应") public record AnnotationResultHistoryResponse( - @Schema(description = "历史记录ID", example = "901") Long id, - @Schema(description = "来源结果ID", example = "802") Long sourceResultId, - @Schema(description = "任务ID", example = "701") Long taskId, - @Schema(description = "资源ID", example = "601") Long resourceId, + @Schema(description = "历史记录ID, 不显示", example = "901") Long id, + //@Schema(description = "来源结果ID", example = "802") Long sourceResultId, + @Schema(description = "任务ID", example = "191000000000000301") Long taskId, + @Schema(description = "任务名称", example = "产品说明书标注") String taskName, // 新增 + @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "资源名称", example = "产品A说明书.pdf") String resourceName, // 新增 + @Schema(description = "问答内容文件路径", example = "annotation-results/2/qa/802.json") String qaContentFilePath, @Schema(description = "归档原因", example = "审核通过后归档") String archiveReason, @Schema(description = "归档操作人ID", example = "5") Long archivedBy, @Schema(description = "归档时间", example = "2026-05-06T10:30:00") LocalDateTime archivedAt, - @Schema(description = "创建时间", example = "2026-05-06T10:30:00") LocalDateTime createdAt + @Schema(description = "创建时间", example = "2026-05-06T10:30:00") LocalDateTime createdAt, + @Schema(description = "审核人ID,自动归档时为null", example = "5") Long reviewerId, + @Schema(description = "审核人姓名,自动归档时为auto", example = "张三") String reviewerName, + @Schema(description = "审核意见,自动归档时为auto", example = "内容符合要求") String reviewerComment ) { } \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java index 6e215ce..171b692 100644 --- a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java @@ -9,7 +9,9 @@ import java.time.LocalDateTime; public record AnnotationResultResponse( @Schema(description = "结果ID", example = "191000000000000401") Long id, @Schema(description = "任务ID", example = "191000000000000301") Long taskId, + @Schema(description = "任务名称", example = "产品说明书标注") String taskName, // 新增 @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "资源名称", example = "产品A说明书.pdf") String resourceName, // 新增 @Schema(description = "标注结果状态", example = "MANUAL_REVIEW_PENDING") AnnotationResultStatus runtimeStatus, @Schema(description = "是否需要人工审核", example = "true") Boolean requiresManualReview, @Schema(description = "是否已删除", example = "false") Boolean isDeleted, diff --git a/src/main/java/com/labelsys/backend/dto/response/FileContentResponse.java b/src/main/java/com/labelsys/backend/dto/response/FileContentResponse.java new file mode 100644 index 0000000..758bba8 --- /dev/null +++ b/src/main/java/com/labelsys/backend/dto/response/FileContentResponse.java @@ -0,0 +1,11 @@ +package com.labelsys.backend.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "文件内容响应") +public record FileContentResponse( + @Schema(description = "文件路径", example = "annotation-results/2/qa/801.json") String filePath, + @Schema(description = "文件内容") String content, + @Schema(description = "文件大小(字节)", example = "1024") Integer size +) { +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/entity/AnnotationResult.java b/src/main/java/com/labelsys/backend/entity/AnnotationResult.java index 833b95f..74e43b8 100644 --- a/src/main/java/com/labelsys/backend/entity/AnnotationResult.java +++ b/src/main/java/com/labelsys/backend/entity/AnnotationResult.java @@ -33,6 +33,13 @@ public class AnnotationResult { @TableField("resource_id") private Long resourceId; + // 添加字段 + @TableField("task_name") + private String taskName; + + @TableField("resource_name") + private String resourceName; + @TableField("qa_content_file_path") private String qaContentFilePath; diff --git a/src/main/java/com/labelsys/backend/entity/AnnotationResultHistory.java b/src/main/java/com/labelsys/backend/entity/AnnotationResultHistory.java index f6cd493..06b3f2f 100644 --- a/src/main/java/com/labelsys/backend/entity/AnnotationResultHistory.java +++ b/src/main/java/com/labelsys/backend/entity/AnnotationResultHistory.java @@ -3,13 +3,13 @@ package com.labelsys.backend.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.labelsys.backend.enums.UserRole; -import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDateTime; + @Data @Builder @NoArgsConstructor @@ -17,18 +17,25 @@ import lombok.NoArgsConstructor; @TableName("annotation_result_history") public class AnnotationResultHistory { @TableId(type = IdType.INPUT) - private Long id; - private Long companyId; - private Long creatorId; - private String creatorRole; - private Long sourceResultId; - private Long taskId; - private Long resourceId; + private Long id; + private Long companyId; + private Long creatorId; + private String creatorRole; + private Long sourceResultId; + private Long taskId; + private Long resourceId; + private String taskName; + private String resourceName; //private String qaContentJson; - private String qaContentStorageMode; - private String qaContentFilePath; - private String archiveReason; - private Long archivedBy; + // private String qaContentStorageMode; + private String qaContentFilePath; + private String archiveReason; + private Long archivedBy; private LocalDateTime archivedAt; private LocalDateTime createdAt; -} + + // 新增审核人相关字段 + private Long reviewerId; + private String reviewerName; + private String reviewerComment; +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java b/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java index ec9b06b..63f453c 100644 --- a/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java +++ b/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java @@ -9,6 +9,7 @@ import com.labelsys.backend.context.LoginUser; import com.labelsys.backend.dto.common.PageResult; import com.labelsys.backend.dto.request.AnnotationResultHistoryPageQuery; import com.labelsys.backend.dto.response.AnnotationResultHistoryResponse; +import com.labelsys.backend.dto.response.FileContentResponse; import com.labelsys.backend.dto.response.MergeReviewResultResponse; import com.labelsys.backend.entity.AnnotationResult; import com.labelsys.backend.entity.AnnotationResultHistory; @@ -91,14 +92,19 @@ public class AnnotationResultArchiveService { private AnnotationResultHistoryResponse toResponse(AnnotationResultHistory history) { return new AnnotationResultHistoryResponse( history.getId(), - history.getSourceResultId(), + // history.getSourceResultId(), history.getTaskId(), + history.getTaskName(), // 新增 history.getResourceId(), + history.getResourceName(), // 新增 history.getQaContentFilePath(), history.getArchiveReason(), history.getArchivedBy(), history.getArchivedAt(), - history.getCreatedAt() + history.getCreatedAt(), + history.getReviewerId(), + history.getReviewerName(), + history.getReviewerComment() ); } @@ -135,7 +141,7 @@ public class AnnotationResultArchiveService { LocalDateTime archivedAt = LocalDateTime.now(); // 从对象存储读取 qa.json 内容 - String qaContentJson = loadQaContentJson(result); + // String qaContentJson = loadQaContentJson(result); AnnotationResultHistory history = AnnotationResultHistory.builder() .id(IdGenerator.nextId()) @@ -144,12 +150,17 @@ public class AnnotationResultArchiveService { .creatorRole(result.getCreatorRole()) .sourceResultId(result.getId()) .taskId(result.getTaskId()) + .taskName(result.getTaskName()) .resourceId(result.getResourceId()) + .resourceName(result.getResourceName()) //.qaContentJson(qaContentJson) // 使用从对象存储读取的内容 .qaContentFilePath(result.getQaContentFilePath()) .archiveReason(archiveReason) .archivedBy(reviewerId) .archivedAt(archivedAt) + .reviewerId(null) + .reviewerName("auto") + .reviewerComment("auto") .build(); annotationResultHistoryMapper.insert(history); @@ -208,4 +219,35 @@ public class AnnotationResultArchiveService { int firstSlash = filePath.indexOf('/'); return firstSlash > 0 ? filePath.substring(firstSlash + 1) : ""; } + + /** + * 加载归档记录的文件内容 + * @param currentUser 当前用户 + * @param historyId 历史记录ID + * @return 文件内容响应 + */ + public FileContentResponse loadFileContent(LoginUser currentUser, Long historyId) { + AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId); + if (history == null || !history.getCompanyId().equals(currentUser.companyId())) { + throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在"); + } + //assertHistoryPermission(currentUser, history); + + String filePath = history.getQaContentFilePath(); + if (filePath == null || filePath.isEmpty()) { + throw new BusinessException(ResultCode.ERROR, "文件路径为空"); + } + + try { + String bucketName = extractBucketName(filePath); + String objectKey = extractObjectKey(filePath); + byte[] content = objectStorageService.download(bucketName, objectKey); + String contentStr = new String(content, StandardCharsets.UTF_8); + + return new FileContentResponse(filePath, contentStr, content.length); + } catch (Exception e) { + log.error("Failed to load file content, historyId={}, filePath={}", historyId, filePath, e); + throw new BusinessException(ResultCode.ERROR, "加载文件内容失败"); + } + } } \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java index 414fb2c..a3f3346 100644 --- a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java +++ b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java @@ -25,7 +25,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; @@ -48,6 +47,7 @@ public class AnnotationResultService { boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); var wrapper = new LambdaQueryWrapper() + .eq(AnnotationResult::getIsDeleted, Boolean.FALSE) .eq(AnnotationResult::getCompanyId, currentUser.companyId()) .eq(query.taskId() != null, AnnotationResult::getTaskId, query.taskId()) .eq(query.resourceId() != null, AnnotationResult::getResourceId, query.resourceId()) @@ -95,7 +95,7 @@ public class AnnotationResultService { //assertResultPermission(currentUser, result); QaContent qaContent = loadQaContent(result); - DiffContent diffContent = StringUtils.hasText(result.getDiffSummaryFilePath()) ? + DiffContent diffContent = Boolean.TRUE.equals(result.getRequiresManualReview()) ? loadDiffSummary(result) : null; SourceResource resource = sourceResourceMapper.selectById(result.getResourceId()); @@ -170,14 +170,15 @@ public class AnnotationResultService { saveQaContent(result, updatedQaContent); // 更新数据库记录 + result.setIsDeleted(Boolean.TRUE); result.setReviewerId(currentUser.userId()); result.setReviewComment(request.reviewComment()); result.setReviewedAt(LocalDateTime.now()); result.setRequiresManualReview(false); annotationResultMapper.updateById(result); - // 归档到历史表 - archiveToHistory(result, currentUser, "审核通过后归档"); + // 归档到历史表(人工审核后归档) + archiveToHistory(result, currentUser, "审核通过后归档", false); log.info("merged review result, companyId={}, userId={}, resultId={}", currentUser.companyId(), currentUser.userId(), resultId); @@ -187,7 +188,9 @@ public class AnnotationResultService { return new AnnotationResultResponse( result.getId(), result.getTaskId(), + result.getTaskName(), // 新增 result.getResourceId(), + result.getResourceName(), // 新增 deriveStatus(result), result.getRequiresManualReview(), result.getIsDeleted(), @@ -262,31 +265,55 @@ public class AnnotationResultService { } } - private void archiveToHistory(AnnotationResult result, LoginUser currentUser, String archiveReason) { + /** + * 归档到历史表 + * @param result 标注结果 + * @param currentUser 当前用户 + * @param archiveReason 归档原因 + * @param isAutoArchive 是否自动归档(true=自动归档,false=人工审核后归档) + */ + private void archiveToHistory(AnnotationResult result, LoginUser currentUser, String archiveReason, boolean isAutoArchive) { try { // 读取 qa.json 内容用于归档 QaContent qaContent = loadQaContent(result); // 构建归档记录 - AnnotationResultHistory history = AnnotationResultHistory.builder() + AnnotationResultHistory.AnnotationResultHistoryBuilder historyBuilder = AnnotationResultHistory.builder() .id(IdGenerator.nextId()) .companyId(result.getCompanyId()) - .creatorId(currentUser.userId()) - .creatorRole(currentUser.role().name()) + .creatorId(result.getCreatorId()) + .creatorRole(result.getCreatorRole()) .sourceResultId(result.getId()) .taskId(result.getTaskId()) + .taskName(result.getTaskName()) .resourceId(result.getResourceId()) + .resourceName(result.getResourceName()) //.qaContentJson(objectMapper.writeValueAsString(qaContent)) .qaContentFilePath(result.getQaContentFilePath()) .archiveReason(archiveReason) .archivedBy(currentUser.userId()) .archivedAt(LocalDateTime.now()) - .createdAt(LocalDateTime.now()) - .build(); + .createdAt(LocalDateTime.now()); - annotationResultHistoryMapper.insert(history); + // 根据归档类型设置审核人信息 + if (isAutoArchive) { + // 自动归档:reviewer_id为NULL,name和comment为"auto" + historyBuilder + .reviewerId(null) + .reviewerName("auto") + .reviewerComment("auto"); + } else { + // 人工审核后归档:使用审核人信息 + historyBuilder + .reviewerId(result.getReviewerId()) + .reviewerName(currentUser.realName()) + .reviewerComment(result.getReviewComment()); + } - log.info("archived result to history, resultId={}, historyId={}", result.getId(), history.getId()); + annotationResultHistoryMapper.insert(historyBuilder.build()); + + log.info("archived result to history, resultId={}, historyId={}, isAutoArchive={}", + result.getId(), historyBuilder.build().getId(), isAutoArchive); } catch (Exception e) { log.error("Failed to archive result to history, resultId={}", result.getId(), e); throw new BusinessException(ResultCode.ERROR, "归档失败"); diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql index 07f87a0..800944e 100644 --- a/src/main/resources/sql/data.sql +++ b/src/main/resources/sql/data.sql @@ -84,27 +84,27 @@ INSERT INTO annotation_task_resource ( ON CONFLICT DO NOTHING; INSERT INTO annotation_result ( - id, company_id, creator_id, creator_role, task_id, resource_id, + id, company_id, creator_id, creator_role, task_id, task_name, resource_id, resource_name, qa_content_file_path, diff_summary_file_path, requires_manual_review, is_deleted, reviewer_id, review_comment, reviewed_at ) VALUES - (801, 2, 3, 'EMPLOYEE', 701, 601, - 'annotation-results/qa/801.json', - 'annotation-results/diff/801.json', - TRUE, FALSE, NULL, NULL, NULL), - (802, 2, 3, 'EMPLOYEE', 702, 602, - 'annotation-results/qa/802.json', - NULL, - FALSE, FALSE, 5, '结果可通过。', CURRENT_TIMESTAMP) + (801, 2, 3, 'EMPLOYEE', 701, '多资源问答抽取任务', 601, '设备巡检规范.txt', + 'annotation-results/qa/801.json', + 'annotation-results/diff/801.json', + TRUE, FALSE, NULL, NULL, NULL), + (802, 2, 3, 'EMPLOYEE', 702, '图片问答抽取任务', 602, '控制柜照片.jpg', + 'annotation-results/qa/802.json', + NULL, + FALSE, FALSE, 5, '结果可通过。', CURRENT_TIMESTAMP) ON CONFLICT DO NOTHING; INSERT INTO annotation_result_history ( - id, company_id, creator_id, creator_role, source_result_id, task_id, resource_id, - qa_content_file_path, archive_reason, archived_by, archived_at + id, company_id, creator_id, creator_role, source_result_id, task_id, task_name, resource_id, resource_name, + qa_content_file_path, reviewer_id, reviewer_name, reviewer_comment, archive_reason, archived_by, archived_at ) VALUES - (901, 2, 3, 'EMPLOYEE', 802, 702, 602, + (901, 2, 3, 'EMPLOYEE', 802, 702, '图片问答抽取任务', 602, '控制柜照片.jpg', 'annotation-results/2/qa/802.json', - '审核通过后归档', 5, CURRENT_TIMESTAMP) + 5, '甲公司审核员', '结果可通过。', '审核通过后归档', 5, CURRENT_TIMESTAMP) ON CONFLICT DO NOTHING; INSERT INTO image_bbox_annotation ( diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index 4f3c766..c015a0c 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -163,14 +163,14 @@ COMMENT ON COLUMN source_resource.updated_at IS '更新时间。'; CREATE TABLE IF NOT EXISTS image_bbox_annotation ( id BIGINT PRIMARY KEY, - company_id BIGINT NOT NULL, - resource_id BIGINT NOT NULL, + company_id BIGINT NOT NULL, + resource_id BIGINT NOT NULL, bbox_json TEXT, remark VARCHAR(500), - creator_id BIGINT NOT NULL, - creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + creator_id BIGINT NOT NULL, + creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_image_bbox_annotation_company FOREIGN KEY (company_id) REFERENCES sys_company (id), CONSTRAINT fk_image_bbox_annotation_resource FOREIGN KEY (resource_id) REFERENCES source_resource (id), CONSTRAINT fk_image_bbox_annotation_creator FOREIGN KEY (creator_id) REFERENCES sys_user (id) @@ -244,24 +244,26 @@ COMMENT ON COLUMN annotation_task_resource.task_id IS '任务ID。'; COMMENT ON COLUMN annotation_task_resource.resource_id IS '资源ID。'; COMMENT ON COLUMN annotation_task_resource.created_at IS '创建时间。'; - +drop table if exists annotation_result; CREATE TABLE IF NOT EXISTS annotation_result ( - id BIGINT PRIMARY KEY, - company_id BIGINT NOT NULL, - creator_id BIGINT NOT NULL, - creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', - task_id BIGINT NOT NULL, - resource_id BIGINT NOT NULL, - qa_content_file_path VARCHAR(512) NOT NULL, - diff_summary_file_path VARCHAR(512), - requires_manual_review BOOLEAN NOT NULL DEFAULT FALSE, - is_deleted BOOLEAN NOT NULL DEFAULT FALSE, - reviewer_id BIGINT, - review_comment TEXT, - reviewed_at TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + id BIGINT PRIMARY KEY, + company_id BIGINT NOT NULL, + creator_id BIGINT NOT NULL, + creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', + task_id BIGINT NOT NULL, + resource_id BIGINT NOT NULL, + task_name VARCHAR(256), + resource_name VARCHAR(512), + qa_content_file_path VARCHAR(512) NOT NULL, + diff_summary_file_path VARCHAR(512), + requires_manual_review BOOLEAN NOT NULL DEFAULT FALSE, + is_deleted BOOLEAN NOT NULL DEFAULT FALSE, + reviewer_id BIGINT, + review_comment TEXT, + reviewed_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_annotation_result_company FOREIGN KEY (company_id) REFERENCES sys_company (id), CONSTRAINT fk_annotation_result_creator FOREIGN KEY (creator_id) REFERENCES sys_user (id), CONSTRAINT fk_annotation_result_task FOREIGN KEY (task_id) REFERENCES annotation_task (id), @@ -285,28 +287,35 @@ COMMENT ON COLUMN annotation_result.review_comment IS '审核意见。'; COMMENT ON COLUMN annotation_result.reviewed_at IS '审核时间。'; COMMENT ON COLUMN annotation_result.created_at IS '创建时间。'; COMMENT ON COLUMN annotation_result.updated_at IS '更新时间。'; - +COMMENT ON COLUMN annotation_result.task_name IS '任务名称(冗余字段)。'; +COMMENT ON COLUMN annotation_result.resource_name IS '资源名称(冗余字段)。'; CREATE TABLE IF NOT EXISTS annotation_result_history ( - id BIGINT PRIMARY KEY, - company_id BIGINT NOT NULL, - creator_id BIGINT NOT NULL, - creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', - source_result_id BIGINT, - task_id BIGINT NOT NULL, - resource_id BIGINT NOT NULL, + id BIGINT PRIMARY KEY, + company_id BIGINT NOT NULL, + creator_id BIGINT NOT NULL, + creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE', + source_result_id BIGINT, + task_id BIGINT NOT NULL, + resource_id BIGINT NOT NULL, + task_name VARCHAR(256), + resource_name VARCHAR(512), qa_content_file_path VARCHAR(512) NOT NULL, - archive_reason VARCHAR(256), - archived_by BIGINT, - archived_at TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + reviewer_id BIGINT, + reviewer_name VARCHAR(128), + reviewer_comment TEXT, + archive_reason VARCHAR(256), + archived_by BIGINT, + archived_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_annotation_result_history_company FOREIGN KEY (company_id) REFERENCES sys_company (id), CONSTRAINT fk_annotation_result_history_creator FOREIGN KEY (creator_id) REFERENCES sys_user (id), CONSTRAINT fk_annotation_result_history_result FOREIGN KEY (source_result_id) REFERENCES annotation_result (id), CONSTRAINT fk_annotation_result_history_task FOREIGN KEY (task_id) REFERENCES annotation_task (id), CONSTRAINT fk_annotation_result_history_resource FOREIGN KEY (resource_id) REFERENCES source_resource (id), - CONSTRAINT fk_annotation_result_history_archived_by FOREIGN KEY (archived_by) REFERENCES sys_user (id) + CONSTRAINT fk_annotation_result_history_archived_by FOREIGN KEY (archived_by) REFERENCES sys_user (id), + CONSTRAINT fk_annotation_result_history_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user (id) ); COMMENT ON TABLE annotation_result_history IS '历史归档结果表。问答内容存储在对象存储中。'; @@ -322,6 +331,11 @@ COMMENT ON COLUMN annotation_result_history.archive_reason IS '归档原因说 COMMENT ON COLUMN annotation_result_history.archived_by IS '归档操作人用户ID。'; COMMENT ON COLUMN annotation_result_history.archived_at IS '归档时间。'; COMMENT ON COLUMN annotation_result_history.created_at IS '创建时间。'; +COMMENT ON COLUMN annotation_result_history.reviewer_id IS '审核人用户ID。自动归档时为NULL。'; +COMMENT ON COLUMN annotation_result_history.reviewer_name IS '审核人姓名。自动归档时为"auto"。'; +COMMENT ON COLUMN annotation_result_history.reviewer_comment IS '审核意见。自动归档时为"auto"。'; +COMMENT ON COLUMN annotation_result_history.task_name IS '任务名称(冗余字段)。'; +COMMENT ON COLUMN annotation_result_history.resource_name IS '资源名称(冗余字段)。'; CREATE TABLE IF NOT EXISTS training_dataset (