feat: 账号管理支持按账号名批量选号打标签,并支持复制账号名
This commit is contained in:
@@ -98,6 +98,20 @@ def _query_bool(value) -> bool:
|
||||
return value is True
|
||||
|
||||
|
||||
def _parse_account_names(raw_names: str) -> list[str]:
|
||||
"""解析粘贴的账号名:每行一个,去空白并按输入顺序去重。"""
|
||||
names: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for value in (
|
||||
(raw_names or "").replace("\r\n", "\n").replace("\r", "\n").split("\n")
|
||||
):
|
||||
name = value.strip()
|
||||
if name and name not in seen:
|
||||
names.append(name)
|
||||
seen.add(name)
|
||||
return names
|
||||
|
||||
|
||||
def _filter_accounts_query(
|
||||
db: Session,
|
||||
query,
|
||||
@@ -109,6 +123,7 @@ def _filter_accounts_query(
|
||||
tag: str | None = None,
|
||||
has_cookie: bool = False,
|
||||
search: str = "",
|
||||
account_names: str = "",
|
||||
status: str = "",
|
||||
ck_status: str = "",
|
||||
failure_kind: str = "",
|
||||
@@ -140,6 +155,9 @@ def _filter_accounts_query(
|
||||
tag_value = _query_str(tag)
|
||||
if tag_value:
|
||||
query = query.filter(Account.tag == tag_value)
|
||||
selected_names = _parse_account_names(_query_str(account_names))
|
||||
if selected_names:
|
||||
query = query.filter(Account.username.in_(selected_names))
|
||||
status_value = _query_str(status)
|
||||
if status_value:
|
||||
query = query.filter(Account.status == status_value)
|
||||
@@ -248,6 +266,7 @@ def _selected_account_ids(
|
||||
tag=req.tag,
|
||||
has_cookie=req.has_cookie,
|
||||
search=req.search,
|
||||
account_names=req.account_names,
|
||||
status=req.status,
|
||||
ck_status=req.ck_status,
|
||||
failure_kind=req.failure_kind,
|
||||
@@ -398,6 +417,9 @@ def list_accounts(
|
||||
),
|
||||
assigned_user_id: int | None = Query(None, description="只看某个客服名下的账号"),
|
||||
tag: str = Query(None),
|
||||
account_names: str = Query(
|
||||
"", description="多行斗鱼账号名(每行一个),精确匹配并自动去重"
|
||||
),
|
||||
has_cookie: bool = Query(False),
|
||||
search: str = Query(""),
|
||||
status: str = Query("", description="按生命周期状态筛选;空=全部(不含归档)"),
|
||||
@@ -446,6 +468,7 @@ def list_accounts(
|
||||
tag=tag,
|
||||
has_cookie=has_cookie,
|
||||
search=search,
|
||||
account_names=account_names,
|
||||
status=status,
|
||||
ck_status=ck_status,
|
||||
failure_kind=failure_kind,
|
||||
@@ -623,6 +646,79 @@ def list_accounts(
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/ids")
|
||||
def list_account_ids(
|
||||
assigned_only: bool = Query(False),
|
||||
assign_status: str = Query(""),
|
||||
assigned_user_id: int | None = Query(None),
|
||||
tag: str = Query(None),
|
||||
has_cookie: bool = Query(False),
|
||||
search: str = Query(""),
|
||||
account_names: str = Query(
|
||||
"", description="多行斗鱼账号名(每行一个),精确匹配并自动去重"
|
||||
),
|
||||
status: str = Query(""),
|
||||
ck_status: str = Query(""),
|
||||
failure_kind: str = Query(""),
|
||||
bind_status: str = Query(""),
|
||||
high_value_filter: str = Query(""),
|
||||
min_points: int | None = Query(None),
|
||||
max_points: int | None = Query(None),
|
||||
min_gold: float | None = Query(None),
|
||||
max_gold: float | None = Query(None),
|
||||
elite_opened: bool | None = Query(None),
|
||||
esports_opened: bool | None = Query(None),
|
||||
role_bind_status: str = Query(""),
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(get_current_user),
|
||||
):
|
||||
"""返回当前筛选条件下的全部账号 ID,并按粘贴的账号名顺序排序。
|
||||
|
||||
前端「按账号名批量选号」用它一次性拿到所有匹配 ID,再写入表格的选择集,
|
||||
这样跨分页勾选和后续批量标签都不受当前页限制。
|
||||
"""
|
||||
query = _filter_accounts_query(
|
||||
db,
|
||||
_visible_accounts_query(db, current),
|
||||
current,
|
||||
assigned_only=assigned_only,
|
||||
assign_status=assign_status,
|
||||
assigned_user_id=assigned_user_id,
|
||||
tag=tag,
|
||||
has_cookie=has_cookie,
|
||||
search=search,
|
||||
account_names=account_names,
|
||||
status=status,
|
||||
ck_status=ck_status,
|
||||
failure_kind=failure_kind,
|
||||
bind_status=bind_status,
|
||||
high_value_filter=high_value_filter,
|
||||
min_points=min_points,
|
||||
max_points=max_points,
|
||||
min_gold=min_gold,
|
||||
max_gold=max_gold,
|
||||
elite_opened=elite_opened,
|
||||
esports_opened=esports_opened,
|
||||
role_bind_status=role_bind_status,
|
||||
)
|
||||
selected_names = _parse_account_names(_query_str(account_names))
|
||||
if selected_names:
|
||||
input_order = case(
|
||||
{name: index for index, name in enumerate(selected_names)},
|
||||
value=Account.username,
|
||||
else_=len(selected_names),
|
||||
)
|
||||
query = query.order_by(input_order, Account.id.desc())
|
||||
else:
|
||||
query = query.order_by(Account.id.desc())
|
||||
rows = query.with_entities(Account.id, Account.username).all()
|
||||
return {
|
||||
"account_ids": [account_id for account_id, _ in rows],
|
||||
"usernames": [username for _, username in rows],
|
||||
"total": len(rows),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/summary")
|
||||
def accounts_summary(
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
@@ -130,6 +130,8 @@ class AccountBulkSelection(BaseModel):
|
||||
all_matching: bool = False
|
||||
search: str = ""
|
||||
tag: str = ""
|
||||
#: 多行斗鱼账号名(每行一个),与其它筛选条件叠加
|
||||
account_names: str = ""
|
||||
assigned_only: bool = False
|
||||
#: 归属筛选:""=全部 / unassigned=未分配 / assigned=已分配
|
||||
assign_status: str = ""
|
||||
|
||||
Reference in New Issue
Block a user