fix(huya): 刷新开通商品不再依赖已下线的活动任务接口

真机(2026-10-15)实测 webActUI.getActTaskDetail(act 25135) 返回
601「活动已下线」,刷新开通商品第一步就失败,下拉框一直为空。

- 商品来源改为内置候选(积分中心页面「赠送指定礼物得积分」那一排,
  全部经 getGoodsInfoV5 真机验证 code=200):精英宝典 hy-8328015 ¥30、
  精英币 hy-8327356 ¥0.1、精英徽章 hy-5872824 ¥1、精英令 hy-5879346 ¥10、
  精英令*10 hy-5874269 ¥100、精英令*100 hy-5874270 ¥1000;
  旧版精英宝典 hy-5879340 页面已不再使用,从候选移除
- 活动任务详情降级为可选补充:返回非 200 只记 warning 并写入
  result.task_detail_error,不再让整次刷新失败;失败原因以商品详情为准
- 刷新时清掉该账号全部旧商品行(不限 sid),避免同名商品重复
- 列表接口只返回账号级快照并过滤 2026-07-04 的全局种子行,
  同一 spu_id 保留最新一行(原先 精英宝典 会出现两次)
- 前端:下拉标签带 spu 便于区分,按内置顺序排序,默认自动选中第一项
- 新增 tests/test_huya_recharge_goods_source.py(6 条):活动下线响应字节
  回归、下线不阻断刷新、活动商品仍会并入、失败原因归属、跨 sid 清理、
  列表去重与隐藏种子行(均已做反向验证)

真机验证:刷新成功 6 个商品,价格/库存与网页一致
This commit is contained in:
yml2213
2026-10-15 15:57:25 +08:00
parent 905a7ef22c
commit 7ca0f7ee28
5 changed files with 405 additions and 50 deletions
+9 -2
View File
@@ -78,7 +78,7 @@ export default function HuyaElitePage() {
const [goods, setGoods] = useState<HuyaGoodsItem[]>([]);
const [selectedGoodsId, setSelectedGoodsId] = useState('');
const [rechargeGoods, setRechargeGoods] = useState<HuyaRechargeGoodsItem[]>([]);
const [selectedRechargeSpu, setSelectedRechargeSpu] = useState('hy-5879340');
const [selectedRechargeSpu, setSelectedRechargeSpu] = useState('');
const [search, setSearch] = useState('');
const [loading, setLoading] = useState(false);
const [starting, setStarting] = useState(false);
@@ -240,7 +240,14 @@ export default function HuyaElitePage() {
return accounts.filter((item) => !value || [item.uid, item.nickname, item.username, item.tag, item.game_name].some((v) => String(v || '').toLowerCase().includes(value)));
}, [accounts, search]);
const filteredGoods = useMemo(() => goods.map((item) => ({ ...item, label: `${item.name} / ${item.price ?? '-'}分 / ${item.remain_text || '动态库存'}` })), [goods]);
const filteredRechargeGoods = useMemo(() => rechargeGoods.map((item) => ({ ...item, label: `${item.name || item.spu_id} / ${item.price ? `${(item.price / 100).toFixed(2)}元` : '价格动态'}` })), [rechargeGoods]);
const filteredRechargeGoods = useMemo(() => rechargeGoods.map((item) => ({ ...item, label: `${item.name || item.spu_id} / ${item.price ? `${(item.price / 100).toFixed(2)}元` : '价格动态'} / ${item.spu_id}` })).sort((a, b) => Number(a.raw?.raw_order ?? 0) - Number(b.raw?.raw_order ?? 0) || a.id - b.id), [rechargeGoods]);
// 默认选中列表里的第一个商品;已选商品从列表消失时同步回落到第一个
useEffect(() => {
if (!filteredRechargeGoods.length) return;
if (!filteredRechargeGoods.some((item) => item.spu_id === selectedRechargeSpu)) {
setSelectedRechargeSpu(filteredRechargeGoods[0].spu_id);
}
}, [filteredRechargeGoods, selectedRechargeSpu]);
const exchangeCount = tasks.filter((task) => task.task_type === 'exchange_goods').length;
const accountColumns: TableProps<HuyaAccountItem>['columns'] = [
+1 -1
View File
@@ -676,7 +676,7 @@ export default function HuyaTasksPage() {
const rechargeGoodsOptions = useMemo(() => {
return sortedRechargeGoods.map((item) => ({
value: item.spu_id,
label: `${item.name || item.spu_id}${item.price ? ` / ${formatPriceText(item.price)}` : ''}`,
label: `${item.name || item.spu_id}${item.price ? ` / ${formatPriceText(item.price)}` : ''} / ${item.spu_id}`,
}));
}, [sortedRechargeGoods]);