feat(huya): 协作台账勾选导出 CK 到剪贴板(单点权限 + 逐行审计)+ 工具区固定两行
This commit is contained in:
@@ -53,6 +53,8 @@ PERMISSIONS = {
|
||||
"huya:collab:view": "查看外部 CK 协作台账",
|
||||
"huya:collab:edit": "编辑外部 CK 协作台账",
|
||||
"huya:collab:manage": "删除外部 CK 协作台账",
|
||||
# CK 是凭据:导到剪贴板 = 把凭据带出系统,单独一个点(同 cookie:export 的口径),默认只给运营
|
||||
"huya:collab:ck_export": "导出外部 CK 协作台账的 CK(写剪贴板)",
|
||||
# 代理 & 白名单
|
||||
"proxy:manage": "代理配置管理",
|
||||
"whitelist:manage": "白名单配置管理",
|
||||
@@ -105,6 +107,7 @@ ROLE_PERMISSIONS = {
|
||||
"huya:collab:view",
|
||||
"huya:collab:edit",
|
||||
"huya:collab:manage",
|
||||
"huya:collab:ck_export",
|
||||
"proxy:manage",
|
||||
"whitelist:manage",
|
||||
"whitelist:test",
|
||||
@@ -125,6 +128,8 @@ ROLE_PERMISSIONS = {
|
||||
# 客服能看能改(共享表,靠审计留痕),但删除只给运营。
|
||||
"huya:collab:view",
|
||||
"huya:collab:edit",
|
||||
# 注意:**不给** huya:collab:ck_export —— 贴 CK 是「录入」,导出是「把凭据带走」,
|
||||
# 需要时在权限页单独勾(口径同 huya:cookie:export,见设计文档 §11.8)。
|
||||
"file:view",
|
||||
"file:upload",
|
||||
],
|
||||
|
||||
@@ -34,6 +34,8 @@ from ...schemas import (
|
||||
HuyaExternalOrderActivityQueryOut,
|
||||
HuyaExternalOrderActivityQueryRequest,
|
||||
HuyaExternalOrderAuditOut,
|
||||
HuyaExternalOrderCkExportOut,
|
||||
HuyaExternalOrderCkExportRequest,
|
||||
HuyaExternalOrderCkRequest,
|
||||
HuyaExternalOrderCkStatusRequest,
|
||||
HuyaExternalOrderCreate,
|
||||
@@ -375,6 +377,25 @@ def verify_external_orders_ck(
|
||||
raise _http_error(exc) from exc
|
||||
|
||||
|
||||
@router.post("/external-orders/ck/export", response_model=HuyaExternalOrderCkExportOut)
|
||||
def export_external_orders_ck(
|
||||
req: HuyaExternalOrderCkExportRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(require_permission("huya:collab:ck_export")),
|
||||
):
|
||||
"""勾选多行导出 **CK 明文**(前端写进剪贴板)。
|
||||
|
||||
单独一个权限点 ``huya:collab:ck_export``(默认只给运营):贴 CK 是「录入」,
|
||||
导出是「把凭据带走」。逐行写审计(``huya:collab:ck_export``),但**只记单号**,
|
||||
不把 CK 本体写进审计;没 CK 的行在 ``skipped`` 里显式回原因。
|
||||
"""
|
||||
try:
|
||||
orders = collab.list_orders_by_ids(db, req.ids)
|
||||
return collab.export_cks(db, current, orders)
|
||||
except collab.CollabError as exc:
|
||||
raise _http_error(exc) from exc
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 单行操作
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
@@ -1304,6 +1304,43 @@ class HuyaExternalOrderActivityQueryRequest(BaseModel):
|
||||
ids: list[int] = Field(default_factory=list)
|
||||
|
||||
|
||||
class HuyaExternalOrderCkExportRequest(BaseModel):
|
||||
"""勾选多行,导出这些行的 CK 明文(前端写剪贴板;一次最多 50 条)。"""
|
||||
|
||||
ids: list[int] = Field(default_factory=list)
|
||||
|
||||
|
||||
class HuyaExternalOrderCkExportItemOut(BaseModel):
|
||||
"""导出结果里的一行:``ck_text`` 是**明文凭据**,只走这个接口、不留日志。"""
|
||||
|
||||
id: int
|
||||
order_no: str = ""
|
||||
uid: str = ""
|
||||
nickname: str = ""
|
||||
status: str = ""
|
||||
status_label: str = ""
|
||||
ck_status: str = ""
|
||||
ck_status_label: str = ""
|
||||
ck_text: str = ""
|
||||
|
||||
|
||||
class HuyaExternalOrderCkExportSkippedOut(BaseModel):
|
||||
"""没导出的行(例如这行还没贴 CK)——把原因显式回给前端,别静默丢。"""
|
||||
|
||||
id: int
|
||||
order_no: str = ""
|
||||
reason: str = ""
|
||||
|
||||
|
||||
class HuyaExternalOrderCkExportOut(BaseModel):
|
||||
"""导出 CK 的结果:``exported + len(skipped) = total``。"""
|
||||
|
||||
total: int
|
||||
exported: int
|
||||
skipped: list[HuyaExternalOrderCkExportSkippedOut] = Field(default_factory=list)
|
||||
items: list[HuyaExternalOrderCkExportItemOut] = Field(default_factory=list)
|
||||
|
||||
|
||||
class HuyaCollabMetricMatchedOut(BaseModel):
|
||||
"""匹配到的那条兑换记录(只留界面要用的几个字段)。"""
|
||||
|
||||
|
||||
@@ -1678,6 +1678,90 @@ def list_orders_by_ids(db: Session, ids: Sequence[int]) -> list[HuyaExternalOrde
|
||||
return [by_id[value] for value in wanted if value in by_id]
|
||||
|
||||
|
||||
# 导出 CK 的审计动作名(导出=把凭据带出系统,必须留痕)
|
||||
CK_EXPORT_ACTION = "huya:collab:ck_export"
|
||||
|
||||
|
||||
def export_cks(
|
||||
db: Session,
|
||||
current: User | None,
|
||||
orders: Sequence[HuyaExternalOrder],
|
||||
*,
|
||||
commit: bool = True,
|
||||
) -> dict:
|
||||
"""把勾选行的 **CK 明文**取出来(前端写剪贴板用)。
|
||||
|
||||
这是本模块唯一一个把凭据**往外送**的读接口,所以三条约束写死在这里:
|
||||
|
||||
1. **权限单独一个点**(``huya:collab:ck_export``,默认只给运营)—— 贴 CK 是「录入」,
|
||||
导出是「把凭据带走」,两件事不该共用一个权限(口径同 ``huya:cookie:export``);
|
||||
2. **逐行写审计**(``huya:collab:ck_export``):只记「谁在什么时候导出了哪一单」,
|
||||
**绝不把 CK 本体写进审计/日志**(列表接口也照旧不返回 cookie);
|
||||
3. **没 CK 的行显式跳过并回原因**,不静默丢;也不替用户猜 ——
|
||||
作废/停用的单只要还有 CK 照样导出,界面把状态标出来让人自己判断。
|
||||
|
||||
Returns:
|
||||
``{total, exported, skipped: [{id, order_no, reason}], items: [{..., ck_text}]}``
|
||||
——只有这个接口会返回 ``ck_text``。
|
||||
"""
|
||||
rows = list(orders)
|
||||
if not rows:
|
||||
raise CollabError("请先勾选要导出的行", code="ck_export_empty")
|
||||
if len(rows) > PROBE_BATCH_MAX:
|
||||
raise CollabError(
|
||||
f"一次最多导出 {PROBE_BATCH_MAX} 行,请分批操作", code="ck_export_too_large"
|
||||
)
|
||||
|
||||
items: list[dict] = []
|
||||
skipped: list[dict] = []
|
||||
for order in rows:
|
||||
ck_text = str(order.cookie or "").strip()
|
||||
if not ck_text:
|
||||
skipped.append(
|
||||
{
|
||||
"id": int(order.id),
|
||||
"order_no": order.order_no,
|
||||
"reason": "这行还没贴 CK",
|
||||
}
|
||||
)
|
||||
continue
|
||||
items.append(
|
||||
{
|
||||
"id": int(order.id),
|
||||
"order_no": order.order_no,
|
||||
"uid": str(order.uid or ""),
|
||||
"nickname": order.nickname or "",
|
||||
"status": order.status,
|
||||
"status_label": ORDER_STATUS_LABELS.get(order.status, order.status),
|
||||
"ck_status": order.ck_status,
|
||||
"ck_status_label": CK_STATUS_LABELS.get(
|
||||
order.ck_status, order.ck_status
|
||||
),
|
||||
"ck_text": ck_text,
|
||||
}
|
||||
)
|
||||
record_audit(
|
||||
db,
|
||||
current,
|
||||
action=CK_EXPORT_ACTION,
|
||||
target=_audit_target(order),
|
||||
detail={
|
||||
"order_no": order.order_no,
|
||||
"uid": str(order.uid or ""),
|
||||
"ck_status": order.ck_status,
|
||||
"batch_size": len(rows),
|
||||
},
|
||||
)
|
||||
if commit:
|
||||
db.commit()
|
||||
return {
|
||||
"total": len(rows),
|
||||
"exported": len(items),
|
||||
"skipped": skipped,
|
||||
"items": items,
|
||||
}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 店铺字典(新建协作单时点一下选;也支持自定义输入)
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user