feat: migrate cross review to v3 leaudit flow

This commit is contained in:
wren
2026-05-07 18:18:59 +08:00
parent 35e0c45c42
commit 1c84209f38
23 changed files with 5172 additions and 39 deletions
@@ -1128,6 +1128,7 @@ class DocumentServiceImpl(IDocumentService):
)
).scalar_one()
await self._syncRuleBindings(Session, int(row), Body.ruleSetIds, "default")
await sync_group_bindings_from_doc_type(Session, int(row), Body.ruleSetIds)
await Session.commit()
return await self.GetDocumentType(int(row))
@@ -1170,6 +1171,7 @@ class DocumentServiceImpl(IDocumentService):
if "ruleSetIds" in providedFields and Body.ruleSetIds is not None:
await self._syncRuleBindings(Session, Id, Body.ruleSetIds, "default")
await sync_group_bindings_from_doc_type(Session, Id, Body.ruleSetIds)
await Session.commit()
return await self.GetDocumentType(Id)
@@ -1186,6 +1188,7 @@ class DocumentServiceImpl(IDocumentService):
if not current:
raise LeauditException(StatusCodeEnum.HTTP_404_NOT_FOUND, "文档类型不存在")
await Session.execute(text("UPDATE leaudit_document_types SET deleted_at = NOW() WHERE id = :id"), {"id": Id})
await Session.execute(text("UPDATE leaudit_rule_type_bindings SET deleted_at = NOW() WHERE doc_type_id = :id AND deleted_at IS NULL"), {"id": Id})
await Session.commit()
async def ListDocumentTypeRoots(self, EntryModuleId: int | None = None) -> list[DocumentTypeRootItemVO]:
@@ -1331,36 +1334,17 @@ class DocumentServiceImpl(IDocumentService):
await Session.execute(
text(
"""
SELECT
child.document_type_id AS doc_type_id,
rgb.rule_set_id,
child.sort_order AS child_sort_order,
rgb.priority,
rgb.id
FROM leaudit_evaluation_point_groups child
JOIN leaudit_rule_group_bindings rgb
ON rgb.group_id = child.id
AND rgb.deleted_at IS NULL
AND rgb.is_active = TRUE
WHERE child.document_type_id = ANY(:ids)
AND child.deleted_at IS NULL
AND COALESCE(child.pid, 0) <> 0
ORDER BY
child.document_type_id ASC,
COALESCE(child.sort_order, 0) ASC,
COALESCE(rgb.priority, 0) DESC,
rgb.id ASC
SELECT doc_type_id, rule_set_id
FROM leaudit_rule_type_bindings
WHERE doc_type_id = ANY(:ids) AND deleted_at IS NULL AND is_active = true
ORDER BY priority DESC
"""
),
{"ids": allIds},
)
).fetchall()
for docTypeId, ruleSetId, *_ in bindingRows:
current = bindingsMap.setdefault(int(docTypeId), [])
normalizedRuleSetId = int(ruleSetId)
if normalizedRuleSetId not in current:
current.append(normalizedRuleSetId)
for b in bindingRows:
bindingsMap.setdefault(int(b[0]), []).append(int(b[1]))
return rows, bindingsMap
async def _queryDocumentTypeRoots(self, Session, Ids: list[int] | None = None, EntryModuleId: int | None = None):
@@ -2198,6 +2182,33 @@ class DocumentServiceImpl(IDocumentService):
async def _loadScoringProposals(self, Session, DocumentId: int) -> list[dict[str, Any]]:
"""读取交叉评分提案;缺表时降级为空。"""
if await self._tableExists(Session, "leaudit_cross_review_proposals"):
rows = (
await Session.execute(
text(
"""
SELECT
id,
rule_result_id AS evaluation_result_id,
proposer_id,
proposed_score_delta AS proposed_score,
reason,
status,
create_time AS created_at,
update_time AS updated_at,
document_id
FROM leaudit_cross_review_proposals
WHERE document_id = :document_id
AND delete_time IS NULL
ORDER BY id DESC
"""
),
{"document_id": DocumentId},
)
).mappings().all()
if rows:
return [dict(row) for row in rows]
if not await self._tableExists(Session, "cross_scoring_proposals"):
return []
@@ -2580,8 +2591,21 @@ class DocumentServiceImpl(IDocumentService):
return str(Row.get("rule_name") or Row.get("rule_id") or "")
async def _syncRuleBindings(self, Session, DocTypeId: int, RuleSetIds: list[int], Region: str = "default") -> None:
"""全量替换规则绑定,仅写入新分组绑定"""
await sync_group_bindings_from_doc_type(Session, DocTypeId, RuleSetIds)
"""全量替换规则绑定。"""
await Session.execute(
text("UPDATE leaudit_rule_type_bindings SET deleted_at = NOW() WHERE doc_type_id = :id AND deleted_at IS NULL"),
{"id": DocTypeId},
)
for idx, ruleSetId in enumerate(RuleSetIds):
await Session.execute(
text(
"""
INSERT INTO leaudit_rule_type_bindings (doc_type_id, rule_set_id, binding_mode, priority, region, is_active, created_at, updated_at)
VALUES (:doc_type_id, :rule_set_id, 'explicit', :priority, :region, true, NOW(), NOW())
"""
),
{"doc_type_id": DocTypeId, "rule_set_id": ruleSetId, "priority": 100 - idx, "region": Region},
)
async def _find_latest_version_candidate(