feat(douyu): 支持批量导出用户名
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user