1639 lines
58 KiB
HTML
1639 lines
58 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta
|
||
name="viewport"
|
||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
||
/>
|
||
<meta name="theme-color" content="#3e1b00" />
|
||
<title data-i18n="huwaa_rank.page_title">Huwaa Ranking</title>
|
||
<link rel="stylesheet" href="../common/theme.css" />
|
||
<style>
|
||
:root {
|
||
--rank-zoom: 1;
|
||
--rank-bg: url('assets/huwaa/bg-wealth.webp');
|
||
--rank-base: #3e1b00;
|
||
--rank-fade: rgba(62, 27, 0, 0.9);
|
||
--rank-shade: rgba(58, 34, 16, 0.58);
|
||
--row-frame: url('assets/huwaa/row-wealth.svg');
|
||
--row-photo-opacity: 0.14;
|
||
--mine-start: #ffe27d;
|
||
--mine-end: #d78d0d;
|
||
--mine-glow: rgba(255, 210, 106, 0.68);
|
||
--mine-text: #6a4300;
|
||
--gold: #ffc928;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
html,
|
||
body {
|
||
min-height: 100%;
|
||
margin: 0;
|
||
background: var(--rank-base);
|
||
color: #fff;
|
||
font-family: Arial, 'Helvetica Neue', sans-serif;
|
||
overscroll-behavior-y: none;
|
||
}
|
||
|
||
body {
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
button {
|
||
margin: 0;
|
||
padding: 0;
|
||
border: 0;
|
||
outline: 0;
|
||
color: inherit;
|
||
font: inherit;
|
||
background: transparent;
|
||
cursor: pointer;
|
||
}
|
||
|
||
img {
|
||
display: block;
|
||
user-select: none;
|
||
-webkit-user-drag: none;
|
||
}
|
||
|
||
.rank-app {
|
||
position: relative;
|
||
width: 375px;
|
||
min-height: 100vh;
|
||
margin: 0 auto;
|
||
overflow: visible;
|
||
isolation: isolate;
|
||
background: var(--rank-base);
|
||
zoom: var(--rank-zoom);
|
||
}
|
||
|
||
.rank-background {
|
||
position: absolute;
|
||
z-index: -2;
|
||
inset: 0 0 auto;
|
||
width: 375px;
|
||
min-height: 100%;
|
||
overflow: hidden;
|
||
background: var(--rank-base);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.rank-background::before {
|
||
position: absolute;
|
||
top: -115px;
|
||
left: 0;
|
||
width: 375px;
|
||
height: 666px;
|
||
background: var(--rank-bg) center / 375px 666px no-repeat;
|
||
content: '';
|
||
}
|
||
|
||
/* Figma 的背景蒙版在原稿 y=595 结束;移除 44px 状态栏后,渐隐必须在 y=551 前收进主题底色,避免列表中段出现断层。 */
|
||
.rank-background::after {
|
||
position: absolute;
|
||
top: 425px;
|
||
left: 0;
|
||
width: 375px;
|
||
height: 140px;
|
||
background: linear-gradient(
|
||
180deg,
|
||
transparent,
|
||
var(--rank-fade) 72%,
|
||
var(--rank-base) 100%
|
||
);
|
||
content: '';
|
||
}
|
||
|
||
.sticky-header {
|
||
position: sticky;
|
||
z-index: 50;
|
||
top: 0;
|
||
width: 375px;
|
||
height: 88px;
|
||
background: linear-gradient(
|
||
180deg,
|
||
var(--rank-shade) 0%,
|
||
rgba(9, 5, 35, 0.16) 72%,
|
||
transparent 100%
|
||
);
|
||
}
|
||
|
||
.top-nav {
|
||
position: relative;
|
||
width: 375px;
|
||
height: 44px;
|
||
}
|
||
|
||
.back-button {
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: 0;
|
||
left: 8px;
|
||
display: grid;
|
||
width: 40px;
|
||
height: 44px;
|
||
place-items: center;
|
||
}
|
||
|
||
.back-button::before {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-bottom: 2px solid #fff;
|
||
border-left: 2px solid #fff;
|
||
content: '';
|
||
transform: rotate(45deg);
|
||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.7));
|
||
}
|
||
|
||
.help-button {
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: 11px;
|
||
right: 18px;
|
||
width: 14px;
|
||
height: 14px;
|
||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||
border-radius: 50%;
|
||
color: #fff;
|
||
font-size: 10px;
|
||
line-height: 12px;
|
||
text-align: center;
|
||
}
|
||
|
||
.board-tabs {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 57px;
|
||
display: grid;
|
||
width: 263px;
|
||
height: 44px;
|
||
grid-template-columns: 70px 60px 72px 61px;
|
||
align-items: center;
|
||
}
|
||
|
||
.board-tab {
|
||
position: relative;
|
||
height: 44px;
|
||
color: #e2e2e2;
|
||
font-size: 16px;
|
||
line-height: 44px;
|
||
text-align: center;
|
||
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.76);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.board-tab.is-active {
|
||
color: var(--gold);
|
||
text-shadow:
|
||
0 0 7px rgba(255, 202, 45, 0.68),
|
||
0 1px 2px rgba(0, 0, 0, 0.76);
|
||
}
|
||
|
||
.board-tab.is-active::after {
|
||
position: absolute;
|
||
bottom: 3px;
|
||
left: 50%;
|
||
width: 16px;
|
||
height: 3px;
|
||
margin-left: -8px;
|
||
border-radius: 3px;
|
||
background: var(--gold);
|
||
box-shadow: 0 0 7px rgba(255, 201, 40, 0.85);
|
||
content: '';
|
||
}
|
||
|
||
.period-tabs {
|
||
position: absolute;
|
||
top: 53px;
|
||
left: 65px;
|
||
display: grid;
|
||
width: 258px;
|
||
height: 29px;
|
||
border: 1px solid #ffc376;
|
||
border-radius: 15px;
|
||
background: #23180a;
|
||
grid-template-columns: repeat(3, 86px);
|
||
}
|
||
|
||
.period-tab {
|
||
position: relative;
|
||
z-index: 1;
|
||
height: 29px;
|
||
color: #fff;
|
||
font-size: 12px;
|
||
line-height: 28px;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.period-tab::before {
|
||
position: absolute;
|
||
z-index: -1;
|
||
top: -6px;
|
||
left: -6px;
|
||
display: none;
|
||
width: 92px;
|
||
height: 40px;
|
||
background: url('assets/huwaa/period-active.webp') center / 92px
|
||
40px no-repeat;
|
||
content: '';
|
||
}
|
||
|
||
.period-tab.is-active {
|
||
color: #492307;
|
||
}
|
||
|
||
.period-tab.is-active::before {
|
||
display: block;
|
||
}
|
||
|
||
.podium {
|
||
position: relative;
|
||
z-index: 1;
|
||
width: 375px;
|
||
height: 278px;
|
||
}
|
||
|
||
.podium-card {
|
||
position: absolute;
|
||
overflow: visible;
|
||
text-align: center;
|
||
}
|
||
|
||
.podium-card.top-one {
|
||
top: 6px;
|
||
left: 114px;
|
||
width: 147px;
|
||
height: 225px;
|
||
}
|
||
|
||
.podium-card.side {
|
||
top: 89px;
|
||
width: 119px;
|
||
height: 202px;
|
||
}
|
||
|
||
.podium-card.top-two {
|
||
left: 4px;
|
||
}
|
||
|
||
.podium-card.top-three {
|
||
right: 4px;
|
||
}
|
||
|
||
.podium-avatar,
|
||
.podium-frame,
|
||
.podium-banner,
|
||
.game-frame {
|
||
position: absolute;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.podium-avatar {
|
||
z-index: 1;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
background: #241504;
|
||
}
|
||
|
||
.podium-banner {
|
||
z-index: 0;
|
||
}
|
||
|
||
.podium-frame,
|
||
.game-frame {
|
||
z-index: 2;
|
||
}
|
||
|
||
.top-one .podium-avatar {
|
||
top: 29px;
|
||
left: 37px;
|
||
width: 73px;
|
||
height: 73px;
|
||
}
|
||
|
||
.top-one .podium-frame {
|
||
inset: 0 auto auto 0;
|
||
width: 147px;
|
||
height: 138px;
|
||
}
|
||
|
||
.top-one .podium-banner {
|
||
top: 83px;
|
||
left: 12px;
|
||
width: 122px;
|
||
height: 142px;
|
||
}
|
||
|
||
.side .podium-avatar {
|
||
top: 18px;
|
||
left: 25px;
|
||
width: 70px;
|
||
height: 70px;
|
||
}
|
||
|
||
.side .podium-frame {
|
||
inset: 0 auto auto 0;
|
||
width: 119px;
|
||
height: 119px;
|
||
}
|
||
|
||
.side .podium-banner {
|
||
top: 68px;
|
||
left: 11px;
|
||
width: 98px;
|
||
height: 134px;
|
||
}
|
||
|
||
.top-three .podium-banner {
|
||
width: 99px;
|
||
}
|
||
|
||
.game-frame {
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.rank-app.is-game .top-one {
|
||
top: 2px;
|
||
height: 221px;
|
||
}
|
||
|
||
.rank-app.is-game .side {
|
||
height: 197px;
|
||
}
|
||
|
||
.podium-copy {
|
||
position: absolute;
|
||
z-index: 3;
|
||
color: #6a4300;
|
||
text-align: center;
|
||
}
|
||
|
||
.top-one .podium-copy {
|
||
top: 140px;
|
||
left: 23px;
|
||
width: 100px;
|
||
}
|
||
|
||
.side .podium-copy {
|
||
top: 122px;
|
||
left: 20px;
|
||
width: 79px;
|
||
}
|
||
|
||
.podium-name {
|
||
display: block;
|
||
overflow: hidden;
|
||
font-size: 14px;
|
||
line-height: 14px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.side .podium-name {
|
||
font-size: 12px;
|
||
line-height: 14px;
|
||
}
|
||
|
||
.badge-strip {
|
||
display: flex;
|
||
height: 20px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 1px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.rank-badge {
|
||
width: auto;
|
||
max-width: 19px;
|
||
height: 16px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.side .rank-badge {
|
||
max-width: 17px;
|
||
height: 14px;
|
||
}
|
||
|
||
.podium-score,
|
||
.row-score,
|
||
.mine-score {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.podium-score {
|
||
justify-content: center;
|
||
height: 14px;
|
||
font-size: 10px;
|
||
line-height: 14px;
|
||
}
|
||
|
||
.score-coin {
|
||
width: 12px;
|
||
height: 12px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.side .podium-score,
|
||
.side .score-coin {
|
||
font-size: 9px;
|
||
}
|
||
|
||
.side .score-coin {
|
||
width: 10px;
|
||
height: 10px;
|
||
}
|
||
|
||
.rank-list {
|
||
position: relative;
|
||
z-index: 2;
|
||
width: 375px;
|
||
min-height: 375px;
|
||
padding-bottom: 104px;
|
||
}
|
||
|
||
.rank-item {
|
||
position: relative;
|
||
display: block;
|
||
width: 375px;
|
||
height: 75px;
|
||
text-align: left;
|
||
}
|
||
|
||
.row-frame,
|
||
.row-photo {
|
||
position: absolute;
|
||
top: 8px;
|
||
left: 10px;
|
||
width: 355px;
|
||
height: 63px;
|
||
}
|
||
|
||
.row-frame {
|
||
z-index: 0;
|
||
content: var(--row-frame);
|
||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.28));
|
||
}
|
||
|
||
.row-photo {
|
||
z-index: 1;
|
||
background: var(--rank-bg) center -204px / 375px 666px no-repeat;
|
||
clip-path: polygon(
|
||
2.8% 0,
|
||
97.3% 0,
|
||
100% 15%,
|
||
100% 86%,
|
||
97.3% 100%,
|
||
2.8% 100%,
|
||
0 86%,
|
||
0 15%
|
||
);
|
||
opacity: var(--row-photo-opacity);
|
||
}
|
||
|
||
.row-ornament {
|
||
position: absolute;
|
||
z-index: 3;
|
||
top: 0;
|
||
left: 133px;
|
||
width: 110px;
|
||
height: 14px;
|
||
}
|
||
|
||
.rank-number {
|
||
position: absolute;
|
||
z-index: 4;
|
||
top: 31px;
|
||
left: 21px;
|
||
width: 20px;
|
||
font-size: 16px;
|
||
line-height: 18px;
|
||
text-align: center;
|
||
}
|
||
|
||
.row-avatar {
|
||
position: absolute;
|
||
z-index: 4;
|
||
top: 19px;
|
||
left: 48px;
|
||
width: 42px;
|
||
height: 42px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
background: #1c120b;
|
||
}
|
||
|
||
.row-main {
|
||
position: absolute;
|
||
z-index: 4;
|
||
top: 19px;
|
||
left: 98px;
|
||
width: 148px;
|
||
height: 45px;
|
||
}
|
||
|
||
.row-name {
|
||
display: block;
|
||
overflow: hidden;
|
||
font-size: 14px;
|
||
line-height: 17px;
|
||
text-overflow: ellipsis;
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.row-badges {
|
||
display: flex;
|
||
height: 20px;
|
||
align-items: center;
|
||
gap: 3px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.row-badges .rank-badge {
|
||
max-width: 17px;
|
||
height: 14px;
|
||
}
|
||
|
||
.row-score {
|
||
position: absolute;
|
||
z-index: 4;
|
||
top: 29px;
|
||
right: 29px;
|
||
justify-content: flex-end;
|
||
width: 86px;
|
||
font-size: 16px;
|
||
line-height: 20px;
|
||
text-align: right;
|
||
}
|
||
|
||
.row-score .score-coin {
|
||
width: 14px;
|
||
height: 14px;
|
||
}
|
||
|
||
.empty-state,
|
||
.error-state {
|
||
display: none;
|
||
min-height: 150px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 14px;
|
||
text-align: center;
|
||
text-shadow: 0 1px 3px #000;
|
||
}
|
||
|
||
.empty-state.is-visible,
|
||
.error-state.is-visible {
|
||
display: flex;
|
||
}
|
||
|
||
.my-rank {
|
||
position: fixed;
|
||
z-index: 80;
|
||
bottom: 0;
|
||
left: 50%;
|
||
display: block;
|
||
width: 375px;
|
||
height: 82px;
|
||
margin-left: -187.5px;
|
||
overflow: hidden;
|
||
border-top: 1px solid #ffe76d;
|
||
border-radius: 8px 8px 0 0;
|
||
color: var(--mine-text);
|
||
text-align: left;
|
||
background:
|
||
linear-gradient(
|
||
180deg,
|
||
var(--mine-glow) 0%,
|
||
transparent 100%
|
||
),
|
||
linear-gradient(90deg, var(--mine-start), var(--mine-end));
|
||
box-shadow: 0 -5px 16px rgba(26, 12, 0, 0.22);
|
||
zoom: var(--rank-zoom);
|
||
}
|
||
|
||
.my-rank::before {
|
||
position: absolute;
|
||
top: -1px;
|
||
left: 40px;
|
||
width: 88px;
|
||
height: 1px;
|
||
background: linear-gradient(
|
||
90deg,
|
||
transparent,
|
||
#fff,
|
||
transparent
|
||
);
|
||
content: '';
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.mine-number {
|
||
position: absolute;
|
||
top: 22px;
|
||
left: 18px;
|
||
width: 12px;
|
||
font-size: 20px;
|
||
line-height: 22px;
|
||
text-align: center;
|
||
}
|
||
|
||
.mine-avatar {
|
||
position: absolute;
|
||
top: 11px;
|
||
left: 46px;
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.mine-main {
|
||
position: absolute;
|
||
top: 12px;
|
||
left: 100px;
|
||
width: 150px;
|
||
}
|
||
|
||
.mine-name {
|
||
display: block;
|
||
overflow: hidden;
|
||
font-size: 16px;
|
||
line-height: 18px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.mine-badges {
|
||
height: 23px;
|
||
justify-content: flex-start;
|
||
gap: 5px;
|
||
}
|
||
|
||
.mine-badges .rank-badge {
|
||
max-width: 18px;
|
||
height: 16px;
|
||
}
|
||
|
||
.mine-score {
|
||
position: absolute;
|
||
top: 24px;
|
||
right: 22px;
|
||
justify-content: flex-end;
|
||
width: 90px;
|
||
font-size: 16px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.mine-score .score-coin {
|
||
width: 14px;
|
||
height: 14px;
|
||
}
|
||
|
||
.home-indicator {
|
||
position: absolute;
|
||
right: 121px;
|
||
bottom: 9px;
|
||
left: 121px;
|
||
height: 5px;
|
||
border-radius: 3px;
|
||
background: #fff;
|
||
}
|
||
|
||
.loading-overlay {
|
||
position: fixed;
|
||
z-index: 120;
|
||
inset: 0;
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(0, 0, 0, 0.16);
|
||
}
|
||
|
||
.loading-overlay.is-visible {
|
||
display: flex;
|
||
}
|
||
|
||
.loading-dot {
|
||
width: 30px;
|
||
height: 30px;
|
||
border: 3px solid rgba(255, 255, 255, 0.28);
|
||
border-top-color: #ffd349;
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
[dir='rtl'] .rank-item,
|
||
[dir='rtl'] .my-rank {
|
||
direction: ltr;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.loading-dot {
|
||
animation-duration: 1.8s;
|
||
}
|
||
}
|
||
</style>
|
||
<script>
|
||
window.HyAppI18nSupported = ['en', 'ar', 'tr', 'es'];
|
||
// Huwaa 独立入口必须在公共 API/参数脚本执行前固定 app_code;否则 localStorage 中其他品牌值会污染请求头与用户概览。
|
||
window.HyAppDefaultAppCode = 'huwaa';
|
||
(function enforceHuwaaAppCode() {
|
||
try {
|
||
var entryURL = new URL(window.location.href);
|
||
if (entryURL.searchParams.get('app_code') !== 'huwaa') {
|
||
entryURL.searchParams.set('app_code', 'huwaa');
|
||
window.history.replaceState(
|
||
null,
|
||
'',
|
||
entryURL.toString()
|
||
);
|
||
}
|
||
} catch (_) {
|
||
// 旧 WebView 可能禁止 file:// 改写 history;默认值仍保证请求层发送 X-App-Code: huwaa。
|
||
}
|
||
})();
|
||
</script>
|
||
<script src="../common/api.js"></script>
|
||
<script src="../common/params.js"></script>
|
||
<script src="../common/jsbridge.js"></script>
|
||
<script src="../common/i18n.js"></script>
|
||
</head>
|
||
<body>
|
||
<main class="rank-app" id="rankApp">
|
||
<div class="rank-background" aria-hidden="true"></div>
|
||
|
||
<header class="sticky-header">
|
||
<nav
|
||
class="top-nav"
|
||
data-i18n-aria="fami_rank.navigation"
|
||
aria-label="Ranking navigation"
|
||
>
|
||
<button
|
||
class="back-button"
|
||
id="backButton"
|
||
type="button"
|
||
data-i18n-aria="fami_rank.back"
|
||
aria-label="Back"
|
||
></button>
|
||
<div class="board-tabs" id="boardTabs">
|
||
<button
|
||
class="board-tab"
|
||
type="button"
|
||
data-board="wealth"
|
||
data-i18n="fami_rank.wealth"
|
||
>
|
||
Wealth
|
||
</button>
|
||
<button
|
||
class="board-tab"
|
||
type="button"
|
||
data-board="room"
|
||
data-i18n="fami_rank.room"
|
||
>
|
||
Room
|
||
</button>
|
||
<button
|
||
class="board-tab"
|
||
type="button"
|
||
data-board="charm"
|
||
data-i18n="fami_rank.charm"
|
||
>
|
||
Charm
|
||
</button>
|
||
<button
|
||
class="board-tab"
|
||
type="button"
|
||
data-board="game"
|
||
data-i18n="huwaa_rank.game"
|
||
>
|
||
Game
|
||
</button>
|
||
</div>
|
||
<button
|
||
class="help-button"
|
||
id="helpButton"
|
||
type="button"
|
||
data-i18n-aria="fami_rank.rules"
|
||
aria-label="Ranking rules"
|
||
>
|
||
?
|
||
</button>
|
||
</nav>
|
||
|
||
<div class="period-tabs" id="periodTabs">
|
||
<button
|
||
class="period-tab"
|
||
type="button"
|
||
data-period="today"
|
||
data-i18n="fami_rank.daily"
|
||
>
|
||
Daily
|
||
</button>
|
||
<button
|
||
class="period-tab"
|
||
type="button"
|
||
data-period="week"
|
||
data-i18n="fami_rank.weekly"
|
||
>
|
||
Weekly
|
||
</button>
|
||
<button
|
||
class="period-tab"
|
||
type="button"
|
||
data-period="month"
|
||
data-i18n="fami_rank.monthly"
|
||
>
|
||
Monthly
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<section class="podium" id="podium" aria-live="polite"></section>
|
||
<section class="rank-list" id="rankList"></section>
|
||
<div
|
||
class="empty-state"
|
||
id="emptyState"
|
||
data-i18n="fami_rank.empty"
|
||
>
|
||
No ranking data yet
|
||
</div>
|
||
<div
|
||
class="error-state"
|
||
id="errorState"
|
||
data-i18n="fami_rank.network_error"
|
||
>
|
||
Unable to load the ranking. Please try again.
|
||
</div>
|
||
</main>
|
||
|
||
<button class="my-rank" id="myRank" type="button" hidden></button>
|
||
<div
|
||
class="loading-overlay"
|
||
id="loadingOverlay"
|
||
aria-hidden="true"
|
||
data-i18n-aria="fami_rank.loading"
|
||
aria-label="Loading"
|
||
>
|
||
<span class="loading-dot"></span>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
'use strict';
|
||
|
||
var ASSET_ROOT = 'assets/huwaa/';
|
||
var BOARD_CONFIG = {
|
||
// UI 名称与后端枚举解耦;切换主题时只从这里读取协议值,避免翻译文案或 URL 别名直接进入接口。
|
||
wealth: {
|
||
apiType: 'sent',
|
||
background: 'bg-wealth.webp',
|
||
rowFrame: 'row-wealth.svg',
|
||
base: '#3e1b00',
|
||
fade: 'rgba(62, 27, 0, .9)',
|
||
shade: 'rgba(58, 34, 16, .58)',
|
||
photoOpacity: '.14',
|
||
mineStart: '#ffe27d',
|
||
mineEnd: '#d78d0d',
|
||
mineGlow: 'rgba(255, 210, 106, .68)',
|
||
mineText: '#6a4300',
|
||
},
|
||
room: {
|
||
apiType: 'room',
|
||
background: 'bg-room.webp',
|
||
rowFrame: 'row-room.svg',
|
||
base: '#003958',
|
||
fade: 'rgba(0, 57, 88, .92)',
|
||
shade: 'rgba(9, 5, 35, .38)',
|
||
photoOpacity: '.14',
|
||
mineStart: '#5577f4',
|
||
mineEnd: '#122b81',
|
||
mineGlow: 'rgba(101, 136, 255, .72)',
|
||
mineText: '#fff',
|
||
},
|
||
charm: {
|
||
apiType: 'received',
|
||
background: 'bg-charm.webp',
|
||
rowFrame: 'row-charm.svg',
|
||
base: '#2f0044',
|
||
fade: 'rgba(47, 0, 68, .92)',
|
||
shade: 'rgba(9, 5, 35, .36)',
|
||
photoOpacity: '.14',
|
||
mineStart: '#c230df',
|
||
mineEnd: '#6c128a',
|
||
mineGlow: 'rgba(213, 80, 255, .7)',
|
||
mineText: '#fff',
|
||
},
|
||
game: {
|
||
// 游戏榜使用后端独立 game bucket,禁止复用 sent,避免财富榜数据被误展示为游戏排名。
|
||
apiType: 'game',
|
||
background: 'bg-game.webp',
|
||
rowFrame: 'row-game.svg',
|
||
base: '#190c03',
|
||
fade: 'rgba(25, 12, 3, .94)',
|
||
shade: 'rgba(9, 5, 35, .36)',
|
||
photoOpacity: '.2',
|
||
mineStart: '#ffe27d',
|
||
mineEnd: '#d78d0d',
|
||
mineGlow: 'rgba(255, 210, 106, .68)',
|
||
mineText: '#6a4300',
|
||
},
|
||
};
|
||
var PERIODS = ['today', 'week', 'month'];
|
||
var query = new URLSearchParams(window.location.search);
|
||
var state = {
|
||
board: normalizeBoard(
|
||
query.get('board') || query.get('board_type')
|
||
),
|
||
period:
|
||
PERIODS.indexOf(query.get('period')) >= 0
|
||
? query.get('period')
|
||
: 'today',
|
||
page: 1,
|
||
pageSize: 20,
|
||
total: 0,
|
||
items: [],
|
||
myRank: null,
|
||
currentUser: null,
|
||
loading: false,
|
||
loaded: false,
|
||
error: null,
|
||
requestSerial: 0,
|
||
};
|
||
|
||
function byId(id) {
|
||
return document.getElementById(id);
|
||
}
|
||
|
||
function normalizeBoard(value) {
|
||
var aliases = {
|
||
sent: 'wealth',
|
||
wealth: 'wealth',
|
||
received: 'charm',
|
||
charm: 'charm',
|
||
room: 'room',
|
||
rooms: 'room',
|
||
game: 'game',
|
||
gaming: 'game',
|
||
};
|
||
return (
|
||
aliases[String(value || '').toLowerCase()] || 'wealth'
|
||
);
|
||
}
|
||
|
||
function escapeHTML(value) {
|
||
return String(value == null ? '' : value)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|
||
|
||
function t(key, fallback) {
|
||
return window.HyAppI18n && window.HyAppI18n.t
|
||
? window.HyAppI18n.t(key, fallback)
|
||
: fallback;
|
||
}
|
||
|
||
function mockEnabled() {
|
||
var hasToken = Boolean(
|
||
window.HyAppAPI &&
|
||
window.HyAppAPI.getAccessToken &&
|
||
window.HyAppAPI.getAccessToken()
|
||
);
|
||
// APP 可能以 file:// 承载 H5;只有文件预览且无 token 时启用样例,携带 token 必须走 Huwaa 真实请求。
|
||
return (
|
||
query.get('mock') === '1' ||
|
||
(window.location.protocol === 'file:' && !hasToken)
|
||
);
|
||
}
|
||
|
||
function compactNumber(value) {
|
||
var number = Number(value || 0);
|
||
if (!Number.isFinite(number)) number = 0;
|
||
if (number >= 1000000000)
|
||
return trimDecimal(number / 1000000000) + 'b';
|
||
if (number >= 1000000)
|
||
return trimDecimal(number / 1000000) + 'm';
|
||
if (number >= 1000) return trimDecimal(number / 1000) + 'k';
|
||
return String(Math.round(number));
|
||
}
|
||
|
||
function trimDecimal(value) {
|
||
return value
|
||
.toFixed(value >= 100 ? 0 : 1)
|
||
.replace(/\.0$/, '');
|
||
}
|
||
|
||
function normalizeItem(raw) {
|
||
var item = raw || {};
|
||
var user = item.user || {};
|
||
var room = item.room || {};
|
||
var badges =
|
||
user.short_badge_cover_urls ||
|
||
user.shortBadgeCoverUrls ||
|
||
[];
|
||
if (!Array.isArray(badges)) badges = [];
|
||
return {
|
||
rank: Number(item.rank || 0),
|
||
giftValue: Number(
|
||
item.gift_value || item.giftValue || item.value || 0
|
||
),
|
||
userId: String(
|
||
item.user_id || user.user_id || user.userId || ''
|
||
),
|
||
roomId: String(
|
||
item.room_id || room.room_id || room.roomId || ''
|
||
),
|
||
name:
|
||
user.username ||
|
||
user.nickname ||
|
||
user.display_user_id ||
|
||
room.title ||
|
||
room.name ||
|
||
room.room_short_id ||
|
||
t('fami_rank.unknown', 'Unknown'),
|
||
avatar:
|
||
user.avatar ||
|
||
user.avatar_url ||
|
||
user.avatarUrl ||
|
||
room.cover_url ||
|
||
room.coverUrl ||
|
||
room.room_avatar ||
|
||
room.avatar ||
|
||
'',
|
||
badges: badges.filter(function (url) {
|
||
return typeof url === 'string' && url.trim();
|
||
}),
|
||
};
|
||
}
|
||
|
||
function normalizeCurrentUser(current) {
|
||
var overview = current && current.user;
|
||
var profile =
|
||
(overview &&
|
||
(overview.profile || overview.user || overview)) ||
|
||
{};
|
||
var badges =
|
||
profile.short_badge_cover_urls ||
|
||
profile.shortBadgeCoverUrls ||
|
||
[];
|
||
if (!Array.isArray(badges)) badges = [];
|
||
return {
|
||
rank: 0,
|
||
giftValue: 0,
|
||
userId: String(
|
||
profile.user_id ||
|
||
profile.userId ||
|
||
profile.id ||
|
||
''
|
||
),
|
||
roomId: '',
|
||
name:
|
||
profile.nickname ||
|
||
profile.username ||
|
||
profile.display_user_id ||
|
||
profile.user_id ||
|
||
t('fami_rank.unknown', 'Unknown'),
|
||
avatar:
|
||
profile.avatar ||
|
||
profile.avatar_url ||
|
||
profile.avatarUrl ||
|
||
'',
|
||
badges: badges.filter(function (url) {
|
||
return typeof url === 'string' && url.trim();
|
||
}),
|
||
};
|
||
}
|
||
|
||
function normalizePayload(data, reset) {
|
||
var incoming = (
|
||
data && Array.isArray(data.items) ? data.items : []
|
||
)
|
||
.map(normalizeItem)
|
||
.filter(function (item) {
|
||
return item.rank > 0;
|
||
});
|
||
state.items = reset
|
||
? incoming
|
||
: state.items.concat(incoming);
|
||
state.total = Number(
|
||
(data && data.total) || state.items.length || 0
|
||
);
|
||
state.page = Number((data && data.page) || state.page);
|
||
state.pageSize = Number(
|
||
(data && (data.page_size || data.pageSize)) ||
|
||
state.pageSize
|
||
);
|
||
state.myRank =
|
||
data && data.my_rank
|
||
? normalizeItem(data.my_rank)
|
||
: null;
|
||
state.loaded = true;
|
||
state.error = null;
|
||
}
|
||
|
||
function mockItems() {
|
||
return Array.from({ length: 14 }, function (_, index) {
|
||
return {
|
||
rank: index + 1,
|
||
giftValue:
|
||
index < 3 ? 1232345 : 102400 - index * 700,
|
||
userId: 'huwaa_user_' + (index + 1),
|
||
roomId: 'huwaa_room_' + (index + 1),
|
||
name: index < 3 ? 'Namename' : 'Namenamename',
|
||
avatar:
|
||
ASSET_ROOT +
|
||
(index === 0
|
||
? 'default-top.webp'
|
||
: index < 3
|
||
? 'default-side.webp'
|
||
: 'default-row.webp'),
|
||
// 样例徽章只用于 Figma 核对;真实接口为空时必须不渲染,不能伪造用户权益。
|
||
badges: Array.from(
|
||
{ length: index === 0 ? 5 : 4 },
|
||
function () {
|
||
return ASSET_ROOT + 'mock-badge.webp';
|
||
}
|
||
),
|
||
};
|
||
});
|
||
}
|
||
|
||
function visibleItems() {
|
||
return mockEnabled() ? mockItems() : state.items;
|
||
}
|
||
|
||
function itemAvatar(item, rank) {
|
||
if (item && item.avatar) return item.avatar;
|
||
if (rank === 1) return ASSET_ROOT + 'default-top.webp';
|
||
if (rank === 2 || rank === 3)
|
||
return ASSET_ROOT + 'default-side.webp';
|
||
return ASSET_ROOT + 'default-row.webp';
|
||
}
|
||
|
||
function badgeMarkup(item, className, limit) {
|
||
var badges =
|
||
item && Array.isArray(item.badges) ? item.badges : [];
|
||
return (
|
||
'<span class="' +
|
||
className +
|
||
'">' +
|
||
badges
|
||
.slice(0, limit)
|
||
.map(function (url) {
|
||
return (
|
||
'<img class="rank-badge" src="' +
|
||
escapeHTML(url) +
|
||
'" alt="" />'
|
||
);
|
||
})
|
||
.join('') +
|
||
'</span>'
|
||
);
|
||
}
|
||
|
||
function scoreMarkup(item, className) {
|
||
return (
|
||
'<span class="' +
|
||
className +
|
||
'"><img class="score-coin" src="' +
|
||
ASSET_ROOT +
|
||
'coin.webp" alt="" /><span>' +
|
||
compactNumber(item ? item.giftValue : 0) +
|
||
'</span></span>'
|
||
);
|
||
}
|
||
|
||
function podiumMarkup(item, rank) {
|
||
var actual = item || {
|
||
rank: rank,
|
||
name: t('fami_rank.unknown', 'Unknown'),
|
||
giftValue: 0,
|
||
badges: [],
|
||
};
|
||
var classes =
|
||
rank === 1
|
||
? 'podium-card top-one'
|
||
: rank === 2
|
||
? 'podium-card side top-two'
|
||
: 'podium-card side top-three';
|
||
var normalFrame =
|
||
rank === 1
|
||
? 'top-frame.webp'
|
||
: rank === 2
|
||
? 'side-frame-silver.webp'
|
||
: 'side-frame-bronze.webp';
|
||
var normalBanner =
|
||
rank === 1
|
||
? 'top-banner.webp'
|
||
: rank === 2
|
||
? 'side-banner-silver.webp'
|
||
: 'side-banner-bronze.webp';
|
||
var gameFrame =
|
||
rank === 1
|
||
? 'game-top.webp'
|
||
: rank === 2
|
||
? 'game-silver.webp'
|
||
: 'game-bronze.webp';
|
||
var art =
|
||
state.board === 'game'
|
||
? '<img class="game-frame" src="' +
|
||
ASSET_ROOT +
|
||
gameFrame +
|
||
'" alt="" />'
|
||
: '<img class="podium-banner" src="' +
|
||
ASSET_ROOT +
|
||
normalBanner +
|
||
'" alt="" /><img class="podium-avatar" src="' +
|
||
escapeHTML(itemAvatar(actual, rank)) +
|
||
'" alt="" /><img class="podium-frame" src="' +
|
||
ASSET_ROOT +
|
||
normalFrame +
|
||
'" alt="" />';
|
||
return (
|
||
'<button class="' +
|
||
classes +
|
||
'" type="button" data-rank="' +
|
||
rank +
|
||
'"' +
|
||
(item ? '' : ' disabled') +
|
||
'>' +
|
||
art +
|
||
'<span class="podium-copy"><span class="podium-name">' +
|
||
escapeHTML(actual.name) +
|
||
'</span>' +
|
||
badgeMarkup(actual, 'badge-strip', rank === 1 ? 5 : 4) +
|
||
scoreMarkup(actual, 'podium-score') +
|
||
'</span></button>'
|
||
);
|
||
}
|
||
|
||
function rowMarkup(item) {
|
||
return (
|
||
'<button class="rank-item" type="button" data-rank="' +
|
||
item.rank +
|
||
'"><img class="row-frame" src="' +
|
||
ASSET_ROOT +
|
||
BOARD_CONFIG[state.board].rowFrame +
|
||
'" alt="" /><span class="row-photo"></span><img class="row-ornament" src="' +
|
||
ASSET_ROOT +
|
||
'row-ornament.webp" alt="" /><span class="rank-number">' +
|
||
item.rank +
|
||
'</span><img class="row-avatar" src="' +
|
||
escapeHTML(itemAvatar(item, 0)) +
|
||
'" alt="" /><span class="row-main"><span class="row-name">' +
|
||
escapeHTML(item.name) +
|
||
'</span>' +
|
||
badgeMarkup(item, 'row-badges', 4) +
|
||
'</span>' +
|
||
scoreMarkup(item, 'row-score') +
|
||
'</button>'
|
||
);
|
||
}
|
||
|
||
function currentMineItem() {
|
||
if (mockEnabled()) {
|
||
var sample = mockItems()[3];
|
||
sample.badges.push(ASSET_ROOT + 'mock-badge.webp');
|
||
return sample;
|
||
}
|
||
// 未上榜仍保留真实用户资料,排名显示 --、值显示 0;否则底栏会在弱活跃用户上整条消失。
|
||
return state.myRank || state.currentUser;
|
||
}
|
||
|
||
function renderMine() {
|
||
var item = currentMineItem();
|
||
var mine = byId('myRank');
|
||
mine.hidden = !item;
|
||
if (!item) {
|
||
mine.innerHTML = '';
|
||
return;
|
||
}
|
||
mine.innerHTML =
|
||
'<span class="mine-number">' +
|
||
(item.rank || '--') +
|
||
'</span><img class="mine-avatar" src="' +
|
||
escapeHTML(itemAvatar(item, 0)) +
|
||
'" alt="" /><span class="mine-main"><span class="mine-name">' +
|
||
escapeHTML(item.name) +
|
||
'</span>' +
|
||
badgeMarkup(item, 'badge-strip mine-badges', 5) +
|
||
'</span>' +
|
||
scoreMarkup(item, 'mine-score') +
|
||
'<span class="home-indicator"></span>';
|
||
}
|
||
|
||
function render() {
|
||
var config = BOARD_CONFIG[state.board];
|
||
var root = document.documentElement;
|
||
root.style.setProperty(
|
||
'--rank-bg',
|
||
'url("' + ASSET_ROOT + config.background + '")'
|
||
);
|
||
root.style.setProperty('--rank-base', config.base);
|
||
root.style.setProperty('--rank-fade', config.fade);
|
||
root.style.setProperty('--rank-shade', config.shade);
|
||
root.style.setProperty(
|
||
'--row-photo-opacity',
|
||
config.photoOpacity
|
||
);
|
||
root.style.setProperty('--mine-start', config.mineStart);
|
||
root.style.setProperty('--mine-end', config.mineEnd);
|
||
root.style.setProperty('--mine-glow', config.mineGlow);
|
||
root.style.setProperty('--mine-text', config.mineText);
|
||
document
|
||
.querySelector('meta[name="theme-color"]')
|
||
.setAttribute('content', config.base);
|
||
byId('rankApp').classList.toggle(
|
||
'is-game',
|
||
state.board === 'game'
|
||
);
|
||
document
|
||
.querySelectorAll('[data-board]')
|
||
.forEach(function (node) {
|
||
node.classList.toggle(
|
||
'is-active',
|
||
node.getAttribute('data-board') === state.board
|
||
);
|
||
});
|
||
document
|
||
.querySelectorAll('[data-period]')
|
||
.forEach(function (node) {
|
||
node.classList.toggle(
|
||
'is-active',
|
||
node.getAttribute('data-period') ===
|
||
state.period
|
||
);
|
||
});
|
||
var items = visibleItems();
|
||
byId('podium').innerHTML =
|
||
podiumMarkup(items[0], 1) +
|
||
podiumMarkup(items[1], 2) +
|
||
podiumMarkup(items[2], 3);
|
||
byId('rankList').innerHTML = items
|
||
.slice(3)
|
||
.map(rowMarkup)
|
||
.join('');
|
||
byId('emptyState').classList.toggle(
|
||
'is-visible',
|
||
state.loaded && !state.error && items.length === 0
|
||
);
|
||
byId('errorState').classList.toggle(
|
||
'is-visible',
|
||
state.loaded &&
|
||
Boolean(state.error) &&
|
||
items.length === 0
|
||
);
|
||
byId('loadingOverlay').classList.toggle(
|
||
'is-visible',
|
||
state.loading
|
||
);
|
||
byId('loadingOverlay').setAttribute(
|
||
'aria-hidden',
|
||
state.loading ? 'false' : 'true'
|
||
);
|
||
renderMine();
|
||
}
|
||
|
||
function updateURLState() {
|
||
if (!window.history || !window.history.replaceState) return;
|
||
var url = new URL(window.location.href);
|
||
url.searchParams.set('app_code', 'huwaa');
|
||
url.searchParams.set('board', state.board);
|
||
url.searchParams.set('period', state.period);
|
||
window.history.replaceState(null, '', url.toString());
|
||
}
|
||
|
||
function load(reset) {
|
||
if (reset) {
|
||
state.page = 1;
|
||
state.items = [];
|
||
state.total = 0;
|
||
state.myRank = null;
|
||
state.loaded = false;
|
||
state.error = null;
|
||
}
|
||
if (mockEnabled()) {
|
||
state.loaded = true;
|
||
state.loading = false;
|
||
state.error = null;
|
||
render();
|
||
return Promise.resolve();
|
||
}
|
||
if (!window.HyAppAPI || !window.HyAppAPI.getAccessToken()) {
|
||
state.loaded = true;
|
||
state.loading = false;
|
||
state.error = new Error('missing_token');
|
||
render();
|
||
return Promise.resolve();
|
||
}
|
||
var requestedPage = state.page;
|
||
var serial = ++state.requestSerial;
|
||
state.loading = true;
|
||
state.error = null;
|
||
render();
|
||
return window.HyAppAPI.get(
|
||
'/api/v1/activities/user-leaderboards',
|
||
{
|
||
board_type: BOARD_CONFIG[state.board].apiType,
|
||
period: state.period,
|
||
page: requestedPage,
|
||
page_size: state.pageSize,
|
||
}
|
||
)
|
||
.then(function (payload) {
|
||
// 切榜、切周期可能并发;只接收最后一次请求,防止慢响应把当前主题覆盖回旧榜。
|
||
if (serial !== state.requestSerial) return;
|
||
normalizePayload(payload, reset);
|
||
})
|
||
.catch(function (error) {
|
||
if (serial !== state.requestSerial) return;
|
||
state.loaded = true;
|
||
state.error = error;
|
||
// 翻页失败回滚页码,下一次触底才会重试失败页而不是永久跳页。
|
||
if (!reset)
|
||
state.page = Math.max(1, requestedPage - 1);
|
||
})
|
||
.finally(function () {
|
||
if (serial !== state.requestSerial) return;
|
||
state.loading = false;
|
||
render();
|
||
});
|
||
}
|
||
|
||
function switchBoard(board) {
|
||
if (!BOARD_CONFIG[board] || state.board === board) return;
|
||
state.board = board;
|
||
state.requestSerial += 1;
|
||
updateURLState();
|
||
window.scrollTo(0, 0);
|
||
load(true);
|
||
}
|
||
|
||
function switchPeriod(period) {
|
||
if (PERIODS.indexOf(period) < 0 || state.period === period)
|
||
return;
|
||
state.period = period;
|
||
state.requestSerial += 1;
|
||
updateURLState();
|
||
window.scrollTo(0, 0);
|
||
load(true);
|
||
}
|
||
|
||
function itemByRank(rank) {
|
||
return visibleItems().find(function (item) {
|
||
return String(item.rank) === String(rank);
|
||
});
|
||
}
|
||
|
||
function openItem(item) {
|
||
if (!item) return;
|
||
if (state.board === 'room') {
|
||
if (item.roomId)
|
||
window.HyAppBridge.openRoom(item.roomId);
|
||
return;
|
||
}
|
||
if (item.userId) window.HyAppBridge.openUser(item.userId);
|
||
}
|
||
|
||
function resizeCanvas() {
|
||
// 375px 是 Figma 基准;窄屏整体缩放,避免皇冠、榜框的绝对坐标被流式布局挤散。
|
||
var zoom = Math.min(1, window.innerWidth / 375);
|
||
document.documentElement.style.setProperty(
|
||
'--rank-zoom',
|
||
String(zoom)
|
||
);
|
||
}
|
||
|
||
byId('boardTabs').addEventListener('click', function (event) {
|
||
var target = event.target.closest('[data-board]');
|
||
if (target) switchBoard(target.getAttribute('data-board'));
|
||
});
|
||
byId('periodTabs').addEventListener('click', function (event) {
|
||
var target = event.target.closest('[data-period]');
|
||
if (target)
|
||
switchPeriod(target.getAttribute('data-period'));
|
||
});
|
||
byId('podium').addEventListener('click', function (event) {
|
||
var target = event.target.closest('[data-rank]');
|
||
if (target)
|
||
openItem(itemByRank(target.getAttribute('data-rank')));
|
||
});
|
||
byId('rankList').addEventListener('click', function (event) {
|
||
var target = event.target.closest('[data-rank]');
|
||
if (target)
|
||
openItem(itemByRank(target.getAttribute('data-rank')));
|
||
});
|
||
byId('myRank').addEventListener('click', function () {
|
||
openItem(currentMineItem());
|
||
});
|
||
byId('backButton').addEventListener('click', function () {
|
||
window.HyAppBridge.back();
|
||
});
|
||
byId('helpButton').addEventListener('click', function () {
|
||
if (window.HyAppBridge.openRankNote)
|
||
window.HyAppBridge.openRankNote(state.board);
|
||
});
|
||
|
||
document.addEventListener(
|
||
'error',
|
||
function (event) {
|
||
var image = event.target;
|
||
if (!image || image.tagName !== 'IMG') return;
|
||
if (image.classList.contains('rank-badge')) {
|
||
// 失效远端徽章直接移除;本地替代图会错误展示用户并未拥有的权益。
|
||
image.remove();
|
||
return;
|
||
}
|
||
if (
|
||
image.classList.contains('row-frame') ||
|
||
image.classList.contains('row-ornament') ||
|
||
image.classList.contains('podium-frame') ||
|
||
image.classList.contains('podium-banner') ||
|
||
image.classList.contains('game-frame') ||
|
||
image.classList.contains('score-coin')
|
||
) {
|
||
return;
|
||
}
|
||
// CDN 头像失败只回退头像资源,装饰和徽章保持真实失败语义。
|
||
image.src = ASSET_ROOT + 'default-row.webp';
|
||
},
|
||
true
|
||
);
|
||
|
||
window.addEventListener('scroll', function () {
|
||
if (
|
||
mockEnabled() ||
|
||
state.loading ||
|
||
!state.loaded ||
|
||
!state.total ||
|
||
state.items.length >= state.total
|
||
) {
|
||
return;
|
||
}
|
||
if (
|
||
window.innerHeight + window.scrollY >=
|
||
document.documentElement.scrollHeight - 180
|
||
) {
|
||
state.page += 1;
|
||
load(false);
|
||
}
|
||
});
|
||
window.addEventListener('resize', resizeCanvas);
|
||
window.addEventListener('hyapp:i18n-ready', render);
|
||
|
||
// WebView 刷新会恢复旧滚动位置;排行榜入口固定从吸顶导航开始,避免首屏直接落在三甲中段。
|
||
if ('scrollRestoration' in window.history) {
|
||
window.history.scrollRestoration = 'manual';
|
||
}
|
||
window.scrollTo(0, 0);
|
||
resizeCanvas();
|
||
updateURLState();
|
||
render();
|
||
window.HyAppBridge.ready({ page: 'rank/huwaa' });
|
||
|
||
// 用户概览失败不能阻断排行榜;接口未返回 my_rank 时仍可用概览填充个人底栏。
|
||
Promise.resolve(
|
||
window.HyAppParams && window.HyAppParams.loadUser
|
||
? window.HyAppParams.loadUser()
|
||
: null
|
||
)
|
||
.then(function (current) {
|
||
state.currentUser = current
|
||
? normalizeCurrentUser(current)
|
||
: null;
|
||
render();
|
||
})
|
||
.catch(function () {
|
||
return null;
|
||
})
|
||
.finally(function () {
|
||
load(true);
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|