diff --git a/core/huya/elite_session.py b/core/huya/elite_session.py
index 1a7ebfe..5ab88f6 100644
--- a/core/huya/elite_session.py
+++ b/core/huya/elite_session.py
@@ -273,5 +273,11 @@ class HuyaEliteWssSession:
def get_follow_wechat_status(self, **kwargs):
return self._run(self.client.get_follow_wechat_status(**kwargs))
+ def get_redeem_need_goods(self, **kwargs):
+ return self._run(self.client.get_redeem_need_goods(**kwargs))
+
+ def get_grow_level_user_info(self, **kwargs):
+ return self._run(self.client.get_grow_level_user_info(**kwargs))
+
__all__ = ["HuyaEliteWssSession"]
diff --git a/core/huya/http_client.py b/core/huya/http_client.py
index e5acf4c..dba8707 100644
--- a/core/huya/http_client.py
+++ b/core/huya/http_client.py
@@ -29,6 +29,7 @@ from .wss_client import (
ORDER_BIZ_TYPE,
ORDER_SCENE,
POINTS_PAY_CALLBACK,
+ POINTS_REDEEM_GOODS_NUM,
SHOP_APP_SCENE,
)
from .wup_protocol import WupRequest, WupResponse
@@ -1448,6 +1449,53 @@ class HuyaHttpClient:
)
return self._raw_from_wup(resp) if isinstance(resp, WupResponse) else None
+ def get_redeem_need_goods(
+ self,
+ uid: int,
+ guid: str,
+ cookie: str,
+ goods_num: int = POINTS_REDEEM_GOODS_NUM,
+ timeout: float = 15.0,
+ ):
+ """shopMiddleUI.getRedeemNeedGoods(当前积分 tag2 / 兑换门槛 tag3)。"""
+ from .shop_structs import GetRedeemNeedGoodsReq
+
+ req = GetRedeemNeedGoodsReq()
+ req.userId = self._build_shop_user(uid, cookie)
+ req.shopAppInfo = self._build_shop_app("yellowcarlist", SHOP_APP_SCENE)
+ req.goodsNum = int(goods_num or 0)
+ resp = self.call_rpc(
+ "shopMiddleUI",
+ "getRedeemNeedGoods",
+ req,
+ None,
+ uid,
+ guid,
+ cookie,
+ timeout=timeout,
+ )
+ return self._raw_from_wup(resp) if isinstance(resp, WupResponse) else None
+
+ def get_grow_level_user_info(
+ self, uid: int, guid: str, cookie: str, timeout: float = 15.0
+ ):
+ """GameBizUI.getGrowLevelUserInfo(成长值 tag1.tag0 / 等级 tag1.tag1)。"""
+ from .shop_structs import GetGrowLevelUserInfoReq
+
+ req = GetGrowLevelUserInfoReq()
+ req.userId = self._build_shop_user(uid, cookie)
+ resp = self.call_rpc(
+ "GameBizUI",
+ "getGrowLevelUserInfo",
+ req,
+ None,
+ uid,
+ guid,
+ cookie,
+ timeout=timeout,
+ )
+ return self._raw_from_wup(resp) if isinstance(resp, WupResponse) else None
+
def _self_check():
uid = 1199647239697
diff --git a/core/huya/shop_structs.py b/core/huya/shop_structs.py
index 317fe4a..cb0c2d6 100644
--- a/core/huya/shop_structs.py
+++ b/core/huya/shop_structs.py
@@ -1398,6 +1398,39 @@ class FollowWeChatStatusReq(TafStruct):
pass
+class GetRedeemNeedGoodsReq(ShopAppRequest):
+ """shopMiddleUI.getRedeemNeedGoods 请求(兑换所需商品 + 当前积分)。
+
+ tag2 是兑换商品的数字商品号(抓包为精英宝典兑换商品 ``hy-8315982`` →
+ ``8315982``);传错会返回 500「系统异常」,所以调用方必须给真实商品号。
+ """
+
+ def __init__(self):
+ super().__init__()
+ self.goodsNum: int = 0 # tag 2
+
+ def write_to(self, os: TafOutputStream):
+ os.write_struct(0, self.userId)
+ os.write_struct(1, self.shopAppInfo)
+ os.write_int64(2, self.goodsNum)
+
+ def read_from(self, ins: TafInputStream):
+ pass
+
+
+class GetGrowLevelUserInfoReq(TafStruct):
+ """GameBizUI.getGrowLevelUserInfo 请求(抓包 tReq 只有 tag0 UserId)。"""
+
+ def __init__(self):
+ self.userId = UserId() # tag 0
+
+ def write_to(self, os: TafOutputStream):
+ os.write_struct(0, self.userId)
+
+ def read_from(self, ins: TafInputStream):
+ self.userId = ins.read_struct(0, UserId) or self.userId
+
+
def shop_spu_number(spu_id: str) -> int:
"""把商品 ID(``hy-8328015``)转成接口需要的数字形式(``8328015``)。"""
text = str(spu_id or "").strip()
diff --git a/core/huya/wss_client.py b/core/huya/wss_client.py
index c03388f..293490d 100644
--- a/core/huya/wss_client.py
+++ b/core/huya/wss_client.py
@@ -73,6 +73,9 @@ ORDER_BIZ_TYPE = 5
SHOP_APP_SCENE = 7
ORDER_SCENE = 4
PEACE_ELITE_GAME_ID = 9815
+# getRedeemNeedGoods 的兑换商品号:抓包里的精英宝典兑换商品 hy-8315982 → 8315982。
+# 服务端只认这个商品号(传 0/其它值直接 500「系统异常」)。
+POINTS_REDEEM_GOODS_NUM = 8315982
# createOrderV5 的 extraParam.bizParams:标记「积分中心」来源,缺了会走成普通商城单。
JIFENCENTER_BIZ_PARAMS = '{ "jifencenter": 1 }'
@@ -1448,3 +1451,34 @@ class HuyaWssClient:
return await self.call_rpc_raw(
"wupui", "getUserFollowWeChatOfficialStatus", req
)
+
+ async def get_redeem_need_goods(
+ self,
+ uid: int,
+ guid: str,
+ cookie: str,
+ goods_num: int = POINTS_REDEEM_GOODS_NUM,
+ ):
+ """shopMiddleUI.getRedeemNeedGoods — 兑换所需商品与当前积分。
+
+ 响应:``tag2`` 当前积分、``tag3`` 兑换门槛积分(抓包 + 真机实证)。
+ """
+ from .shop_structs import GetRedeemNeedGoodsReq
+
+ req = GetRedeemNeedGoodsReq()
+ req.userId = self._build_biz_user(uid, cookie)
+ req.shopAppInfo = self._build_shop_app("yellowcarlist", SHOP_APP_SCENE)
+ req.goodsNum = int(goods_num or 0)
+ return await self.call_rpc_raw("shopMiddleUI", "getRedeemNeedGoods", req)
+
+ async def get_grow_level_user_info(self, uid: int, guid: str, cookie: str):
+ """GameBizUI.getGrowLevelUserInfo — 成长值/成长等级/昵称。
+
+ 响应:``tag1.tag0`` 成长值、``tag1.tag1`` 成长等级、``tag2`` 昵称、
+ ``tag3`` 头像(抓包 + 真机实证)。
+ """
+ from .shop_structs import GetGrowLevelUserInfoReq
+
+ req = GetGrowLevelUserInfoReq()
+ req.userId = self._build_biz_user(uid, cookie)
+ return await self.call_rpc_raw("GameBizUI", "getGrowLevelUserInfo", req)
diff --git a/tests/test_huya_points_query.py b/tests/test_huya_points_query.py
new file mode 100644
index 0000000..dbb08c0
--- /dev/null
+++ b/tests/test_huya_points_query.py
@@ -0,0 +1,295 @@
+"""查询积分改走积分中心新接口(2026-10-15 真机实测)。
+
+背景:旧活动接口 ``webActUI.getUserScore`` 对任何 sid 都返回
+603「活动已结束」(该接口已下线,与工作台里的 SID/活动配置无关);
+积分中心用 ``shopMiddleUI.getRedeemNeedGoods`` 查积分:
+``tag2``=当前积分、``tag3``=兑换门槛。下面固化的响应字节来自真机 HTTP 通道。
+
+抓包/真机字面值直接写在测试里(不引用实现常量),避免断言跟着实现漂移。
+"""
+
+import asyncio
+
+from core.huya.activity_structs import GetUserScoreResp
+from core.huya.frame_decoder import _decode_wup_body, decode_struct_bytes
+from core.huya.http_client import HuyaHttpClient
+from core.huya.shop_structs import ShopRawRsp
+from core.huya.wss_client import HuyaWssClient, WssMessage
+from web.backend.models import HuyaAccount
+from web.backend.services.huya_runner import HuyaBatchRunner
+
+UID = 1199665170519
+GUID = "0a8995af9218ce6a340261946294a9e7"
+COOKIE = f"udb_uid={UID}; yyuid={UID}; guid={GUID}"
+# 真机(2026-10-15,账号 hy_297832664)getRedeemNeedGoods 响应:200 / 积分 280 / 门槛 20
+REDEEM_RSP_HEX = "0a0100c8160ce69fa5e8afa2e68890e58a9f21011830144c50016001790c0b"
+# 真机 getGrowLevelUserInfo 响应:成长值 980 / 成长等级 3 / 昵称 / 头像
+GROW_RSP_HEX = (
+ "0a0a0c1606e68890e58a9f0b1a0103d41003230000019f124082043c4c50"
+ "0360ff7101f48103e80b260fe8bdafe8b88fe697a5e6bdbae6b9b236386874"
+ "7470733a2f2f6469792d6173736574732e6d737374617469632e636f6d2f6371"
+ "68666f6c6465722f4e657744656661756c742e706e670b"
+)
+
+
+class _FakeWs:
+ """记录发出的帧,并立刻兑现 RPC future(离线跑完整链路)。"""
+
+ def __init__(self, client: HuyaWssClient):
+ self.client = client
+ self.sent: list[bytes] = []
+
+ async def send(self, data: bytes):
+ self.sent.append(data)
+ while self.client.rpc_queue:
+ future = self.client.rpc_queue.popleft()
+ if not future.done():
+ future.set_result(b"")
+
+ def last_request(self) -> dict:
+ return _decode_wup_body(WssMessage.decode(self.sent[-1]).body)
+
+
+def _points_client() -> HuyaWssClient:
+ client = HuyaWssClient(logger=lambda _message: None)
+ client._points_mode = True
+ client.ws = _FakeWs(client)
+ return client
+
+
+def _raw_rsp(payload_hex: str) -> ShopRawRsp:
+ return ShopRawRsp.from_payload(
+ decode_struct_bytes(bytes.fromhex("".join(payload_hex.split())))
+ )
+
+
+class _StubClient:
+ """按需返回真机响应字节的积分中心客户端。"""
+
+ def __init__(self, redeem=True, grow=True):
+ self.redeem = _raw_rsp(REDEEM_RSP_HEX) if redeem else None
+ self.grow = _raw_rsp(GROW_RSP_HEX) if grow else None
+ self.calls: list[tuple[str, dict]] = []
+
+ def get_redeem_need_goods(self, **kwargs):
+ self.calls.append(("get_redeem_need_goods", kwargs))
+ return self.redeem
+
+ def get_grow_level_user_info(self, **kwargs):
+ self.calls.append(("get_grow_level_user_info", kwargs))
+ return self.grow
+
+
+class _LegacyClient:
+ """旧活动接口:真机实测任何 sid 都返回 603「活动已结束」。"""
+
+ def query_user_score(self, uid: int, cookie: str, sid: int):
+ response = GetUserScoreResp()
+ response.status = 603
+ response.msg = "活动已结束"
+ response.score = 0
+ return response
+
+
+def _runner(monkeypatch, client, legacy=None) -> tuple[HuyaBatchRunner, list]:
+ runner = HuyaBatchRunner(db=None, batch_id="test-batch", task_type="query_points")
+ marks: list[tuple[str, str, dict | None]] = []
+ monkeypatch.setattr(
+ runner, "_shop_client", lambda uid, cookie: client, raising=False
+ )
+ if legacy is not None:
+ monkeypatch.setattr(
+ runner, "_activity_client", lambda uid, cookie: legacy, raising=False
+ )
+ monkeypatch.setattr(
+ runner,
+ "_mark_task",
+ lambda _db, _task, status, message, result=None: marks.append(
+ (status, message, result)
+ ),
+ raising=False,
+ )
+ return runner, marks
+
+
+def test_wss_redeem_need_goods_request_matches_real_call():
+ async def run():
+ client = _points_client()
+ await client.get_redeem_need_goods(uid=UID, guid=GUID, cookie=COOKIE)
+
+ message = WssMessage.decode(client.ws.sent[-1])
+ # 积分中心业务帧统一 0x1d000107(只有下单/支付用 0x1d000108)
+ assert message.sequence == 0x1D000107
+
+ decoded = client.ws.last_request()
+ assert (decoded["servant"], decoded["func"]) == (
+ "shopMiddleUI",
+ "getRedeemNeedGoods",
+ )
+ t_req = decoded["tReq"]
+ assert t_req["tag0"]["tag0"] == UID
+ assert t_req["tag1"]["tag0"] == "huya"
+ assert t_req["tag1"]["tag4"] == 7
+ assert t_req["tag1"]["tag5"] == "yellowcarlist"
+ # 默认兑换商品号必须是真机可用的 hy-8315982 的数字形式
+ assert t_req["tag2"] == 8315982
+
+ asyncio.run(run())
+
+
+def test_wss_grow_level_request_carries_only_user_id():
+ async def run():
+ client = _points_client()
+ await client.get_grow_level_user_info(uid=UID, guid=GUID, cookie=COOKIE)
+
+ decoded = client.ws.last_request()
+ assert (decoded["servant"], decoded["func"]) == (
+ "GameBizUI",
+ "getGrowLevelUserInfo",
+ )
+ t_req = decoded["tReq"]
+ assert t_req["tag0"]["tag0"] == UID
+ # 抓包 tReq 只有 tag0,没有 shopAppInfo
+ assert set(t_req) == {"tag0"}
+
+ asyncio.run(run())
+
+
+def test_http_redeem_need_goods_request_matches_real_call():
+ client = HuyaHttpClient(logger=lambda _message: None)
+ recorded: list[tuple] = []
+
+ def fake_call_rpc(
+ service, method, req_struct, rsp_class=None, uid=0, guid="", cookie="", **kwargs
+ ):
+ recorded.append((service, method, req_struct))
+
+ client.call_rpc = fake_call_rpc # type: ignore[method-assign]
+
+ client.get_redeem_need_goods(uid=UID, guid="", cookie=COOKIE)
+
+ service, method, req = recorded[-1]
+ assert (service, method) == ("shopMiddleUI", "getRedeemNeedGoods")
+ assert req.userId.lUid == UID
+ assert req.shopAppInfo.scene == 7
+ assert req.shopAppInfo.sourceId == "yellowcarlist"
+ assert req.goodsNum == 8315982
+
+
+def test_real_redeem_response_bytes_are_points_and_threshold():
+ rsp = _raw_rsp(REDEEM_RSP_HEX)
+
+ assert rsp.code == 200
+ assert rsp.message == "查询成功"
+ # tag2 = 当前积分,tag3 = 兑换门槛积分(真机 280 / 20)
+ assert rsp.value("tag2") == 280
+ assert rsp.value("tag3") == 20
+
+
+def test_real_grow_level_response_bytes_are_level_and_nickname():
+ rsp = _raw_rsp(GROW_RSP_HEX)
+
+ assert rsp.code == 0
+ assert rsp.message == "成功"
+ assert rsp.value("tag1", "tag0") == 980 # 成长值
+ assert rsp.value("tag1", "tag1") == 3 # 成长等级
+ assert rsp.value("tag2") == "软踏日潺湲"
+ assert str(rsp.value("tag3")).startswith("https://diy-assets.msstatic.com/")
+
+
+def test_query_points_reads_points_from_points_center(monkeypatch):
+ client = _StubClient()
+ runner, marks = _runner(monkeypatch, client)
+ account = HuyaAccount(uid=str(UID), cookie=COOKIE)
+
+ runner._execute_query_points(
+ None, None, account, {"uid": UID, "cookie": COOKIE}, {}
+ )
+
+ assert [name for name, _kwargs in client.calls] == [
+ "get_redeem_need_goods",
+ "get_grow_level_user_info",
+ ]
+ assert client.calls[0][1]["goods_num"] == 8315982
+ status, message, result = marks[-1]
+ assert status == "success"
+ assert message == "积分: 280"
+ assert account.points == 280
+ assert result["points"] == 280
+ assert result["redeem_threshold"] == 20
+ assert result["grow_level"] == 3
+ assert result["grow_value"] == 980
+ assert result["nickname"] == "软踏日潺湲"
+
+
+def test_query_points_keeps_working_when_grow_level_fails(monkeypatch):
+ client = _StubClient(grow=False)
+ runner, marks = _runner(monkeypatch, client)
+ account = HuyaAccount(uid=str(UID), cookie=COOKIE)
+
+ runner._execute_query_points(
+ None, None, account, {"uid": UID, "cookie": COOKIE}, {}
+ )
+
+ status, message, result = marks[-1]
+ assert status == "success"
+ assert message == "积分: 280"
+ assert "grow_level" not in result
+
+
+def test_query_points_reports_server_error_of_points_center(monkeypatch):
+ class _FailingClient(_StubClient):
+ def get_redeem_need_goods(self, **kwargs):
+ self.calls.append(("get_redeem_need_goods", kwargs))
+ return ShopRawRsp.from_payload(
+ decode_struct_bytes(
+ bytes.fromhex(
+ "0a0101f4161ee7b3bbe7bb9fe5bc82e5b8b8efbc8ce8afb7e7a88de5"
+ "908ee9878de8af952c3c4c5c6c0b"
+ )
+ )
+ )
+
+ client = _FailingClient()
+ runner, marks = _runner(monkeypatch, client)
+ account = HuyaAccount(uid=str(UID), cookie=COOKIE)
+
+ runner._execute_query_points(
+ None, None, account, {"uid": UID, "cookie": COOKIE}, {}
+ )
+
+ status, message, result = marks[-1]
+ assert status == "failed"
+ assert message == "系统异常,请稍后重试"
+ assert result["code"] == 500
+ assert result["goods_num"] == 8315982
+
+
+def test_query_points_fallback_reports_legacy_interface_offline(monkeypatch):
+ client = _StubClient(redeem=False)
+ runner, marks = _runner(monkeypatch, client, legacy=_LegacyClient())
+ account = HuyaAccount(uid=str(UID), cookie=COOKIE)
+
+ runner._execute_query_points(
+ None, None, account, {"uid": UID, "cookie": COOKIE}, {"sid": "2203"}
+ )
+
+ status, message, _result = marks[-1]
+ assert status == "failed"
+ # 旧接口的真实返回必须如实暴露,而不是只报「活动已结束」
+ assert "旧活动接口(sid=2203)返回 603 活动已结束" in message
+ assert "积分中心接口无响应" in message
+
+
+def test_query_points_without_sid_reports_points_center_offline(monkeypatch):
+ client = _StubClient(redeem=False)
+ runner, marks = _runner(monkeypatch, client, legacy=_LegacyClient())
+ account = HuyaAccount(uid=str(UID), cookie=COOKIE)
+
+ runner._execute_query_points(
+ None, None, account, {"uid": UID, "cookie": COOKIE}, {}
+ )
+
+ status, message, _result = marks[-1]
+ assert status == "error"
+ assert "积分中心接口无响应" in message
diff --git a/web/backend/services/huya_runner_goods.py b/web/backend/services/huya_runner_goods.py
index 7e80376..a3f3380 100644
--- a/web/backend/services/huya_runner_goods.py
+++ b/web/backend/services/huya_runner_goods.py
@@ -8,6 +8,8 @@ from typing import TYPE_CHECKING, Any
from sqlalchemy.orm import Session
+from core.huya.wss_client import POINTS_REDEEM_GOODS_NUM
+
from ..models import HuyaAccount, HuyaGoodsSnapshot, HuyaTask
@@ -26,6 +28,7 @@ class GoodsMixin:
def _resolve_uid(self, account_info: dict) -> int: ...
def _push_log(self, level: str, message: str) -> None: ...
def _activity_client(self, uid: int, cookie: str): ...
+ def _shop_client(self, uid: int, cookie: str): ...
def _mark_task(self, *args: Any, **kwargs: Any) -> None: ...
def _wait_until(self, when: datetime, uid: int) -> bool: ...
def _parse_scheduled_time(self, value: Any) -> datetime | None: ...
@@ -90,16 +93,13 @@ class GoodsMixin:
account_info: dict,
config_info: dict,
):
- sid = str(self.payload.get("sid") or config_info.get("sid") or "").strip()
- if not sid:
- self._mark_task(worker_db, task, "failed", "请先配置虎牙活动 SID")
- return
-
- sid_int = self._to_int(sid)
- if not sid_int:
- self._mark_task(worker_db, task, "failed", f"虎牙活动 SID 无效: {sid}")
- return
+ """查询积分:主源是积分中心的 shopMiddleUI.getRedeemNeedGoods。
+ 2026-10-15 真机实测:旧活动接口 webActUI.getUserScore 对任何 sid 都返回
+ 603「活动已结束」(该接口已下线,与配置无关);积分中心接口返回
+ ``tag2``=当前积分、``tag3``=兑换门槛积分,另可顺手取 GameBizUI
+ 的成长值/成长等级。
+ """
uid = self._resolve_uid(account_info)
if not uid:
self._mark_task(worker_db, task, "failed", "无法从账号或 Cookie 解析 yyuid")
@@ -110,10 +110,76 @@ class GoodsMixin:
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
return
+ goods_num = (
+ self._to_int(self.payload.get("goods_num")) or POINTS_REDEEM_GOODS_NUM
+ )
+ client: Any = self._shop_client(uid, cookie)
+ redeem = client.get_redeem_need_goods(
+ uid=uid, guid="", cookie=cookie, goods_num=goods_num
+ )
+ if redeem is None:
+ self._query_points_legacy(
+ worker_db, task, account, uid, cookie, config_info
+ )
+ return
+
+ result = redeem.to_dict()
+ result["goods_num"] = goods_num
+ if redeem.code != 200:
+ self._mark_task(
+ worker_db,
+ task,
+ "failed",
+ redeem.message or f"虎牙积分查询失败: {redeem.code}",
+ result,
+ )
+ return
+
+ points = self._to_int(redeem.value("tag2"))
+ result["points"] = points
+ result["redeem_threshold"] = self._to_int(redeem.value("tag3"))
+ growth = client.get_grow_level_user_info(uid=uid, guid="", cookie=cookie)
+ if growth is not None and growth.code == 0:
+ result["grow_value"] = self._to_int(growth.value("tag1", "tag0"))
+ result["grow_level"] = self._to_int(growth.value("tag1", "tag1"))
+ result["nickname"] = growth.value("tag2") or ""
+
+ account.points = points
+ account.status = "points_queried"
+ account.updated_at = datetime.now(UTC)
+ self._mark_task(worker_db, task, "success", f"积分: {points}", result)
+
+ def _query_points_legacy(
+ self,
+ worker_db: Session,
+ task: HuyaTask,
+ account: HuyaAccount,
+ uid: int,
+ cookie: str,
+ config_info: dict,
+ ):
+ """积分中心接口没有响应时回退旧活动接口,并如实报告旧接口的返回。"""
+ sid = str(self.payload.get("sid") or config_info.get("sid") or "").strip()
+ if not sid:
+ self._mark_task(
+ worker_db, task, "error", "积分中心接口无响应,且未配置可回退的活动 SID"
+ )
+ return
+
+ sid_int = self._to_int(sid)
+ if not sid_int:
+ self._mark_task(worker_db, task, "failed", f"虎牙活动 SID 无效: {sid}")
+ return
+
client: Any = self._activity_client(uid, cookie)
response = client.query_user_score(uid=uid, cookie=cookie, sid=sid_int)
if response is None:
- self._mark_task(worker_db, task, "error", "虎牙积分接口无响应")
+ self._mark_task(
+ worker_db,
+ task,
+ "error",
+ "虎牙积分接口无响应(积分中心与旧活动接口均失败)",
+ )
return
result = response.to_dict()
@@ -123,7 +189,8 @@ class GoodsMixin:
worker_db,
task,
"failed",
- response.msg or f"虎牙积分查询失败: {response.status}",
+ f"积分中心接口无响应;旧活动接口(sid={sid_int})返回 "
+ f"{response.status} {response.msg}".strip(),
result,
)
return
@@ -132,7 +199,9 @@ class GoodsMixin:
account.points = points
account.status = "points_queried"
account.updated_at = datetime.now(UTC)
- self._mark_task(worker_db, task, "success", f"积分: {points}", result)
+ self._mark_task(
+ worker_db, task, "success", f"积分: {points}(旧活动接口)", result
+ )
def _execute_query_exchange_records(
self,
diff --git a/web/backend/services/huya_runner_recharge.py b/web/backend/services/huya_runner_recharge.py
index 004bf72..0719534 100644
--- a/web/backend/services/huya_runner_recharge.py
+++ b/web/backend/services/huya_runner_recharge.py
@@ -506,12 +506,12 @@ class RechargeMixin:
account.updated_at = datetime.now(UTC)
if payment_status == "paid":
account.status = "recharge_paid"
- post_score = client.query_user_score(
- uid=uid, cookie=cookie, sid=self._to_int(config_info.get("sid")) or 2203
- )
- if post_score is not None:
- result["post_payment_score"] = post_score.to_dict()
- account.points = post_score.available_score
+ # 支付后刷新积分:旧活动接口 getUserScore 已下线(603 活动已结束),
+ # 改走积分中心 getRedeemNeedGoods(tag2 = 当前积分)。
+ post_redeem = client.get_redeem_need_goods(uid=uid, guid="", cookie=cookie)
+ if post_redeem is not None and post_redeem.code == 200:
+ result["post_payment_points"] = self._to_int(post_redeem.value("tag2"))
+ account.points = result["post_payment_points"]
paid_message = f"支付成功: {product_name} x{count} {result['amount_text']}"
if payment_order and payment_order.get("pay_time"):
paid_message += f",支付时间 {self._format_local_time(int(payment_order['pay_time']) // 1000)}"
diff --git a/web/frontend/src/pages/HuyaTasksPage.tsx b/web/frontend/src/pages/HuyaTasksPage.tsx
index 96cf3f5..242baef 100644
--- a/web/frontend/src/pages/HuyaTasksPage.tsx
+++ b/web/frontend/src/pages/HuyaTasksPage.tsx
@@ -1136,9 +1136,11 @@ export default function HuyaTasksPage() {
return -;
}
- const availableScore = value?.available_score;
- if (typeof availableScore === 'number') {
- return 可用积分 {availableScore};
+ // 积分结果:新版走积分中心(points),旧任务记录里是活动接口的 available_score
+ const points = typeof value?.points === 'number' ? value.points : value?.available_score;
+ if (typeof points === 'number') {
+ const level = value?.grow_level;
+ return 可用积分 {points}{typeof level === 'number' ? ` · 等级 ${level}` : ''};
}
return value ? {JSON.stringify(value)} : -;