fix(C2): 审核台显示文案质量分(总分+7维明细)

审核要能判断,原审核队列接口不返回分数=组长盲审。
- review.py _fmt_queue_item: 解析selected_text.score_json,复用现成
  _score_array_to_obj(tasks.py)算总分+透传维度,绝不读eval_score(留NULL)
- dto.tasks.ts: ReviewQueueItem.selected_text 加 score?:TextScore|null
- ReviewCard.tsx: 复用现成ScoreDimBars组件,passLine=80(合格线红线,
  不用组件默认85)

端到端验:task40审核队列返回total=83+5维明细,新旧维度兼容。tsc EXIT0。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
yangqianqian
2026-06-16 12:28:56 +08:00
parent e3fb6f2655
commit ea423e8a32
3 changed files with 16 additions and 1 deletions

View File

@@ -50,6 +50,7 @@ def review_queue(
def _fmt_queue_item(t: GenerationTask, db: Session) -> dict: def _fmt_queue_item(t: GenerationTask, db: Session) -> dict:
import json import json
from app.models.product import Product from app.models.product import Product
from app.api.v1.tasks import _score_array_to_obj
product = db.query(Product).filter(Product.id == t.product_id).first() product = db.query(Product).filter(Product.id == t.product_id).first()
operator = db.query(User).filter(User.id == t.operator_id).first() operator = db.query(User).filter(User.id == t.operator_id).first()
selected_text = db.query(TextCandidate).filter( selected_text = db.query(TextCandidate).filter(
@@ -67,6 +68,14 @@ def _fmt_queue_item(t: GenerationTask, db: Session) -> dict:
except (json.JSONDecodeError, ValueError): except (json.JSONDecodeError, ValueError):
text_parsed = {"content": selected_text.content} text_parsed = {"content": selected_text.content}
# 质量分:解析 score_json 明细数组算总分+透传维度(绝不读 eval_score,设计留NULL)
text_score = None
if selected_text and selected_text.score_json:
try:
text_score = _score_array_to_obj(json.loads(selected_text.score_json))
except (json.JSONDecodeError, ValueError):
text_score = None
return { return {
"task_id": t.id, "task_id": t.id,
"product_name": product.name if product else None, "product_name": product.name if product else None,
@@ -79,6 +88,7 @@ def _fmt_queue_item(t: GenerationTask, db: Session) -> dict:
"title": text_parsed.get("title", ""), "title": text_parsed.get("title", ""),
"content": text_parsed.get("content", ""), # 纯正文 "content": text_parsed.get("content", ""), # 纯正文
"tags": text_parsed.get("tags", []), "tags": text_parsed.get("tags", []),
"score": text_score, # 审核显分:总分+7维明细(C2)
} if selected_text else None, } if selected_text else None,
"selected_image": { "selected_image": {
"candidate_id": selected_image.id, "candidate_id": selected_image.id,

View File

@@ -4,6 +4,7 @@
* 通过(+5) / 打回(-3必填原因) * 通过(+5) / 打回(-3必填原因)
*/ */
import { ReviewQueueItem } from '@/types/index'; import { ReviewQueueItem } from '@/types/index';
import { ScoreDimBars } from '@/components/tasks/ScoreDimBars';
interface ReviewCardProps { interface ReviewCardProps {
item: ReviewQueueItem; item: ReviewQueueItem;
@@ -30,6 +31,10 @@ export function ReviewCard({ item, onApprove, onReject }: ReviewCardProps) {
{item.selected_text.content} {item.selected_text.content}
</p> </p>
)} )}
{/* 质量分:审核可判断(C2)。合格线80=红线,不用组件默认85 */}
{item.selected_text?.score && (
<ScoreDimBars score={item.selected_text.score} passLine={80} />
)}
</div> </div>
{item.selected_image && ( {item.selected_image && (
<img src={item.selected_image.url} alt="已选图预览" <img src={item.selected_image.url} alt="已选图预览"

View File

@@ -76,7 +76,7 @@ export interface ReviewQueueItem {
theme: string; theme: string;
submitted_at: string; submitted_at: string;
operator_name: string; operator_name: string;
selected_text: { candidate_id: number; angle_label: string; content: string; }; selected_text: { candidate_id: number; angle_label: string; title?: string; content: string; tags?: string[]; score?: TextScore | null; };
selected_image: { candidate_id: number; strategy: 'A' | 'B' | 'C'; url: string; }; selected_image: { candidate_id: number; strategy: 'A' | 'B' | 'C'; url: string; };
} }