feat: show fission records in history
This commit is contained in:
@@ -183,10 +183,13 @@ def list_tasks(
|
||||
):
|
||||
from datetime import datetime, timedelta
|
||||
from app.models.product import Product
|
||||
include_fission = bool(status and "fission" in status)
|
||||
task_statuses = [s for s in (status or []) if s != "fission"]
|
||||
|
||||
q = db.query(GenerationTask).filter(GenerationTask.workspace_id == current_user.workspace_id)
|
||||
if status:
|
||||
if task_statuses:
|
||||
# 支持多状态(?status=approved&status=rejected),单值也兼容
|
||||
q = q.filter(GenerationTask.status.in_(status))
|
||||
q = q.filter(GenerationTask.status.in_(task_statuses))
|
||||
if product_id is not None:
|
||||
q = q.filter(GenerationTask.product_id == product_id)
|
||||
# 日期筛选:date 形参非法 → 40001(不静默吞成全量,防运营误判)
|
||||
@@ -200,19 +203,99 @@ def list_tasks(
|
||||
except ValueError:
|
||||
from app.core.response import raise_param_error
|
||||
raise_param_error("date_from/date_to 需为 YYYY-MM-DD 格式")
|
||||
total = q.count()
|
||||
items = q.order_by(GenerationTask.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all()
|
||||
if not include_fission:
|
||||
total = q.count()
|
||||
items = q.order_by(GenerationTask.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all()
|
||||
# product_name 一次性批量查(防 N+1):收集本页 product_id → id→name dict
|
||||
pids = {t.product_id for t in items if t.product_id}
|
||||
name_map: dict[int, str] = {}
|
||||
if pids:
|
||||
for p in db.query(Product.id, Product.name).filter(Product.id.in_(pids)).all():
|
||||
name_map[p.id] = p.name
|
||||
rows = []
|
||||
for t in items:
|
||||
d = _fmt_task(t)
|
||||
d["item_type"] = "task"
|
||||
d["product_name"] = name_map.get(t.product_id)
|
||||
rows.append(d)
|
||||
return ok(paginate(rows, total, page, page_size))
|
||||
|
||||
from app.models.fission import FissionTask, FissionNote
|
||||
|
||||
task_items = q.all() if task_statuses else []
|
||||
fission_q = db.query(FissionTask).filter(FissionTask.workspace_id == current_user.workspace_id)
|
||||
try:
|
||||
if date_from:
|
||||
fission_q = fission_q.filter(FissionTask.created_at >= datetime.fromisoformat(date_from))
|
||||
if date_to:
|
||||
_end = datetime.fromisoformat(date_to) + timedelta(days=1)
|
||||
fission_q = fission_q.filter(FissionTask.created_at < _end)
|
||||
except ValueError:
|
||||
from app.core.response import raise_param_error
|
||||
raise_param_error("date_from/date_to 需为 YYYY-MM-DD 格式")
|
||||
fission_items = fission_q.all()
|
||||
|
||||
source_ids = {f.source_task_id for f in fission_items if f.source_task_id}
|
||||
source_tasks: dict[int, GenerationTask] = {}
|
||||
if source_ids:
|
||||
for t in db.query(GenerationTask).filter(GenerationTask.id.in_(source_ids)).all():
|
||||
if t.workspace_id == current_user.workspace_id:
|
||||
source_tasks[t.id] = t
|
||||
if product_id is not None:
|
||||
fission_items = [
|
||||
f for f in fission_items
|
||||
if f.source_task_id and source_tasks.get(f.source_task_id)
|
||||
and source_tasks[f.source_task_id].product_id == product_id
|
||||
]
|
||||
|
||||
# product_name 一次性批量查(防 N+1):收集本页 product_id → id→name dict
|
||||
pids = {t.product_id for t in items if t.product_id}
|
||||
pids = {t.product_id for t in task_items if t.product_id}
|
||||
pids.update(
|
||||
t.product_id for t in source_tasks.values()
|
||||
if t.product_id and (product_id is None or t.product_id == product_id)
|
||||
)
|
||||
name_map: dict[int, str] = {}
|
||||
if pids:
|
||||
for p in db.query(Product.id, Product.name).filter(Product.id.in_(pids)).all():
|
||||
name_map[p.id] = p.name
|
||||
rows = []
|
||||
for t in items:
|
||||
for t in task_items:
|
||||
d = _fmt_task(t)
|
||||
d["item_type"] = "task"
|
||||
d["product_name"] = name_map.get(t.product_id)
|
||||
rows.append(d)
|
||||
for f in fission_items:
|
||||
source = source_tasks.get(f.source_task_id) if f.source_task_id else None
|
||||
notes = db.query(FissionNote).filter(
|
||||
FissionNote.fission_id == f.id,
|
||||
FissionNote.workspace_id == current_user.workspace_id,
|
||||
).all()
|
||||
image_count = 0
|
||||
for n in notes:
|
||||
import json
|
||||
try:
|
||||
images = json.loads(n.images_json) if n.images_json else []
|
||||
except (TypeError, ValueError):
|
||||
images = []
|
||||
image_count += sum(1 for im in images if isinstance(im, dict) and im.get("url") and not im.get("error"))
|
||||
rows.append({
|
||||
"id": f.id,
|
||||
"item_type": "fission",
|
||||
"product_id": source.product_id if source else 0,
|
||||
"product_name": name_map.get(source.product_id) if source else None,
|
||||
"theme": (source.theme if source and source.theme else f"裂变笔记 #{f.id}"),
|
||||
"status": "fission",
|
||||
"created_at": f.created_at.isoformat(),
|
||||
"text_count": len(notes),
|
||||
"image_count": image_count,
|
||||
"review_status": None,
|
||||
"reject_reason": None,
|
||||
"reviewed_at": None,
|
||||
})
|
||||
rows.sort(key=lambda x: x["created_at"], reverse=True)
|
||||
total = len(rows)
|
||||
start = (page - 1) * page_size
|
||||
rows = rows[start:start + page_size]
|
||||
return ok(paginate(rows, total, page, page_size))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user