feat(accounts): 账号列表按列排序,默认把还能换套装的排到前面

分页在服务端,点表头按全库排,不能只排当前这一页。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-10-05 18:50:43 +08:00
co-authored by Cursor
parent ab4c0a5422
commit f2157f67f7
5 changed files with 363 additions and 5 deletions
+137
View File
@@ -1792,6 +1792,143 @@ class TestHighValueAccountFilters:
assert "acc_broken" in names
assert "acc_both_owned" not in names
def test_list_sorts_by_suit_availability(self):
# 升序:两套都能换 → 只剩一套 → 都换过 → 没查过。同档按 id。
names = [it.username for it in self._query(sort="high_value", order="asc")]
assert names == [
"acc_crown",
"acc_broken",
"acc_bairimeng_owned",
"acc_mengtu_owned",
"acc_both_owned",
"acc_unqueried",
]
names = [it.username for it in self._query(sort="high_value", order="desc")]
assert names == [
"acc_unqueried",
"acc_both_owned",
"acc_mengtu_owned",
"acc_bairimeng_owned",
"acc_broken",
"acc_crown",
]
def test_list_sorts_by_official_exchange_count(self):
from web.backend.services.account_events_service import (
CATEGORY_BUSINESS,
EVENT_EXCHANGE,
OFFICIAL_SYNC_SOURCE,
emit,
)
now = datetime.now(UTC)
emit(
self.session,
account_id=self.acc_both_owned.id,
event_type=EVENT_EXCHANGE,
title="兑换 A",
category=CATEGORY_BUSINESS,
occurred_at=now,
source=OFFICIAL_SYNC_SOURCE,
)
emit(
self.session,
account_id=self.acc_both_owned.id,
event_type=EVENT_EXCHANGE,
title="兑换 B",
category=CATEGORY_BUSINESS,
occurred_at=now,
source=OFFICIAL_SYNC_SOURCE,
)
emit(
self.session,
account_id=self.acc_crown.id,
event_type=EVENT_EXCHANGE,
title="兑换 C",
category=CATEGORY_BUSINESS,
occurred_at=now,
source=OFFICIAL_SYNC_SOURCE,
)
# 当场记的不算进列表「兑换记录」,排序也不能把它算进去
emit(
self.session,
account_id=self.acc_unqueried.id,
event_type=EVENT_EXCHANGE,
title="兑换 当场",
category=CATEGORY_BUSINESS,
occurred_at=now,
source="manual",
)
self.session.commit()
names = [it.username for it in self._query(sort="exchange", order="asc")]
assert names == [
"acc_bairimeng_owned",
"acc_mengtu_owned",
"acc_unqueried",
"acc_broken",
"acc_crown",
"acc_both_owned",
]
names = [it.username for it in self._query(sort="exchange", order="desc")]
assert names == [
"acc_both_owned",
"acc_crown",
"acc_bairimeng_owned",
"acc_mengtu_owned",
"acc_unqueried",
"acc_broken",
]
def test_list_sorts_points_status_bind_and_tag(self):
self.acc_crown.status = "active"
self.acc_crown.role_bind_status = "bound"
self.acc_crown.tag = "b"
self.acc_broken.status = "invalid"
self.acc_broken.role_bind_status = "unbound"
self.acc_broken.tag = "a"
self.acc_unqueried.status = "imported"
# 积分相同,鱼翅多的在积分降序里更靠前
self.acc_bairimeng_owned.points = 50
self.acc_bairimeng_owned.gold_balance = 1
self.session.commit()
assert [it.username for it in self._query(sort="points", order="desc")] == [
"acc_broken",
"acc_crown",
"acc_mengtu_owned",
"acc_bairimeng_owned",
"acc_both_owned",
"acc_unqueried",
]
assert [it.username for it in self._query(sort="points", order="asc")] == [
"acc_both_owned",
"acc_bairimeng_owned",
"acc_mengtu_owned",
"acc_crown",
"acc_broken",
"acc_unqueried",
]
assert [it.username for it in self._query(sort="status", order="asc")][:3] == [
"acc_crown",
"acc_broken",
"acc_unqueried",
]
assert [it.username for it in self._query(sort="bind", order="asc")][:2] == [
"acc_crown",
"acc_broken",
]
assert [it.username for it in self._query(sort="username", order="asc")] == [
"acc_bairimeng_owned",
"acc_both_owned",
"acc_broken",
"acc_crown",
"acc_mengtu_owned",
"acc_unqueried",
]
tagged = [it.username for it in self._query(sort="tag", order="asc")]
assert tagged[-2:] == ["acc_broken", "acc_crown"]
def test_summary_returns_high_value_breakdown(self):
from web.backend.routers.accounts import accounts_summary