fix(assignments): 未分配列表不再混入 CK 失效账号
分配池统一为:持 CK、CK 未判失效、未被停用/归档。新增 assignable_only 参数贯穿账号列表、批量分配与分配概览;前端列表与一键全部分配使用同一口径。
This commit is contained in:
@@ -55,10 +55,7 @@ from ..services.account_lifecycle import (
|
||||
STATUS_MANUAL,
|
||||
set_manual_state,
|
||||
)
|
||||
from ..services.account_service import (
|
||||
cookie_account_ids_query,
|
||||
parse_and_build_accounts,
|
||||
)
|
||||
from ..services.account_service import parse_and_build_accounts
|
||||
from ..services.account_value import (
|
||||
SUIT_BAIRIMENG,
|
||||
SUIT_MENGTU,
|
||||
@@ -84,6 +81,23 @@ def _visible_accounts_query(db: Session, current: User):
|
||||
raise HTTPException(status_code=403, detail="无权查看账号")
|
||||
|
||||
|
||||
def _assignable_account_filter():
|
||||
"""分配池口径:有 CK 且 CK **还没被判失效**,并且没被人工停用/归档。
|
||||
|
||||
- `ck_check_status` 为空 = 还没检测过(`derive_status` 同样按可用处理);
|
||||
- `error` = 本轮查不到,不代表失效,照常留在池子里;
|
||||
- `invalid` = 巡检已判失效,必须先重登/修复,分配给它也跑不了任何任务。
|
||||
"""
|
||||
return and_(
|
||||
cookie_holding_filter(),
|
||||
or_(Account.ck_check_status.is_(None), Account.ck_check_status != "invalid"),
|
||||
or_(
|
||||
Account.status.is_(None),
|
||||
Account.status.notin_([STATUS_DISABLED, STATUS_ARCHIVED]),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _query_str(value) -> str:
|
||||
"""把查询参数安全地取成字符串。
|
||||
|
||||
@@ -120,6 +134,7 @@ def _filter_accounts_query(
|
||||
assigned_only: bool = False,
|
||||
assign_status: str = "",
|
||||
assigned_user_id: int | None = None,
|
||||
assignable_only: bool = False,
|
||||
tag: str | None = None,
|
||||
has_cookie: bool = False,
|
||||
search: str = "",
|
||||
@@ -140,6 +155,8 @@ def _filter_accounts_query(
|
||||
"""复用列表筛选条件,供分页列表和全量批量操作保持一致。"""
|
||||
if _query_bool(has_cookie):
|
||||
query = query.filter(Account.cookie.isnot(None), Account.cookie != "")
|
||||
if _query_bool(assignable_only):
|
||||
query = query.filter(_assignable_account_filter())
|
||||
if _query_bool(assigned_only) and user_has_permission(current, "account:view_all"):
|
||||
query = query.filter(Account.assigned_to.isnot(None))
|
||||
# 归属筛选:未分配 / 已分配,再叠加「指定客服」。与其它条件(标签、CK、
|
||||
@@ -263,6 +280,7 @@ def _selected_account_ids(
|
||||
assigned_only=req.assigned_only,
|
||||
assign_status=req.assign_status,
|
||||
assigned_user_id=req.assigned_user_id,
|
||||
assignable_only=req.assignable_only,
|
||||
tag=req.tag,
|
||||
has_cookie=req.has_cookie,
|
||||
search=req.search,
|
||||
@@ -416,6 +434,10 @@ def list_accounts(
|
||||
"", description="归属筛选:unassigned=未分配 / assigned=已分配;空=全部"
|
||||
),
|
||||
assigned_user_id: int | None = Query(None, description="只看某个客服名下的账号"),
|
||||
assignable_only: bool = Query(
|
||||
False,
|
||||
description="只看可分配账号:持 CK 且 CK 未失效(排除已停用/归档)",
|
||||
),
|
||||
tag: str = Query(None),
|
||||
account_names: str = Query(
|
||||
"", description="多行斗鱼账号名(每行一个),精确匹配并自动去重"
|
||||
@@ -465,6 +487,7 @@ def list_accounts(
|
||||
assigned_only=assigned_only,
|
||||
assign_status=assign_status,
|
||||
assigned_user_id=assigned_user_id,
|
||||
assignable_only=assignable_only,
|
||||
tag=tag,
|
||||
has_cookie=has_cookie,
|
||||
search=search,
|
||||
@@ -1113,15 +1136,18 @@ def assignments_summary(
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(require_permission("account:assign")),
|
||||
):
|
||||
"""分配概览:每个客服分配了多少账号(仅统计当前仍持有 CK 的账号)。"""
|
||||
"""分配概览:每个客服分到了多少**可分配账号**(持 CK 且 CK 未失效)。
|
||||
|
||||
失效 CK 的账号必须先重登/修复,放进分配池只会让客服以为能跑任务,
|
||||
所以列表、全量分配与这里的统计统一用 `_assignable_account_filter()`。
|
||||
"""
|
||||
results = (
|
||||
db.query(User.id, User.username, func.count(Account.id).label("count"))
|
||||
.outerjoin(
|
||||
Account,
|
||||
and_(
|
||||
Account.assigned_to == User.id,
|
||||
Account.cookie.isnot(None),
|
||||
Account.cookie != "",
|
||||
_assignable_account_filter(),
|
||||
),
|
||||
)
|
||||
.filter(User.role == "support")
|
||||
@@ -1133,8 +1159,7 @@ def assignments_summary(
|
||||
db.query(func.count(Account.id))
|
||||
.filter(
|
||||
Account.assigned_to.is_(None),
|
||||
Account.cookie.isnot(None),
|
||||
Account.cookie != "",
|
||||
_assignable_account_filter(),
|
||||
)
|
||||
.scalar()
|
||||
) or 0
|
||||
|
||||
@@ -207,6 +207,8 @@ class AccountBulkSelection(BaseModel):
|
||||
assign_status: str = ""
|
||||
#: 只看某个客服名下的账号(与 assign_status 可叠加)
|
||||
assigned_user_id: int | None = None
|
||||
#: 分配池口径:持 CK 且 CK 未失效(排除停用/归档)
|
||||
assignable_only: bool = False
|
||||
has_cookie: bool = False
|
||||
status: str = ""
|
||||
ck_status: str = ""
|
||||
|
||||
@@ -25,6 +25,7 @@ export const accountApi = {
|
||||
assigned_only?: boolean;
|
||||
assign_status?: string;
|
||||
assigned_user_id?: number;
|
||||
assignable_only?: boolean;
|
||||
tag?: string;
|
||||
has_cookie?: boolean;
|
||||
include_sensitive?: boolean;
|
||||
|
||||
@@ -36,6 +36,8 @@ export interface AccountBulkSelection {
|
||||
assign_status?: string;
|
||||
/** 只看某个客服名下的账号 */
|
||||
assigned_user_id?: number;
|
||||
/** 分配池口径:持 CK 且 CK 未失效(排除停用/归档) */
|
||||
assignable_only?: boolean;
|
||||
has_cookie?: boolean;
|
||||
status?: string;
|
||||
ck_status?: string;
|
||||
|
||||
@@ -72,7 +72,9 @@ export default function AssignmentsPage() {
|
||||
const params: Parameters<typeof accountApi.listPaged>[0] = {
|
||||
page: currentPage,
|
||||
page_size: pageSize,
|
||||
has_cookie: true,
|
||||
// 分配池只收「有 CK 且 CK 未失效」的账号:失效号的下一步是重登/修复,
|
||||
// 不是分配给客服(分过去也跑不了任务)。
|
||||
assignable_only: true,
|
||||
include_sensitive: false,
|
||||
search: searchText.trim() || undefined,
|
||||
tag: filterTag || undefined,
|
||||
@@ -180,6 +182,7 @@ export default function AssignmentsPage() {
|
||||
const res = await accountApi.batchAssignSelection({
|
||||
all_matching: true,
|
||||
assign_status: 'unassigned',
|
||||
assignable_only: true,
|
||||
tag: filterTag || undefined,
|
||||
search: searchText.trim() || undefined,
|
||||
assigned_to: selectedUser.id,
|
||||
@@ -252,7 +255,7 @@ export default function AssignmentsPage() {
|
||||
<Row gutter={12} style={{ flexShrink: 0 }}>
|
||||
<Col span={6}>
|
||||
<Card size="small">
|
||||
<Statistic title="总账号 (持CK)" value={totalAccountCount} prefix={<TeamOutlined />} />
|
||||
<Statistic title="总账号 (CK 有效)" value={totalAccountCount} prefix={<TeamOutlined />} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
|
||||
Reference in New Issue
Block a user