feat(douyu): 支持批量导出用户名

This commit is contained in:
yml2213
2026-10-23 09:52:47 +08:00
parent bf2f120fdc
commit f074b75871
6 changed files with 322 additions and 1 deletions
+21
View File
@@ -44,6 +44,8 @@ from ..schemas import (
DouyuCollabStatusRequest,
DouyuCollabSummaryOut,
DouyuCollabTimelineOut,
DouyuCollabUsernameExportOut,
DouyuCollabUsernameExportRequest,
)
from ..services import douyu_collab_service as collab
from ..services.douyu_collab_events import collab_events
@@ -369,6 +371,25 @@ def copy_external_order_ck(
raise _http_error(exc) from exc
@router.post(
"/external-orders/usernames/export",
response_model=DouyuCollabUsernameExportOut,
)
def export_external_order_usernames(
req: DouyuCollabUsernameExportRequest,
db: Session = Depends(get_db),
_current: User = Depends(require_permission("douyu:collab:view")),
):
"""勾选多行导出关联的斗鱼用户名(前端写剪贴板)。
用户名不是凭据;能看列表的人本来就能看到,因此只需要查看权限。
"""
try:
return collab.export_usernames(db, req.ids)
except collab.CollabError as exc:
raise _http_error(exc) from exc
@router.post("/external-orders/{order_id}/activity/query")
def query_external_order_activity(
order_id: int,
+29
View File
@@ -1906,6 +1906,35 @@ class DouyuCollabCkExportOut(BaseModel):
items: list[DouyuCollabCkExportItemOut] = Field(default_factory=list)
class DouyuCollabUsernameExportRequest(BaseModel):
"""勾选多行,导出关联的斗鱼用户名(一次最多 500 条)。"""
ids: list[int] = Field(default_factory=list)
class DouyuCollabUsernameExportItemOut(BaseModel):
id: int
order_no: str = ""
account_username: str = ""
class DouyuCollabUsernameExportSkippedOut(BaseModel):
id: int
order_no: str = ""
reason: str = ""
class DouyuCollabUsernameExportOut(BaseModel):
"""``exported`` 是按单计数,``unique`` 是去重后的用户名个数。"""
total: int
exported: int
unique: int
skipped: list[DouyuCollabUsernameExportSkippedOut] = Field(default_factory=list)
items: list[DouyuCollabUsernameExportItemOut] = Field(default_factory=list)
usernames: list[str] = Field(default_factory=list)
class DouyuCollabOrderOut(BaseModel):
id: int
order_no: str
@@ -106,6 +106,7 @@ POINTS_THRESHOLD_MAX = 1_000_000
MAX_IMAGES = 20
CK_EXPORT_BATCH_MAX = 50
CK_EXPORT_ACTION = "douyu:collab:ck_export"
USERNAME_EXPORT_BATCH_MAX = 500
VERDICT_SUCCESS = "success"
VERDICT_FAILED = "failed"
@@ -2084,3 +2085,75 @@ def export_cks(
"skipped": skipped,
"items": items,
}
def export_usernames(
db: Session,
order_ids: Sequence[int],
) -> dict[str, Any]:
"""导出勾选订单关联的斗鱼用户名(去重、保持选择顺序)。
用户名不是凭据,能看列表的人本来就能看到,所以这里不额外要求 CK 导出权限,
也不写审计;没有用户名的行会显式跳过。
"""
requested = list(dict.fromkeys(int(item) for item in order_ids if item))
if not requested:
raise CollabError("请先勾选要导出的行", code="username_export_empty")
if len(requested) > USERNAME_EXPORT_BATCH_MAX:
raise CollabError(
f"一次最多导出 {USERNAME_EXPORT_BATCH_MAX} 行,请分批操作",
code="username_export_too_large",
)
rows = (
db.query(DouyuExternalOrder).filter(DouyuExternalOrder.id.in_(requested)).all()
)
by_id = {int(order.id): order for order in rows}
items: list[dict[str, Any]] = []
skipped: list[dict[str, Any]] = []
usernames: list[str] = []
seen: set[str] = set()
for order_id in requested:
order = by_id.get(order_id)
if order is None:
skipped.append(
{
"id": order_id,
"order_no": "",
"reason": "协作单不存在或已删除",
}
)
continue
username = str(order.account_username or "").strip()
if not username:
account = account_by_id(db, order.account_id) or account_by_username(
db, order.account_username
)
username = str(account.username if account else "").strip()
if not username:
skipped.append(
{
"id": int(order.id),
"order_no": order.order_no,
"reason": "这单还没填斗鱼用户名",
}
)
continue
items.append(
{
"id": int(order.id),
"order_no": order.order_no,
"account_username": username,
}
)
if username not in seen:
seen.add(username)
usernames.append(username)
return {
"total": len(requested),
"exported": len(items),
"unique": len(usernames),
"skipped": skipped,
"items": items,
"usernames": usernames,
}