feat(annotation): 完善文件版本管理和标注同步功能

- 将 useNewVersionUsingPost 重命名为 applyNewVersionUsingPost
- 添加 fileVersionCheckSeqRef 避免版本检查竞态条件
- 移除 checkingFileVersion 状态变量的渲染依赖
- 在文件版本信息中添加 annotationVersionUnknown 字段
- 修复前端文件版本比较显示的 JSX 语法
- 添加历史标注缺少版本信息的提示显示
- 配置 Alembic 异步数据库迁移环境支持 aiomysql
- 添加文件版本未知状态的后端判断逻辑
- 实现标注清除时的段落注释清理功能
- 添加知识库同步钩子到版本更新流程
This commit is contained in:
2026-02-05 23:22:49 +08:00
parent 5507adeb45
commit 719f54bf2e
5 changed files with 109 additions and 45 deletions

View File

@@ -1500,6 +1500,7 @@ class AnnotationEditorService:
for file_record in valid_files:
file_id = str(file_record.id) # type: ignore
file_name = str(getattr(file_record, "file_name", ""))
current_file_version = getattr(file_record, "version", None)
for retry in range(max_retries):
try:
@@ -1602,6 +1603,7 @@ class AnnotationEditorService:
# 更新现有标注
existing.annotation = final_payload # type: ignore[assignment]
existing.annotation_status = ANNOTATION_STATUS_IN_PROGRESS # type: ignore[assignment]
existing.file_version = current_file_version # type: ignore[assignment]
existing.updated_at = now # type: ignore[assignment]
else:
# 创建新标注记录
@@ -1611,6 +1613,7 @@ class AnnotationEditorService:
file_id=file_id,
annotation=final_payload,
annotation_status=ANNOTATION_STATUS_IN_PROGRESS,
file_version=current_file_version,
created_at=now,
updated_at=now,
)
@@ -1679,18 +1682,21 @@ class AnnotationEditorService:
current_file_version = file_record.version
annotation_file_version = annotation.file_version if annotation else None
if annotation is None:
has_new_version = False
elif annotation_file_version is None:
has_new_version = True
else:
has_new_version = current_file_version > annotation_file_version
annotation_version_unknown = (
annotation is not None and annotation_file_version is None
)
has_new_version = (
current_file_version > annotation_file_version
if annotation_file_version is not None
else False
)
return {
"fileId": file_id,
"currentFileVersion": current_file_version,
"annotationFileVersion": annotation_file_version,
"hasNewVersion": has_new_version,
"annotationVersionUnknown": annotation_version_unknown,
}
async def use_new_version(self, project_id: str, file_id: str) -> Dict[str, Any]:
@@ -1749,24 +1755,31 @@ class AnnotationEditorService:
# 清空标注并更新版本号
now = datetime.utcnow()
if isinstance(annotation.annotation, dict):
if annotation.annotation.get(SEGMENTED_KEY):
segments = annotation.annotation.get(SEGMENTS_KEY, {})
for segment_id, segment_data in segments.items():
if isinstance(segment_data, dict):
segment_data[SEGMENT_RESULT_KEY] = []
annotation.annotation = {
SEGMENTED_KEY: True,
"version": annotation.annotation.get("version", 1),
SEGMENTS_KEY: segments,
"total_segments": annotation.annotation.get(
"total_segments", len(segments)
),
}
else:
annotation.annotation = {}
else:
annotation.annotation = {}
cleared_payload: Dict[str, Any] = {}
if isinstance(annotation.annotation, dict) and self._is_segmented_annotation(
annotation.annotation
):
segments = self._extract_segment_annotations(annotation.annotation)
cleared_segments: Dict[str, Dict[str, Any]] = {}
for segment_id, segment_data in segments.items():
if not isinstance(segment_data, dict):
continue
normalized = dict(segment_data)
normalized[SEGMENT_RESULT_KEY] = []
cleared_segments[str(segment_id)] = normalized
total_segments = self._resolve_segment_total(annotation.annotation)
if total_segments is None:
total_segments = len(cleared_segments)
cleared_payload = {
SEGMENTED_KEY: True,
"version": annotation.annotation.get("version", 1),
SEGMENTS_KEY: cleared_segments,
SEGMENT_TOTAL_KEY: total_segments,
}
annotation.annotation = cleared_payload
annotation.annotation_status = ANNOTATION_STATUS_NO_ANNOTATION
annotation.file_version = current_file_version
annotation.updated_at = now
@@ -1774,6 +1787,13 @@ class AnnotationEditorService:
await self.db.commit()
await self.db.refresh(annotation)
await self._sync_annotation_to_knowledge(
project,
file_record,
cleared_payload,
annotation.updated_at or now,
)
return {
"fileId": file_id,
"previousFileVersion": previous_file_version,