feat: 交叉评查后端优化 — 评查地区、文档评查统计、currentScore、错误提示
- GetUserTasks: 新增 task_regions CTE,从任务成员 sso_users.area 去重收集 evaluationRegion - GetTaskDocuments: 新增 es LATERAL 子查询聚合 leaudit_rule_results 的 pass_count/warning_count/error_count/score_percent;path/uploadTime 改为从 leaudit_document_files 获取;新增 fileExt - ReviewPointResultVO: 新增 currentScore 字段 - _loadReviewPointResults: SQL 新增 approved_delta LATERAL 子查询,currentScore = base_score + SUM(approved_deltas) - CrossReviewTaskItemVO: 新增 evaluationRegion - CrossReviewTaskDocumentVO: 新增 18 个评查统计字段 + path/uploadTime/fileExt - 文档更新:交叉评查核心模块业务逻辑文档补充评查地区、评查统计、版本号本地化等章节
This commit is contained in:
@@ -303,6 +303,17 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
FROM leaudit_cross_review_task_documents td
|
||||
WHERE td.delete_time IS NULL
|
||||
GROUP BY td.task_id
|
||||
),
|
||||
task_regions AS (
|
||||
SELECT
|
||||
tm.task_id,
|
||||
ARRAY_AGG(DISTINCT u.area ORDER BY u.area) FILTER (
|
||||
WHERE u.area IS NOT NULL AND u.area != ''
|
||||
) AS evaluation_regions
|
||||
FROM leaudit_cross_review_task_members tm
|
||||
JOIN sso_users u ON u.id = tm.user_id
|
||||
WHERE tm.delete_time IS NULL
|
||||
GROUP BY tm.task_id
|
||||
)
|
||||
SELECT
|
||||
t.id AS task_id,
|
||||
@@ -313,16 +324,20 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
t.status,
|
||||
t.create_time,
|
||||
COALESCE(ds.total_documents, 0) AS total_documents,
|
||||
COALESCE(ds.completed_documents, 0) AS completed_documents
|
||||
COALESCE(ds.completed_documents, 0) AS completed_documents,
|
||||
COALESCE(tr.evaluation_regions, ARRAY[]::varchar[]) AS evaluation_regions
|
||||
FROM leaudit_cross_review_tasks t
|
||||
JOIN leaudit_cross_review_task_members tm
|
||||
ON tm.task_id = t.id
|
||||
LEFT JOIN doc_stats ds
|
||||
ON ds.task_id = t.id
|
||||
LEFT JOIN task_regions tr
|
||||
ON tr.task_id = t.id
|
||||
WHERE {whereSql}
|
||||
GROUP BY
|
||||
t.id, t.task_name, t.task_type, t.doc_type_id, t.doc_type_code,
|
||||
t.status, t.create_time, ds.total_documents, ds.completed_documents
|
||||
t.status, t.create_time, ds.total_documents, ds.completed_documents,
|
||||
tr.evaluation_regions
|
||||
ORDER BY t.create_time DESC, t.id DESC
|
||||
LIMIT :limit OFFSET :offset
|
||||
"""
|
||||
@@ -336,6 +351,13 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
totalDocuments = int(row["total_documents"] or 0)
|
||||
completedDocuments = int(row["completed_documents"] or 0)
|
||||
progress = round((completedDocuments / totalDocuments * 100) if totalDocuments > 0 else 0, 2)
|
||||
rawRegions = row.get("evaluation_regions")
|
||||
if rawRegions is None:
|
||||
evaluationRegion: list[str] = []
|
||||
elif isinstance(rawRegions, list):
|
||||
evaluationRegion = [str(r) for r in rawRegions]
|
||||
else:
|
||||
evaluationRegion = [str(rawRegions)]
|
||||
items.append(
|
||||
CrossReviewTaskItemVO(
|
||||
taskId=int(row["task_id"]),
|
||||
@@ -348,6 +370,7 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
totalDocuments=totalDocuments,
|
||||
completedDocuments=completedDocuments,
|
||||
createdAt=row.get("create_time"),
|
||||
evaluationRegion=evaluationRegion,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -453,7 +476,24 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
d.created_at,
|
||||
td.audit_status,
|
||||
COALESCE(dt.name, '') AS type_name,
|
||||
COALESCE(df.file_size, 0) AS file_size
|
||||
COALESCE(df.file_size, 0) AS file_size,
|
||||
COALESCE(df.file_path, '') AS path,
|
||||
df.file_upload_time AS upload_time,
|
||||
COALESCE(df.file_ext, '') AS file_ext,
|
||||
COALESCE(es.total_evaluation_points, 0) AS total_evaluation_points,
|
||||
COALESCE(es.pass_count, 0) AS pass_count,
|
||||
COALESCE(es.warning_count, 0) AS warning_count,
|
||||
COALESCE(es.error_count, 0) AS error_count,
|
||||
COALESCE(es.manual_count, 0) AS manual_count,
|
||||
COALESCE(es.issue_count, 0) AS issue_count,
|
||||
COALESCE(es.warning_messages, ARRAY[]::text[]) AS warning_messages,
|
||||
COALESCE(es.error_messages, ARRAY[]::text[]) AS error_messages,
|
||||
COALESCE(es.issue_messages, ARRAY[]::text[]) AS issue_messages,
|
||||
COALESCE(es.manual_messages, ARRAY[]::text[]) AS manual_messages,
|
||||
COALESCE(es.final_score, 0) AS final_score,
|
||||
COALESCE(es.full_score, 0) AS full_score,
|
||||
COALESCE(es.score_summary, '') AS score_summary,
|
||||
COALESCE(es.score_percent, 0) AS score_percent
|
||||
FROM leaudit_cross_review_task_documents td
|
||||
JOIN leaudit_documents d
|
||||
ON d.id = td.document_id
|
||||
@@ -462,7 +502,8 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = d.type_id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT file_size
|
||||
SELECT file_size, local_path AS file_path, created_at AS file_upload_time,
|
||||
COALESCE(file_ext, '') AS file_ext
|
||||
FROM leaudit_document_files
|
||||
WHERE document_id = d.id
|
||||
ORDER BY id ASC
|
||||
@@ -478,6 +519,51 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
WHERE d2.deleted_at IS NULL
|
||||
GROUP BY d2.version_group_key
|
||||
) vc ON vc.version_group_key = d.version_group_key
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
COUNT(*)::int AS total_evaluation_points,
|
||||
COUNT(*) FILTER (WHERE rr.passed IS TRUE)::int AS pass_count,
|
||||
COUNT(*) FILTER (WHERE rr.passed IS FALSE AND rr.risk = 'high')::int AS error_count,
|
||||
COUNT(*) FILTER (WHERE rr.passed IS FALSE AND rr.risk IN ('low', 'medium'))::int AS warning_count,
|
||||
0::int AS manual_count,
|
||||
COUNT(*) FILTER (WHERE rr.passed IS FALSE)::int AS issue_count,
|
||||
ARRAY_AGG(rr.fail_message ORDER BY rr.id) FILTER (
|
||||
WHERE rr.passed IS FALSE AND rr.risk = 'high' AND rr.fail_message IS NOT NULL AND rr.fail_message != ''
|
||||
) AS error_messages,
|
||||
ARRAY_AGG(rr.fail_message ORDER BY rr.id) FILTER (
|
||||
WHERE rr.passed IS FALSE AND rr.risk IN ('low', 'medium') AND rr.fail_message IS NOT NULL AND rr.fail_message != ''
|
||||
) AS warning_messages,
|
||||
ARRAY_AGG(rr.fail_message ORDER BY rr.id) FILTER (
|
||||
WHERE rr.passed IS FALSE AND rr.fail_message IS NOT NULL AND rr.fail_message != ''
|
||||
) AS issue_messages,
|
||||
ARRAY[]::text[] AS manual_messages,
|
||||
COALESCE(SUM(rr.score) FILTER (WHERE rr.passed IS TRUE), 0) AS final_score,
|
||||
COALESCE(SUM(rr.score), 0) AS full_score,
|
||||
CASE
|
||||
WHEN COALESCE(SUM(rr.score), 0) > 0
|
||||
THEN CONCAT(
|
||||
ROUND(
|
||||
COALESCE(SUM(rr.score) FILTER (WHERE rr.passed IS TRUE), 0)::numeric,
|
||||
1
|
||||
)::text,
|
||||
'/',
|
||||
ROUND(COALESCE(SUM(rr.score), 0)::numeric, 1)::text
|
||||
)
|
||||
ELSE '0/0'
|
||||
END AS score_summary,
|
||||
CASE
|
||||
WHEN COALESCE(SUM(rr.score), 0) > 0
|
||||
THEN ROUND(
|
||||
COALESCE(SUM(rr.score) FILTER (WHERE rr.passed IS TRUE), 0)
|
||||
/ SUM(rr.score) * 100,
|
||||
1
|
||||
)
|
||||
ELSE 0
|
||||
END AS score_percent
|
||||
FROM leaudit_rule_results rr
|
||||
WHERE rr.document_id = d.id
|
||||
AND rr.run_id = d.current_run_id
|
||||
) es ON TRUE
|
||||
WHERE {whereSql}
|
||||
ORDER BY d.created_at DESC, d.id DESC
|
||||
LIMIT :limit OFFSET :offset
|
||||
@@ -502,6 +588,23 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
auditStatus=int(row.get("audit_status") or 0),
|
||||
createdAt=row.get("created_at"),
|
||||
fileSize=int(row.get("file_size") or 0),
|
||||
path=str(row.get("path") or ""),
|
||||
uploadTime=row.get("upload_time"),
|
||||
fileExt=str(row.get("file_ext") or "") or None,
|
||||
totalEvaluationPoints=int(row.get("total_evaluation_points") or 0),
|
||||
passCount=int(row.get("pass_count") or 0),
|
||||
warningCount=int(row.get("warning_count") or 0),
|
||||
errorCount=int(row.get("error_count") or 0),
|
||||
manualCount=int(row.get("manual_count") or 0),
|
||||
issueCount=int(row.get("issue_count") or 0),
|
||||
warningMessages=self._parse_text_array(row.get("warning_messages")),
|
||||
errorMessages=self._parse_text_array(row.get("error_messages")),
|
||||
issueMessages=self._parse_text_array(row.get("issue_messages")),
|
||||
manualMessages=self._parse_text_array(row.get("manual_messages")),
|
||||
finalScore=float(row.get("final_score") or 0),
|
||||
fullScore=float(row.get("full_score") or 0),
|
||||
scoreSummary=str(row.get("score_summary") or ""),
|
||||
scorePercent=float(row.get("score_percent") or 0),
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
@@ -1411,3 +1514,11 @@ class CrossReviewServiceImpl(ICrossReviewService):
|
||||
if value is None:
|
||||
return None
|
||||
return int(value)
|
||||
|
||||
def _parse_text_array(self, value) -> list[str]:
|
||||
"""安全解析 PostgreSQL text[] 为字符串列表。"""
|
||||
if value is None:
|
||||
return []
|
||||
if isinstance(value, list):
|
||||
return [str(v) for v in value]
|
||||
return [str(value)]
|
||||
|
||||
Reference in New Issue
Block a user