充值,新公会开业活动,CP活动
This commit is contained in:
parent
802bc1c686
commit
ce3725ae37
@ -7,7 +7,7 @@
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<title>New Agency Opening Event</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20260612-agency-opening" />
|
||||
<link rel="stylesheet" href="./style.css?v=20260616-agency-opening-tabs" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-viewport" id="appViewport">
|
||||
@ -366,6 +366,6 @@
|
||||
</script>
|
||||
<script src="../../common/i18n.js?v=20260612-agency-opening"></script>
|
||||
<script src="../../common/api.js?v=20260612-agency-opening"></script>
|
||||
<script src="./script.js?v=20260612-agency-opening"></script>
|
||||
<script src="./script.js?v=20260616-agency-opening-tiers"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -250,7 +250,13 @@
|
||||
.map(function (item) {
|
||||
var revenue = firstValue(
|
||||
item,
|
||||
['opening_revenue', 'openingRevenue', 'revenue'],
|
||||
[
|
||||
'opening_revenue',
|
||||
'openingRevenue',
|
||||
'threshold_coin_spent',
|
||||
'thresholdCoinSpent',
|
||||
'revenue',
|
||||
],
|
||||
'500K'
|
||||
);
|
||||
var reward = firstValue(
|
||||
@ -261,7 +267,7 @@
|
||||
return [
|
||||
'<div class="reward-row">',
|
||||
'<span>',
|
||||
escapeHTML(revenue),
|
||||
escapeHTML(formatCoinLabel(revenue)),
|
||||
'</span>',
|
||||
'<span>',
|
||||
escapeHTML(reward),
|
||||
@ -290,9 +296,8 @@
|
||||
state.qualification.identity;
|
||||
document.getElementById('hostCountText').textContent =
|
||||
state.qualification.hostCount +
|
||||
' / ' +
|
||||
state.qualification.hostRequirement +
|
||||
'+';
|
||||
' / > ' +
|
||||
state.qualification.hostRequirement;
|
||||
document.getElementById('openingStatusText').textContent =
|
||||
state.qualification.openingStatus;
|
||||
document.getElementById('eligibilityText').textContent = state
|
||||
@ -419,6 +424,14 @@
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function formatCoinLabel(value) {
|
||||
var amount = Number(value);
|
||||
if (!Number.isFinite(amount) || amount <= 0) return value;
|
||||
if (amount % 1000000 === 0) return amount / 1000000 + 'M';
|
||||
if (amount % 1000 === 0) return amount / 1000 + 'K';
|
||||
return String(amount);
|
||||
}
|
||||
|
||||
function init() {
|
||||
document.title = t(
|
||||
'agencyOpening.pageTitle',
|
||||
|
||||
@ -130,8 +130,8 @@ button:focus-visible {
|
||||
left: 18px;
|
||||
top: 46px;
|
||||
display: grid;
|
||||
grid-template-columns: 221px repeat(5, 141px);
|
||||
gap: 0;
|
||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
width: 1026px;
|
||||
height: 70px;
|
||||
@ -141,7 +141,13 @@ button:focus-visible {
|
||||
|
||||
.language-tab {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 57px;
|
||||
padding: 0 10px;
|
||||
border: 2px solid #fde5cc;
|
||||
border-radius: 39px;
|
||||
background: linear-gradient(180deg, #4d145a, #210a34);
|
||||
@ -153,47 +159,14 @@ button:focus-visible {
|
||||
text-shadow: 0 1px 7px rgba(87, 16, 110, 0.82);
|
||||
}
|
||||
|
||||
.language-tab:first-child {
|
||||
width: 221px;
|
||||
height: 65px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.language-tab span {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.language-tab:first-child::before,
|
||||
.language-tab:first-child::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
inset: 0 auto auto 0;
|
||||
width: 221px;
|
||||
height: 65px;
|
||||
background-image: url('./assets/lang-sheen.png');
|
||||
background-size: 221px 65px;
|
||||
background-repeat: no-repeat;
|
||||
z-index: 1;
|
||||
-webkit-mask: url('./assets/lang-mask-left.svg') 0 0 / 100px 65px no-repeat;
|
||||
mask: url('./assets/lang-mask-left.svg') 0 0 / 100px 65px no-repeat;
|
||||
}
|
||||
|
||||
.language-tab:first-child::after {
|
||||
transform: rotate(180deg) scaleY(-1);
|
||||
-webkit-mask: url('./assets/lang-mask-right.svg') 121px 0 / 100px 65px
|
||||
no-repeat;
|
||||
mask: url('./assets/lang-mask-right.svg') 121px 0 / 100px 65px no-repeat;
|
||||
}
|
||||
|
||||
.language-tab.is-active {
|
||||
background: linear-gradient(180deg, #6b2a72, #2b0c46);
|
||||
color: #fff8e4;
|
||||
}
|
||||
|
||||
.language-tab:not(:first-child).is-active {
|
||||
box-shadow:
|
||||
inset 0 0 18px rgba(255, 222, 151, 0.2),
|
||||
0 0 14px rgba(255, 203, 116, 0.22);
|
||||
@ -618,14 +591,14 @@ button:focus-visible {
|
||||
.rules-list {
|
||||
position: absolute;
|
||||
left: 119px;
|
||||
top: 306px;
|
||||
top: 258px;
|
||||
width: 842px;
|
||||
margin: 0;
|
||||
padding: 0 0 0 48px;
|
||||
color: var(--gold);
|
||||
font-size: 32px;
|
||||
font-size: 30px;
|
||||
font-weight: 500;
|
||||
line-height: 52px;
|
||||
line-height: 48px;
|
||||
text-transform: capitalize;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
@ -31,52 +31,116 @@
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
<div class="language-menu" data-language-menu hidden>
|
||||
<button type="button" data-lang-option="en">EN</button>
|
||||
<button type="button" data-lang-option="ar">AR</button>
|
||||
<button type="button" data-lang-option="tr">TR</button>
|
||||
<button type="button" data-lang-option="es">ES</button>
|
||||
<button type="button" data-lang-option="zh">ZH</button>
|
||||
<button type="button" data-lang-option="id">ID</button>
|
||||
<div
|
||||
class="language-menu"
|
||||
data-language-menu
|
||||
hidden
|
||||
>
|
||||
<button type="button" data-lang-option="en">
|
||||
EN
|
||||
</button>
|
||||
<button type="button" data-lang-option="ar">
|
||||
AR
|
||||
</button>
|
||||
<button type="button" data-lang-option="tr">
|
||||
TR
|
||||
</button>
|
||||
<button type="button" data-lang-option="es">
|
||||
ES
|
||||
</button>
|
||||
<button type="button" data-lang-option="zh">
|
||||
ZH
|
||||
</button>
|
||||
<button type="button" data-lang-option="id">
|
||||
ID
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img class="hero-bg" src="./assets/hero-bg.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
class="hero-bg"
|
||||
src="./assets/hero-bg.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<section class="countdown" aria-label="Activity countdown">
|
||||
<section
|
||||
class="countdown"
|
||||
aria-label="Activity countdown"
|
||||
>
|
||||
<div class="time-unit">
|
||||
<img src="./assets/countdown-heart.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
src="./assets/countdown-heart.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<strong data-count="days">02</strong>
|
||||
<span data-i18n="cp.days">D</span>
|
||||
</div>
|
||||
<div class="time-unit">
|
||||
<img src="./assets/countdown-heart.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
src="./assets/countdown-heart.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<strong data-count="hours">02</strong>
|
||||
<span data-i18n="cp.hours">H</span>
|
||||
</div>
|
||||
<div class="time-unit">
|
||||
<img src="./assets/countdown-heart.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
src="./assets/countdown-heart.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<strong data-count="minutes">02</strong>
|
||||
<span data-i18n="cp.minutes">M</span>
|
||||
</div>
|
||||
<div class="time-unit">
|
||||
<img src="./assets/countdown-heart.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
src="./assets/countdown-heart.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<strong data-count="seconds">02</strong>
|
||||
<span data-i18n="cp.seconds">S</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<nav class="tabs" aria-label="CP activity tabs" data-i18n-aria="cp.tabsLabel">
|
||||
<button class="tab is-active" type="button" data-tab="plaza">
|
||||
<img src="./assets/tab-active.png" alt="" aria-hidden="true" />
|
||||
<nav
|
||||
class="tabs"
|
||||
aria-label="CP activity tabs"
|
||||
data-i18n-aria="cp.tabsLabel"
|
||||
>
|
||||
<button
|
||||
class="tab is-active"
|
||||
type="button"
|
||||
data-tab="plaza"
|
||||
>
|
||||
<img
|
||||
src="./assets/tab-active.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span data-i18n="cp.tabPlaza">CP Plaza</span>
|
||||
</button>
|
||||
<button class="tab" type="button" data-tab="rank">
|
||||
<img src="./assets/tab-inactive.png" alt="" aria-hidden="true" />
|
||||
<img
|
||||
src="./assets/tab-inactive.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span data-i18n="cp.tabRank">CP Rank</span>
|
||||
</button>
|
||||
<button class="tab" type="button" data-tab="rewards">
|
||||
<img src="./assets/tab-inactive.png" alt="" aria-hidden="true" />
|
||||
<button
|
||||
class="tab"
|
||||
type="button"
|
||||
data-tab="rewards"
|
||||
>
|
||||
<img
|
||||
src="./assets/tab-inactive.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span data-i18n="cp.tabRewards">Rewards</span>
|
||||
</button>
|
||||
</nav>
|
||||
@ -94,9 +158,15 @@
|
||||
(function () {
|
||||
try {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (!params.get('lang') && !window.localStorage.getItem('cp_activity_lang_ready')) {
|
||||
if (
|
||||
!params.get('lang') &&
|
||||
!window.localStorage.getItem('cp_activity_lang_ready')
|
||||
) {
|
||||
window.localStorage.setItem('hyapp_h5_lang', 'en');
|
||||
window.localStorage.setItem('cp_activity_lang_ready', '1');
|
||||
window.localStorage.setItem(
|
||||
'cp_activity_lang_ready',
|
||||
'1'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
document.documentElement.lang = 'en';
|
||||
@ -104,6 +174,7 @@
|
||||
})();
|
||||
</script>
|
||||
<script src="../../common/i18n.js?v=20260608-cp"></script>
|
||||
<script src="../../common/api.js?v=20260608-cp"></script>
|
||||
<script src="./script.js?v=20260608-cp"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -10,6 +10,11 @@
|
||||
var activeTab = 'plaza';
|
||||
var countdownEndAt = 0;
|
||||
var countdownTimer = 0;
|
||||
var activityData = {
|
||||
rank: null,
|
||||
rewards: null,
|
||||
periodEndMS: 0,
|
||||
};
|
||||
|
||||
var viewport = document.getElementById('appViewport');
|
||||
var page = document.getElementById('page');
|
||||
@ -25,9 +30,24 @@
|
||||
previousRows: buildRows('score', 4),
|
||||
},
|
||||
rank: [
|
||||
{ place: 1, score: '1,234,567', leftName: 'Namename', rightName: 'Namename' },
|
||||
{ place: 2, score: '987,654', leftName: 'Namename', rightName: 'Namename' },
|
||||
{ place: 3, score: '876,543', leftName: 'Namename', rightName: 'Namename' },
|
||||
{
|
||||
place: 1,
|
||||
score: '1,234,567',
|
||||
leftName: 'Namename',
|
||||
rightName: 'Namename',
|
||||
},
|
||||
{
|
||||
place: 2,
|
||||
score: '987,654',
|
||||
leftName: 'Namename',
|
||||
rightName: 'Namename',
|
||||
},
|
||||
{
|
||||
place: 3,
|
||||
score: '876,543',
|
||||
leftName: 'Namename',
|
||||
rightName: 'Namename',
|
||||
},
|
||||
],
|
||||
rewards: [
|
||||
{
|
||||
@ -98,17 +118,31 @@
|
||||
|
||||
function resolveFallbackEndAt() {
|
||||
var params = new URLSearchParams(window.location.search || '');
|
||||
var explicitEnd = Date.parse(params.get('end_at') || params.get('endAt') || '');
|
||||
if (Number.isFinite(explicitEnd) && explicitEnd > Date.now()) return explicitEnd;
|
||||
var explicitEnd = Date.parse(
|
||||
params.get('end_at') || params.get('endAt') || ''
|
||||
);
|
||||
if (Number.isFinite(explicitEnd) && explicitEnd > Date.now())
|
||||
return explicitEnd;
|
||||
|
||||
try {
|
||||
var cached = Number(window.localStorage.getItem(STORAGE_KEY));
|
||||
if (Number.isFinite(cached) && cached > Date.now()) return cached;
|
||||
var fallback = Date.now() + 2 * 86400 * 1000 + 2 * 3600 * 1000 + 2 * 60 * 1000 + 2 * 1000;
|
||||
var fallback =
|
||||
Date.now() +
|
||||
2 * 86400 * 1000 +
|
||||
2 * 3600 * 1000 +
|
||||
2 * 60 * 1000 +
|
||||
2 * 1000;
|
||||
window.localStorage.setItem(STORAGE_KEY, String(fallback));
|
||||
return fallback;
|
||||
} catch (error) {
|
||||
return Date.now() + 2 * 86400 * 1000 + 2 * 3600 * 1000 + 2 * 60 * 1000 + 2 * 1000;
|
||||
return (
|
||||
Date.now() +
|
||||
2 * 86400 * 1000 +
|
||||
2 * 3600 * 1000 +
|
||||
2 * 60 * 1000 +
|
||||
2 * 1000
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,9 +160,11 @@
|
||||
function updateCountdown() {
|
||||
var parts = getTimeParts();
|
||||
Object.keys(parts).forEach(function (key) {
|
||||
document.querySelectorAll('[data-count="' + key + '"]').forEach(function (node) {
|
||||
node.textContent = twoDigits(parts[key]);
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-count="' + key + '"]')
|
||||
.forEach(function (node) {
|
||||
node.textContent = twoDigits(parts[key]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -152,23 +188,28 @@
|
||||
}
|
||||
|
||||
function renderCPRow(row) {
|
||||
var center = row.type === 'score'
|
||||
? [
|
||||
'<img class="score-heart" src="./assets/score-heart.png" alt="" aria-hidden="true" />',
|
||||
'<strong class="score-value">',
|
||||
escapeHTML(row.score),
|
||||
'</strong>',
|
||||
].join('')
|
||||
: [
|
||||
'<div class="gift-center">',
|
||||
'<img src="./assets/gift-plane.png" alt="" aria-hidden="true" />',
|
||||
'</div>',
|
||||
].join('');
|
||||
var center =
|
||||
row.type === 'score'
|
||||
? [
|
||||
'<img class="score-heart" src="./assets/score-heart.png" alt="" aria-hidden="true" />',
|
||||
'<strong class="score-value">',
|
||||
escapeHTML(row.score),
|
||||
'</strong>',
|
||||
].join('')
|
||||
: [
|
||||
'<div class="gift-center">',
|
||||
'<img src="./assets/gift-plane.png" alt="" aria-hidden="true" />',
|
||||
'</div>',
|
||||
].join('');
|
||||
|
||||
return [
|
||||
'<article class="cp-row">',
|
||||
'<div class="avatar avatar-left"><img src="./assets/avatar-sample.png" alt="" /></div>',
|
||||
'<div class="avatar avatar-right"><img src="./assets/avatar-sample.png" alt="" /></div>',
|
||||
'<div class="avatar avatar-left"><img src="',
|
||||
escapeHTML(row.leftAvatar || './assets/avatar-sample.png'),
|
||||
'" alt="" /></div>',
|
||||
'<div class="avatar avatar-right"><img src="',
|
||||
escapeHTML(row.rightAvatar || './assets/avatar-sample.png'),
|
||||
'" alt="" /></div>',
|
||||
'<span class="name name-left">',
|
||||
escapeHTML(row.leftName),
|
||||
'</span>',
|
||||
@ -185,10 +226,16 @@
|
||||
function renderPlaza() {
|
||||
var firstBody = [
|
||||
'<h2 class="panel-title">',
|
||||
t('cp.plazaGiftTitle', 'Gifts exchanged between CPs ≥ 5000 gold will be displayed here'),
|
||||
t(
|
||||
'cp.plazaGiftTitle',
|
||||
'Gifts exchanged between CPs ≥ 5000 gold will be displayed here'
|
||||
),
|
||||
'</h2>',
|
||||
'<p class="panel-subtitle">',
|
||||
t('cp.plazaGiftSubtitle', '(Display the last 10 records, sorted in ascending order.)'),
|
||||
t(
|
||||
'cp.plazaGiftSubtitle',
|
||||
'(Display the last 10 records, sorted in ascending order.)'
|
||||
),
|
||||
'</p>',
|
||||
'<div class="cp-list">',
|
||||
mockData.plaza.exchangeRows.map(renderCPRow).join(''),
|
||||
@ -199,7 +246,10 @@
|
||||
t('cp.previousNo1Title', 'The previous number one position'),
|
||||
'</h2>',
|
||||
'<p class="panel-subtitle">',
|
||||
t('cp.plazaGiftSubtitle', '(Display the last 10 records, sorted in ascending order.)'),
|
||||
t(
|
||||
'cp.plazaGiftSubtitle',
|
||||
'(Display the last 10 records, sorted in ascending order.)'
|
||||
),
|
||||
'</p>',
|
||||
'<div class="cp-list">',
|
||||
mockData.plaza.previousRows.map(renderCPRow).join(''),
|
||||
@ -241,7 +291,12 @@
|
||||
}
|
||||
|
||||
function renderPodiumCard(item) {
|
||||
var crown = item.place === 1 ? 'rank-crown-gold.png' : item.place === 2 ? 'rank-crown-silver.png' : 'crown-bronze.png';
|
||||
var crown =
|
||||
item.place === 1
|
||||
? 'rank-crown-gold.png'
|
||||
: item.place === 2
|
||||
? 'rank-crown-silver.png'
|
||||
: 'crown-bronze.png';
|
||||
return [
|
||||
'<article class="podium-card rank-',
|
||||
item.place,
|
||||
@ -250,8 +305,12 @@
|
||||
'<img class="podium-crown" src="./assets/',
|
||||
crown,
|
||||
'" alt="" aria-hidden="true" />',
|
||||
'<div class="avatar podium-avatar left"><img src="./assets/avatar-sample.png" alt="" /></div>',
|
||||
'<div class="avatar podium-avatar right"><img src="./assets/avatar-sample.png" alt="" /></div>',
|
||||
'<div class="avatar podium-avatar left"><img src="',
|
||||
escapeHTML(item.leftAvatar || './assets/avatar-sample.png'),
|
||||
'" alt="" /></div>',
|
||||
'<div class="avatar podium-avatar right"><img src="',
|
||||
escapeHTML(item.rightAvatar || './assets/avatar-sample.png'),
|
||||
'" alt="" /></div>',
|
||||
'<div class="podium-names"><span>',
|
||||
escapeHTML(item.leftName),
|
||||
'</span><span>',
|
||||
@ -271,29 +330,46 @@
|
||||
}
|
||||
|
||||
function renderRank() {
|
||||
var rankRows = activityData.rank || mockData.rank;
|
||||
var podium = [
|
||||
'<section class="rank-podium">',
|
||||
mockData.rank.map(renderPodiumCard).join(''),
|
||||
rankRows.slice(0, 3).map(renderPodiumCard).join(''),
|
||||
'</section>',
|
||||
].join('');
|
||||
var panelBody = [renderInlineCountdown(), '<div class="cp-list">', mockData.rank.concat(mockData.rank.slice(0, 1)).map(renderRankRow).join(''), '</div>'].join('');
|
||||
var panelRows = rankRows.length ? rankRows : mockData.rank;
|
||||
var panelBody = [
|
||||
renderInlineCountdown(),
|
||||
'<div class="cp-list">',
|
||||
panelRows.map(renderRankRow).join(''),
|
||||
'</div>',
|
||||
].join('');
|
||||
return podium + renderPanel('rank-panel', 2430, 1107, panelBody);
|
||||
}
|
||||
|
||||
function renderRewardItem(item) {
|
||||
var name = item.name || t(item.key, item.key);
|
||||
var note = item.note || (item.noteKey ? t(item.noteKey, '') : '');
|
||||
var cover = item.coverUrl || './assets/reward-frame.png';
|
||||
return [
|
||||
'<article class="reward-card">',
|
||||
'<div class="reward-icon-box"><img src="./assets/reward-frame.png" alt="" aria-hidden="true" /></div>',
|
||||
'<div class="reward-icon-box"><img src="',
|
||||
escapeHTML(cover),
|
||||
'" alt="" aria-hidden="true" /></div>',
|
||||
'<div class="reward-name">',
|
||||
t(item.key, item.key),
|
||||
escapeHTML(name),
|
||||
'</div>',
|
||||
item.noteKey ? '<div class="reward-note">' + t(item.noteKey, '') + '</div>' : '',
|
||||
note
|
||||
? '<div class="reward-note">' + escapeHTML(note) + '</div>'
|
||||
: '',
|
||||
'</article>',
|
||||
].join('');
|
||||
}
|
||||
|
||||
function renderRewardPanel(section, index) {
|
||||
var className = ['reward-panel', 'reward-' + ['a', 'b', 'c'][index]].join(' ');
|
||||
var className = [
|
||||
'reward-panel',
|
||||
'reward-' + ['a', 'b', 'c'][index],
|
||||
].join(' ');
|
||||
var top = [1816, 2784, 3752][index];
|
||||
var body = [
|
||||
'<img class="reward-crown" src="./assets/',
|
||||
@ -307,12 +383,95 @@
|
||||
}
|
||||
|
||||
function renderRewards() {
|
||||
return mockData.rewards.map(renderRewardPanel).join('');
|
||||
return (activityData.rewards || mockData.rewards)
|
||||
.map(renderRewardPanel)
|
||||
.join('');
|
||||
}
|
||||
|
||||
function formatScore(value) {
|
||||
var number = Number(value || 0);
|
||||
if (!Number.isFinite(number)) return '0';
|
||||
return number.toLocaleString('en-US');
|
||||
}
|
||||
|
||||
function normalizeUser(user) {
|
||||
return user || {};
|
||||
}
|
||||
|
||||
function normalizeRankEntry(entry) {
|
||||
var userA = normalizeUser(entry.user_a);
|
||||
var userB = normalizeUser(entry.user_b);
|
||||
return {
|
||||
place: Number(entry.rank || 0),
|
||||
score: formatScore(entry.score),
|
||||
leftName: userA.username || userA.display_user_id || 'Namename',
|
||||
rightName: userB.username || userB.display_user_id || 'Namename',
|
||||
leftAvatar: userA.avatar || '',
|
||||
rightAvatar: userB.avatar || '',
|
||||
};
|
||||
}
|
||||
|
||||
function rewardName(item) {
|
||||
var type = item.resource_type || 'reward';
|
||||
if (item.duration_days > 0)
|
||||
return type + ' ' + item.duration_days + 'D';
|
||||
if (item.quantity > 0) return type + ' x' + item.quantity;
|
||||
return type;
|
||||
}
|
||||
|
||||
function normalizeRewardSection(reward, index) {
|
||||
var crowns = ['crown-gold.png', 'crown-silver.png', 'crown-bronze.png'];
|
||||
return {
|
||||
crown: crowns[index] || 'crown-bronze.png',
|
||||
items: (reward.items || []).map(function (item) {
|
||||
return {
|
||||
name: rewardName(item),
|
||||
note:
|
||||
item.duration_days > 0
|
||||
? item.duration_days + ' days'
|
||||
: item.quantity > 0
|
||||
? 'x' + item.quantity
|
||||
: '',
|
||||
coverUrl: item.cover_url || '',
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function applyActivityStatus(status) {
|
||||
if (!status) return;
|
||||
if (status.period && status.period.end_ms > Date.now()) {
|
||||
activityData.periodEndMS = status.period.end_ms;
|
||||
countdownEndAt = status.period.end_ms;
|
||||
}
|
||||
if (Array.isArray(status.entries) && status.entries.length) {
|
||||
activityData.rank = status.entries.map(normalizeRankEntry);
|
||||
}
|
||||
if (Array.isArray(status.rewards) && status.rewards.length) {
|
||||
activityData.rewards = status.rewards.map(normalizeRewardSection);
|
||||
}
|
||||
}
|
||||
|
||||
function loadActivityStatus() {
|
||||
if (!window.HyAppAPI || !window.HyAppAPI.cpWeeklyRank) return;
|
||||
// 周榜配置和奖励由后端控制;H5 只在接口成功时替换展示数据,失败保持静态兜底,避免活动页因为鉴权或网络问题白屏。
|
||||
window.HyAppAPI.cpWeeklyRank
|
||||
.status({ limit: 10 })
|
||||
.then(function (status) {
|
||||
applyActivityStatus(status);
|
||||
render();
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function render() {
|
||||
document.title = t('cp.pageTitle', 'Last Weekly CP');
|
||||
tabContent.innerHTML = activeTab === 'rank' ? renderRank() : activeTab === 'rewards' ? renderRewards() : renderPlaza();
|
||||
tabContent.innerHTML =
|
||||
activeTab === 'rank'
|
||||
? renderRank()
|
||||
: activeTab === 'rewards'
|
||||
? renderRewards()
|
||||
: renderPlaza();
|
||||
applyTabState();
|
||||
updateStageHeight();
|
||||
updateCountdown();
|
||||
@ -322,7 +481,9 @@
|
||||
tabs.forEach(function (tab) {
|
||||
var isActive = tab.getAttribute('data-tab') === activeTab;
|
||||
tab.classList.toggle('is-active', isActive);
|
||||
tab.querySelector('img').src = isActive ? './assets/tab-active.png' : './assets/tab-inactive.png';
|
||||
tab.querySelector('img').src = isActive
|
||||
? './assets/tab-active.png'
|
||||
: './assets/tab-inactive.png';
|
||||
});
|
||||
page.setAttribute('data-tab', activeTab);
|
||||
}
|
||||
@ -331,11 +492,16 @@
|
||||
var designHeight = stageHeights[activeTab] || stageHeights.plaza;
|
||||
stage.style.minHeight = designHeight + 'px';
|
||||
stage.style.height = designHeight + 'px';
|
||||
stageWrap.style.height = Math.ceil(designHeight * (VIEWPORT_WIDTH / DESIGN_WIDTH)) + 'px';
|
||||
stageWrap.style.height =
|
||||
Math.ceil(designHeight * (VIEWPORT_WIDTH / DESIGN_WIDTH)) + 'px';
|
||||
copyright.style.top = designHeight - 77 + 'px';
|
||||
var scale = Math.min(window.innerWidth / VIEWPORT_WIDTH, 1);
|
||||
document.documentElement.style.setProperty('--app-scale', String(scale));
|
||||
document.body.style.minHeight = Math.ceil(stageWrap.offsetHeight * scale) + 'px';
|
||||
document.documentElement.style.setProperty(
|
||||
'--app-scale',
|
||||
String(scale)
|
||||
);
|
||||
document.body.style.minHeight =
|
||||
Math.ceil(stageWrap.offsetHeight * scale) + 'px';
|
||||
viewport.style.minHeight = stageWrap.style.height;
|
||||
page.style.minHeight = stageWrap.style.height;
|
||||
}
|
||||
@ -353,6 +519,7 @@
|
||||
countdownEndAt = resolveFallbackEndAt();
|
||||
bindTabs();
|
||||
render();
|
||||
loadActivityStatus();
|
||||
countdownTimer = window.setInterval(updateCountdown, 1000);
|
||||
window.addEventListener('resize', updateStageHeight);
|
||||
window.addEventListener('hyapp:i18n-ready', render);
|
||||
|
||||
@ -19,15 +19,11 @@ body {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
background: #1d080d;
|
||||
background: var(--cp-red);
|
||||
color: #fff;
|
||||
font-family:
|
||||
"Source Han Sans SC",
|
||||
"Noto Sans CJK SC",
|
||||
Arial,
|
||||
"Helvetica Neue",
|
||||
Helvetica,
|
||||
sans-serif;
|
||||
'Source Han Sans SC', 'Noto Sans CJK SC', Arial, 'Helvetica Neue',
|
||||
Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
@ -54,7 +50,7 @@ button {
|
||||
width: 375px;
|
||||
min-height: 1300px;
|
||||
overflow: hidden;
|
||||
background: #1d080d;
|
||||
background: var(--cp-red);
|
||||
}
|
||||
|
||||
.stage-wrap {
|
||||
@ -89,6 +85,8 @@ button {
|
||||
height: 1919px;
|
||||
object-fit: cover;
|
||||
pointer-events: none;
|
||||
transform: scale(1.04);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.language-switcher {
|
||||
@ -290,7 +288,12 @@ button {
|
||||
border: 8px solid #f62658;
|
||||
border-radius: 48px;
|
||||
background:
|
||||
radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.98) 0, rgba(255, 255, 255, 0.86) 23%, rgba(255, 232, 236, 0.92) 100%),
|
||||
radial-gradient(
|
||||
circle at 50% 0%,
|
||||
rgba(255, 255, 255, 0.98) 0,
|
||||
rgba(255, 255, 255, 0.86) 23%,
|
||||
rgba(255, 232, 236, 0.92) 100%
|
||||
),
|
||||
linear-gradient(180deg, #fff8f8 0%, #ffe6eb 100%);
|
||||
box-shadow:
|
||||
inset 0 0 0 4px rgba(255, 204, 119, 0.95),
|
||||
@ -303,7 +306,7 @@ button {
|
||||
|
||||
.ornate-panel::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@ -313,7 +316,12 @@ button {
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
height: 14px;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 241, 177, 0.95), transparent);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 241, 177, 0.95),
|
||||
transparent
|
||||
);
|
||||
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.8));
|
||||
}
|
||||
|
||||
@ -336,7 +344,7 @@ button {
|
||||
.panel-mid {
|
||||
top: 89px;
|
||||
bottom: 85px;
|
||||
background-image: url("./assets/panel-mid.png");
|
||||
background-image: url('./assets/panel-mid.png');
|
||||
background-size: 960px 184px;
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
@ -693,15 +701,15 @@ button {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .tab span,
|
||||
html[dir="rtl"] .panel-title,
|
||||
html[dir="rtl"] .panel-subtitle,
|
||||
html[dir="rtl"] .copyright,
|
||||
html[dir="rtl"] .reward-name,
|
||||
html[dir="rtl"] .reward-note {
|
||||
html[dir='rtl'] .tab span,
|
||||
html[dir='rtl'] .panel-title,
|
||||
html[dir='rtl'] .panel-subtitle,
|
||||
html[dir='rtl'] .copyright,
|
||||
html[dir='rtl'] .reward-name,
|
||||
html[dir='rtl'] .reward-note {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .language-switcher {
|
||||
html[dir='rtl'] .language-switcher {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
@ -747,6 +747,15 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
},
|
||||
};
|
||||
|
||||
var cpWeeklyRankAPI = {
|
||||
status: function (params) {
|
||||
return request('/api/v1/activities/cp-weekly-rank', {
|
||||
method: 'GET',
|
||||
query: params || {},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// 邀请活动 H5 只关心当前用户本月状态和领取动作;有效人数、累计充值和最高档差额都以后端聚合事实为准。
|
||||
// 领取时页面必须传入本次点击生成的 command_id,服务端按用户、周期、档位和 command_id 做幂等发奖。
|
||||
var inviteActivityRewardAPI = {
|
||||
@ -932,6 +941,7 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
level: levelAPI,
|
||||
task: taskAPI,
|
||||
weeklyStar: weeklyStarAPI,
|
||||
cpWeeklyRank: cpWeeklyRankAPI,
|
||||
inviteActivityReward: inviteActivityRewardAPI,
|
||||
game: gameAPI,
|
||||
};
|
||||
|
||||
@ -494,6 +494,7 @@
|
||||
"recharge.orderStatus": "الحالة",
|
||||
"recharge.payRedirecting": "جار فتح صفحة الدفع...",
|
||||
"recharge.payOpenHint": "افتح صفحة الدفع وأكمل الدفع.",
|
||||
"recharge.confirmingPayment": "جار تأكيد حالة الدفع...",
|
||||
"recharge.openPayment": "فتح الدفع",
|
||||
"recharge.usdtPayment": "دفع USDT",
|
||||
"recharge.usdtAddress": "عنوان USDT-TRC20",
|
||||
|
||||
@ -500,6 +500,7 @@
|
||||
"recharge.orderStatus": "Status",
|
||||
"recharge.payRedirecting": "Opening payment page...",
|
||||
"recharge.payOpenHint": "Open the payment page and finish the payment.",
|
||||
"recharge.confirmingPayment": "Confirming payment status...",
|
||||
"recharge.openPayment": "Open payment",
|
||||
"recharge.usdtPayment": "USDT payment",
|
||||
"recharge.usdtAddress": "USDT-TRC20 address",
|
||||
|
||||
@ -494,6 +494,7 @@
|
||||
"recharge.orderStatus": "Estado",
|
||||
"recharge.payRedirecting": "Abriendo página de pago...",
|
||||
"recharge.payOpenHint": "Abre la página de pago y completa el pago.",
|
||||
"recharge.confirmingPayment": "Confirmando el estado del pago...",
|
||||
"recharge.openPayment": "Abrir pago",
|
||||
"recharge.usdtPayment": "Pago USDT",
|
||||
"recharge.usdtAddress": "Dirección USDT-TRC20",
|
||||
|
||||
@ -461,6 +461,7 @@
|
||||
"recharge.orderStatus": "Status",
|
||||
"recharge.payRedirecting": "Membuka halaman pembayaran...",
|
||||
"recharge.payOpenHint": "Buka halaman pembayaran dan selesaikan pembayaran.",
|
||||
"recharge.confirmingPayment": "Mengonfirmasi status pembayaran...",
|
||||
"recharge.openPayment": "Buka pembayaran",
|
||||
"recharge.usdtPayment": "Pembayaran USDT",
|
||||
"recharge.usdtAddress": "Alamat USDT-TRC20",
|
||||
|
||||
@ -461,6 +461,7 @@
|
||||
"recharge.orderStatus": "Durum",
|
||||
"recharge.payRedirecting": "Ödeme sayfası açılıyor...",
|
||||
"recharge.payOpenHint": "Ödeme sayfasını açın ve ödemeyi tamamlayın.",
|
||||
"recharge.confirmingPayment": "Ödeme durumu doğrulanıyor...",
|
||||
"recharge.openPayment": "Ödemeyi aç",
|
||||
"recharge.usdtPayment": "USDT ödeme",
|
||||
"recharge.usdtAddress": "USDT-TRC20 adresi",
|
||||
|
||||
@ -467,6 +467,7 @@
|
||||
"recharge.orderStatus": "状态",
|
||||
"recharge.payRedirecting": "正在打开支付页面...",
|
||||
"recharge.payOpenHint": "打开支付页面并完成付款。",
|
||||
"recharge.confirmingPayment": "正在确认支付状态...",
|
||||
"recharge.openPayment": "打开支付",
|
||||
"recharge.usdtPayment": "USDT 支付",
|
||||
"recharge.usdtAddress": "USDT-TRC20 收款地址",
|
||||
|
||||
@ -1032,6 +1032,7 @@
|
||||
(function () {
|
||||
var PENDING_MIFAPAY_ORDER_KEY =
|
||||
'hyapp_recharge_pending_mifapay_order';
|
||||
var RETURN_MIFAPAY_ORDER_QUERY_KEY = 'hyapp_order_id';
|
||||
var PENDING_MIFAPAY_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
||||
var state = {
|
||||
context: null,
|
||||
@ -1043,6 +1044,8 @@
|
||||
pollingTimer: 0,
|
||||
loading: false,
|
||||
orderNoticeKey: '',
|
||||
confirmingMifaPay: false,
|
||||
lastMifaPayResumeAtMS: 0,
|
||||
};
|
||||
|
||||
var nodes = {};
|
||||
@ -1111,8 +1114,8 @@
|
||||
bindEvents();
|
||||
var current = window.HyAppParams
|
||||
? window.HyAppParams.parse()
|
||||
: { raw: new URLSearchParams(window.location.search) };
|
||||
var raw = current.raw || new URLSearchParams();
|
||||
: { raw: currentRawParams() };
|
||||
var raw = current.raw || currentRawParams();
|
||||
var pendingOrder = readPendingMifaPayOrder();
|
||||
var displayUserID =
|
||||
raw.get('display_user_id') ||
|
||||
@ -1153,6 +1156,12 @@
|
||||
nodes.copyAddress.addEventListener('click', copyAddress);
|
||||
nodes.copyOrderID.addEventListener('click', copyOrderID);
|
||||
nodes.txForm.addEventListener('submit', submitTx);
|
||||
window.addEventListener('pageshow', resumeMifaPayOrder);
|
||||
window.addEventListener('focus', resumeMifaPayOrder);
|
||||
document.addEventListener(
|
||||
'visibilitychange',
|
||||
resumeVisibleMifaPayOrder
|
||||
);
|
||||
window.addEventListener('hyapp:i18n-ready', function () {
|
||||
document.title = t(
|
||||
'recharge.pageTitle',
|
||||
@ -1405,8 +1414,8 @@
|
||||
state.loading || !state.selectedMethodKey;
|
||||
}
|
||||
|
||||
// 订单弹窗是支付后的唯一操作入口;MiFaPay 展示打开支付按钮,USDT 展示地址和 txid 表单。
|
||||
// 弹窗关闭只影响展示,不会取消轮询;订单终态仍由服务端查询结果驱动。
|
||||
// 订单弹窗是支付中的操作入口;终态由服务端查询结果驱动,成功后关闭弹窗,避免继续展示打开支付按钮。
|
||||
// 失败仍保留弹窗展示失败原因,方便用户看到三方拒单或本地校验失败的信息。
|
||||
function renderOrder() {
|
||||
var order = state.order;
|
||||
nodes.orderModal.classList.toggle(
|
||||
@ -1426,7 +1435,9 @@
|
||||
nodes.usdtPanel.classList.toggle('hidden', !isUSDT);
|
||||
nodes.mifapayPanel.classList.toggle(
|
||||
'hidden',
|
||||
order.provider_code !== 'mifapay' || !order.pay_url
|
||||
order.provider_code !== 'mifapay' ||
|
||||
!order.pay_url ||
|
||||
isTerminalOrder(order)
|
||||
);
|
||||
if (order.provider_code === 'usdt_trc20') {
|
||||
nodes.receiveAddress.textContent =
|
||||
@ -1449,10 +1460,15 @@
|
||||
} else if (order.provider_code === 'mifapay') {
|
||||
setStatus(
|
||||
nodes.orderMessage,
|
||||
t(
|
||||
'recharge.payOpenHint',
|
||||
'Open the payment page and finish the payment.'
|
||||
)
|
||||
state.confirmingMifaPay
|
||||
? t(
|
||||
'recharge.confirmingPayment',
|
||||
'Confirming payment status...'
|
||||
)
|
||||
: t(
|
||||
'recharge.payOpenHint',
|
||||
'Open the payment page and finish the payment.'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
setStatus(nodes.orderMessage, '');
|
||||
@ -1546,16 +1562,13 @@
|
||||
provider_code: method.providerCode,
|
||||
payment_method_id: method.methodID || 0,
|
||||
command_id: commandID(product, method),
|
||||
return_url: window.location.href,
|
||||
return_url: mifaPayReturnURL(),
|
||||
})
|
||||
.then(function (payload) {
|
||||
state.order = payload.order || payload;
|
||||
state.orderModalOpen = true;
|
||||
renderOrder();
|
||||
if (
|
||||
state.order.status === 'credited' ||
|
||||
state.order.status === 'failed'
|
||||
) {
|
||||
if (isTerminalOrder(state.order)) {
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
return;
|
||||
}
|
||||
@ -1629,36 +1642,58 @@
|
||||
}
|
||||
|
||||
// 轮询只在订单存在时启动;credited/failed 是终态,终态后停止,避免 H5 后台持续打接口。
|
||||
// 返回 H5 后必须立即查一次,不再等第一个 5 秒周期,否则用户会看到“已返回但无反馈”。
|
||||
function startPolling() {
|
||||
window.clearInterval(state.pollingTimer);
|
||||
if (!state.order || !state.order.order_id) return;
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
if (isTerminalOrder(state.order)) {
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
return;
|
||||
}
|
||||
refreshOrderStatus();
|
||||
state.pollingTimer = window.setInterval(function () {
|
||||
if (
|
||||
!state.order ||
|
||||
state.order.status === 'credited' ||
|
||||
state.order.status === 'failed'
|
||||
) {
|
||||
if (!state.order || isTerminalOrder(state.order)) {
|
||||
window.clearInterval(state.pollingTimer);
|
||||
return;
|
||||
}
|
||||
window.HyAppAPI.recharge
|
||||
.getOrder(
|
||||
state.order.order_id,
|
||||
targetDisplayUserID()
|
||||
)
|
||||
.then(function (payload) {
|
||||
state.order = payload.order || payload;
|
||||
renderOrder();
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
})
|
||||
.catch(function () {});
|
||||
refreshOrderStatus();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function refreshOrderStatus() {
|
||||
if (!state.order || !state.order.order_id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (isTerminalOrder(state.order)) {
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
return Promise.resolve(state.order);
|
||||
}
|
||||
if (state.order.provider_code === 'mifapay') {
|
||||
state.confirmingMifaPay = true;
|
||||
state.orderModalOpen = true;
|
||||
renderOrder();
|
||||
}
|
||||
return window.HyAppAPI.recharge
|
||||
.getOrder(state.order.order_id, targetDisplayUserID())
|
||||
.then(function (payload) {
|
||||
state.order = payload.order || payload;
|
||||
renderOrder();
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
return state.order;
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function restorePendingMifaPayOrder() {
|
||||
var pending = readPendingMifaPayOrder();
|
||||
if (!pending || state.order) return;
|
||||
if (!pending) return;
|
||||
if (
|
||||
state.order &&
|
||||
state.order.order_id &&
|
||||
state.order.order_id !== pending.order_id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
var accountDisplayUserID = currentAccountDisplayUserID();
|
||||
if (
|
||||
pending.display_user_id &&
|
||||
@ -1667,6 +1702,17 @@
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
state.order &&
|
||||
state.order.order_id === pending.order_id
|
||||
) {
|
||||
state.confirmingMifaPay = true;
|
||||
state.orderModalOpen = true;
|
||||
renderOrder();
|
||||
startPolling();
|
||||
return;
|
||||
}
|
||||
state.confirmingMifaPay = true;
|
||||
window.HyAppAPI.recharge
|
||||
.getOrder(
|
||||
pending.order_id,
|
||||
@ -1677,10 +1723,7 @@
|
||||
state.orderModalOpen = true;
|
||||
renderOrder();
|
||||
applyOrderTerminalSideEffects(state.order);
|
||||
if (
|
||||
state.order.status !== 'credited' &&
|
||||
state.order.status !== 'failed'
|
||||
) {
|
||||
if (!isTerminalOrder(state.order)) {
|
||||
startPolling();
|
||||
}
|
||||
})
|
||||
@ -1689,16 +1732,48 @@
|
||||
});
|
||||
}
|
||||
|
||||
function applyOrderTerminalSideEffects(order) {
|
||||
function resumeVisibleMifaPayOrder() {
|
||||
if (
|
||||
!order ||
|
||||
(order.status !== 'credited' &&
|
||||
order.status !== 'failed')
|
||||
document.visibilityState &&
|
||||
document.visibilityState !== 'visible'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
resumeMifaPayOrder();
|
||||
}
|
||||
|
||||
function resumeMifaPayOrder() {
|
||||
if (!state.context) return;
|
||||
if (Date.now() - state.lastMifaPayResumeAtMS < 800) {
|
||||
return;
|
||||
}
|
||||
state.lastMifaPayResumeAtMS = Date.now();
|
||||
if (
|
||||
state.order &&
|
||||
state.order.provider_code === 'mifapay' &&
|
||||
!isTerminalOrder(state.order)
|
||||
) {
|
||||
state.confirmingMifaPay = true;
|
||||
state.orderModalOpen = true;
|
||||
renderOrder();
|
||||
startPolling();
|
||||
return;
|
||||
}
|
||||
restorePendingMifaPayOrder();
|
||||
}
|
||||
|
||||
function applyOrderTerminalSideEffects(order) {
|
||||
if (!isTerminalOrder(order)) {
|
||||
return;
|
||||
}
|
||||
state.confirmingMifaPay = false;
|
||||
clearPendingMifaPayOrder(order.order_id);
|
||||
clearReturnedMifaPayOrderQuery();
|
||||
window.clearInterval(state.pollingTimer);
|
||||
if (order.status === 'credited') {
|
||||
state.orderModalOpen = false;
|
||||
renderOrder();
|
||||
}
|
||||
var noticeKey = order.order_id + ':' + order.status;
|
||||
if (state.orderNoticeKey === noticeKey) return;
|
||||
state.orderNoticeKey = noticeKey;
|
||||
@ -1725,6 +1800,8 @@
|
||||
}
|
||||
|
||||
function readPendingMifaPayOrder() {
|
||||
var returned = readReturnedMifaPayOrder();
|
||||
if (returned) return returned;
|
||||
try {
|
||||
var raw = storageGet(PENDING_MIFAPAY_ORDER_KEY);
|
||||
if (!raw) return null;
|
||||
@ -1745,6 +1822,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
function readReturnedMifaPayOrder() {
|
||||
var raw = currentRawParams();
|
||||
var orderID = String(
|
||||
raw.get(RETURN_MIFAPAY_ORDER_QUERY_KEY) || ''
|
||||
).trim();
|
||||
if (!orderID) return null;
|
||||
return {
|
||||
order_id: orderID,
|
||||
display_user_id:
|
||||
raw.get('display_user_id') ||
|
||||
currentAccountDisplayUserID(),
|
||||
created_at_ms: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function clearPendingMifaPayOrder(orderID) {
|
||||
var pending = null;
|
||||
try {
|
||||
@ -1764,6 +1856,60 @@
|
||||
}
|
||||
}
|
||||
|
||||
function clearReturnedMifaPayOrderQuery() {
|
||||
try {
|
||||
var url = new URL(window.location.href);
|
||||
var changed = false;
|
||||
if (
|
||||
url.searchParams.has(RETURN_MIFAPAY_ORDER_QUERY_KEY)
|
||||
) {
|
||||
url.searchParams.delete(
|
||||
RETURN_MIFAPAY_ORDER_QUERY_KEY
|
||||
);
|
||||
changed = true;
|
||||
}
|
||||
var hash = url.hash || '';
|
||||
var hashQueryIndex = hash.indexOf('?');
|
||||
if (hashQueryIndex >= 0) {
|
||||
var hashPath = hash.slice(0, hashQueryIndex);
|
||||
var hashParams = new URLSearchParams(
|
||||
hash.slice(hashQueryIndex + 1)
|
||||
);
|
||||
if (
|
||||
hashParams.has(RETURN_MIFAPAY_ORDER_QUERY_KEY)
|
||||
) {
|
||||
hashParams.delete(
|
||||
RETURN_MIFAPAY_ORDER_QUERY_KEY
|
||||
);
|
||||
url.hash = hashParams.toString()
|
||||
? hashPath + '?' + hashParams.toString()
|
||||
: hashPath;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
window.HyAppParams &&
|
||||
window.HyAppParams.current &&
|
||||
window.HyAppParams.current.raw
|
||||
) {
|
||||
window.HyAppParams.current.raw.delete(
|
||||
RETURN_MIFAPAY_ORDER_QUERY_KEY
|
||||
);
|
||||
}
|
||||
if (
|
||||
changed &&
|
||||
window.history &&
|
||||
window.history.replaceState
|
||||
) {
|
||||
window.history.replaceState(
|
||||
window.history.state,
|
||||
document.title,
|
||||
url.toString()
|
||||
);
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
function storageGet(key) {
|
||||
try {
|
||||
return window.localStorage
|
||||
@ -1869,6 +2015,83 @@
|
||||
: '';
|
||||
}
|
||||
|
||||
function isTerminalOrder(order) {
|
||||
return (
|
||||
!!order &&
|
||||
(order.status === 'credited' ||
|
||||
order.status === 'failed')
|
||||
);
|
||||
}
|
||||
|
||||
function mifaPayReturnURL() {
|
||||
try {
|
||||
var url = new URL(window.location.href);
|
||||
var displayUserID =
|
||||
targetDisplayUserID() ||
|
||||
String(nodes.displayUserID.value || '').trim();
|
||||
if (displayUserID) {
|
||||
url.searchParams.set(
|
||||
'display_user_id',
|
||||
displayUserID
|
||||
);
|
||||
}
|
||||
if (window.HyAppAPI && window.HyAppAPI.getAppCode) {
|
||||
url.searchParams.set(
|
||||
'app_code',
|
||||
window.HyAppAPI.getAppCode()
|
||||
);
|
||||
}
|
||||
url.searchParams.set(
|
||||
'language',
|
||||
currentLanguageForReturnURL()
|
||||
);
|
||||
url.searchParams.delete(RETURN_MIFAPAY_ORDER_QUERY_KEY);
|
||||
return url.toString();
|
||||
} catch (error) {
|
||||
return window.location.href;
|
||||
}
|
||||
}
|
||||
|
||||
function currentLanguageForReturnURL() {
|
||||
var raw = currentRawParams();
|
||||
var keys = [
|
||||
'language',
|
||||
'lang',
|
||||
'locale',
|
||||
'app_lang',
|
||||
'appLanguage',
|
||||
];
|
||||
for (var i = 0; i < keys.length; i += 1) {
|
||||
var value = raw.get(keys[i]);
|
||||
if (value) return value;
|
||||
}
|
||||
return document.documentElement.lang || 'en';
|
||||
}
|
||||
|
||||
function currentRawParams() {
|
||||
if (
|
||||
window.HyAppParams &&
|
||||
window.HyAppParams.current &&
|
||||
window.HyAppParams.current.raw
|
||||
) {
|
||||
return window.HyAppParams.current.raw;
|
||||
}
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var hash = window.location.hash || '';
|
||||
var hashQueryIndex = hash.indexOf('?');
|
||||
if (hashQueryIndex >= 0) {
|
||||
var hashParams = new URLSearchParams(
|
||||
hash.slice(hashQueryIndex + 1)
|
||||
);
|
||||
hashParams.forEach(function (value, key) {
|
||||
if (!params.has(key)) {
|
||||
params.set(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
// command_id 给服务端幂等使用,包含时间、商品、方式和随机后缀;真实订单号仍由后端生成。
|
||||
// 三方拒单会把本地订单置失败,后续重用同一 command_id 只会回放旧失败结果,所以每次点击都必须生成新命令。
|
||||
function commandID(product, method) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user