子币商以及aslan充值活动
This commit is contained in:
parent
939acdfc31
commit
f776b87a01
@ -204,7 +204,7 @@
|
|||||||
<script src="../../common/api.js?v=20260708-yumi-layered"></script>
|
<script src="../../common/api.js?v=20260708-yumi-layered"></script>
|
||||||
<script src="../../common/jsbridge.js?v=20260708-yumi-layered"></script>
|
<script src="../../common/jsbridge.js?v=20260708-yumi-layered"></script>
|
||||||
<script src="../../common/toast.js?v=20260708-yumi-layered"></script>
|
<script src="../../common/toast.js?v=20260708-yumi-layered"></script>
|
||||||
<script src="../../yumi_commmon/yumi-common.js?v=20260708-yumi-api"></script>
|
<script src="../../common_yumi/yumi-common.js?v=20260708-yumi-api"></script>
|
||||||
<script src="./yumi.js?v=20260708-yumi-api"></script>
|
<script src="./yumi.js?v=20260708-yumi-api"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -7,8 +7,8 @@
|
|||||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
||||||
/>
|
/>
|
||||||
<title>Recharge Reward</title>
|
<title>Recharge Reward</title>
|
||||||
<link rel="stylesheet" href="../common/theme.css?v=20260707" />
|
<link rel="stylesheet" href="../../common/theme.css?v=20260709" />
|
||||||
<link rel="stylesheet" href="./style.css?v=20260707-modules" />
|
<link rel="stylesheet" href="./style.css?v=20260709-api" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="app-viewport" id="appViewport">
|
<div class="app-viewport" id="appViewport">
|
||||||
@ -18,7 +18,11 @@
|
|||||||
aria-label="Recharge Reward activity"
|
aria-label="Recharge Reward activity"
|
||||||
data-i18n-aria="rechargeReward.pageLabel"
|
data-i18n-aria="rechargeReward.pageLabel"
|
||||||
>
|
>
|
||||||
<img class="bg bg-top" src="./assets/recharge-activity/bg-top.png" alt="" />
|
<img
|
||||||
|
class="bg bg-top"
|
||||||
|
src="./assets/recharge-activity/bg-top.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
<img
|
<img
|
||||||
class="bg bg-mid bg-mid-a"
|
class="bg bg-mid bg-mid-a"
|
||||||
src="./assets/recharge-activity/bg-mid-a.png"
|
src="./assets/recharge-activity/bg-mid-a.png"
|
||||||
@ -56,17 +60,44 @@
|
|||||||
src="./assets/recharge-activity/countdown-frame.png"
|
src="./assets/recharge-activity/countdown-frame.png"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<strong class="count-number" data-count="days">01</strong>
|
<strong class="count-number" data-count="days"
|
||||||
<strong class="count-number" data-count="hours">01</strong>
|
>01</strong
|
||||||
<strong class="count-number" data-count="minutes">01</strong>
|
>
|
||||||
<strong class="count-number" data-count="seconds">01</strong>
|
<strong class="count-number" data-count="hours"
|
||||||
<span class="count-label" data-i18n="rechargeReward.days">Days</span>
|
>01</strong
|
||||||
<span class="count-label" data-i18n="rechargeReward.hours">Hours</span>
|
>
|
||||||
<span class="count-label" data-i18n="rechargeReward.minutes">Minutes</span>
|
<strong class="count-number" data-count="minutes"
|
||||||
<span class="count-label" data-i18n="rechargeReward.seconds">Seconds</span>
|
>01</strong
|
||||||
|
>
|
||||||
|
<strong class="count-number" data-count="seconds"
|
||||||
|
>01</strong
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="count-label"
|
||||||
|
data-i18n="rechargeReward.days"
|
||||||
|
>Days</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="count-label"
|
||||||
|
data-i18n="rechargeReward.hours"
|
||||||
|
>Hours</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="count-label"
|
||||||
|
data-i18n="rechargeReward.minutes"
|
||||||
|
>Minutes</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="count-label"
|
||||||
|
data-i18n="rechargeReward.seconds"
|
||||||
|
>Seconds</span
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="profile-card" aria-label="My recharge status">
|
<section
|
||||||
|
class="profile-card"
|
||||||
|
aria-label="My recharge status"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
class="profile-frame"
|
class="profile-frame"
|
||||||
src="./assets/recharge-activity/profile-frame.png"
|
src="./assets/recharge-activity/profile-frame.png"
|
||||||
@ -78,7 +109,9 @@
|
|||||||
alt=""
|
alt=""
|
||||||
data-profile-avatar
|
data-profile-avatar
|
||||||
/>
|
/>
|
||||||
<h1 class="profile-name" data-profile-name>nanfangjian</h1>
|
<h1 class="profile-name" data-profile-name>
|
||||||
|
nanfangjian
|
||||||
|
</h1>
|
||||||
<p class="profile-id" data-profile-id>ID: 12345678</p>
|
<p class="profile-id" data-profile-id>ID: 12345678</p>
|
||||||
<p class="profile-recharge" data-profile-recharge>
|
<p class="profile-recharge" data-profile-recharge>
|
||||||
Accumlated Recharge:5998
|
Accumlated Recharge:5998
|
||||||
@ -92,7 +125,9 @@
|
|||||||
<script>
|
<script>
|
||||||
document.documentElement.dataset.hyAppCode = 'aslan';
|
document.documentElement.dataset.hyAppCode = 'aslan';
|
||||||
</script>
|
</script>
|
||||||
<script src="../common/i18n.js?v=20260707"></script>
|
<script src="../../common/i18n.js?v=20260709"></script>
|
||||||
<script src="./script.js?v=20260707-modules"></script>
|
<script src="../../common/toast.js?v=20260709"></script>
|
||||||
|
<script src="../../common_aslan/aslan-common.js?v=20260709"></script>
|
||||||
|
<script src="./script.js?v=20260709-api"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var ASSET_BASE = './assets/recharge-activity/';
|
var ASSET_BASE = './assets/recharge-activity/';
|
||||||
var viewport = document.getElementById('appViewport');
|
var viewport = document.getElementById('appViewport');
|
||||||
|
var page = document.getElementById('page');
|
||||||
|
var stage = document.querySelector('.stage');
|
||||||
var rewardSections = document.getElementById('rewardSections');
|
var rewardSections = document.getElementById('rewardSections');
|
||||||
|
var bgBottom = document.querySelector('.bg-bottom');
|
||||||
var countNodes = {
|
var countNodes = {
|
||||||
days: document.querySelector('[data-count="days"]'),
|
days: document.querySelector('[data-count="days"]'),
|
||||||
hours: document.querySelector('[data-count="hours"]'),
|
hours: document.querySelector('[data-count="hours"]'),
|
||||||
@ -10,40 +13,37 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var DESIGN_WIDTH = 1080;
|
var DESIGN_WIDTH = 1080;
|
||||||
var DESIGN_HEIGHT = 3273;
|
|
||||||
var VIEWPORT_WIDTH = 375;
|
var VIEWPORT_WIDTH = 375;
|
||||||
|
var DEFAULT_DESIGN_HEIGHT = 3273;
|
||||||
|
var designHeight = DEFAULT_DESIGN_HEIGHT;
|
||||||
var countdownEndAt = resolveCountdownEndAt();
|
var countdownEndAt = resolveCountdownEndAt();
|
||||||
var activityData = {
|
var countdownTimer = 0;
|
||||||
|
var state = {
|
||||||
user: {
|
user: {
|
||||||
name: 'nanfangjian',
|
name: '',
|
||||||
id: '12345678',
|
id: '',
|
||||||
avatar: ASSET_BASE + 'profile-avatar.png',
|
avatar: ASSET_BASE + 'profile-avatar.png',
|
||||||
accumulatedRecharge: '5998',
|
accumulatedRecharge: 0,
|
||||||
},
|
},
|
||||||
rewards: [
|
rewards: [],
|
||||||
{
|
claiming: {},
|
||||||
amount: '$100',
|
loading: true,
|
||||||
top: 1776,
|
error: '',
|
||||||
background: ASSET_BASE + 'reward-section-a.png',
|
|
||||||
claim: { text: 'Receive', claimable: true, claimed: false },
|
|
||||||
cards: [
|
|
||||||
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 111, top: 293 },
|
|
||||||
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 560, top: 293 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
amount: '$100',
|
|
||||||
top: 2466,
|
|
||||||
background: ASSET_BASE + 'reward-section-b.png',
|
|
||||||
claim: { text: 'Receive', claimable: true, claimed: false },
|
|
||||||
cards: [
|
|
||||||
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 70.5, top: 278 },
|
|
||||||
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 339.5, top: 278 },
|
|
||||||
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 608.5, top: 278 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
var fallbackCards = [
|
||||||
|
{
|
||||||
|
price: '$100',
|
||||||
|
icon: ASSET_BASE + 'reward-icon.png',
|
||||||
|
left: 111,
|
||||||
|
top: 293,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: '$100',
|
||||||
|
icon: ASSET_BASE + 'reward-icon.png',
|
||||||
|
left: 560,
|
||||||
|
top: 293,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
function getParams() {
|
function getParams() {
|
||||||
return new URLSearchParams(window.location.search || '');
|
return new URLSearchParams(window.location.search || '');
|
||||||
@ -68,25 +68,78 @@
|
|||||||
return String(Math.max(0, value)).padStart(2, '0');
|
return String(Math.max(0, value)).padStart(2, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showToast(message) {
|
||||||
|
if (window.HyAppToast && window.HyAppToast.show) {
|
||||||
|
window.HyAppToast.show(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent('hyapp:toast', { detail: { message: message } })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function numeric(value, fallback) {
|
||||||
|
var number = Number(value);
|
||||||
|
return Number.isFinite(number) ? number : fallback || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseJSON(value) {
|
||||||
|
if (!value || typeof value !== 'string') return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstValue() {
|
||||||
|
for (var i = 0; i < arguments.length; i += 1) {
|
||||||
|
var value = arguments[i];
|
||||||
|
if (value !== undefined && value !== null && value !== '')
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUSD(value) {
|
||||||
|
var amount = numeric(value, 0);
|
||||||
|
return (
|
||||||
|
'$' +
|
||||||
|
amount.toLocaleString('en-US', {
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
minimumFractionDigits: amount % 1 === 0 ? 0 : 2,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveCountdownEndAt() {
|
function resolveCountdownEndAt() {
|
||||||
var params = getParams();
|
var params = getParams();
|
||||||
var explicitEnd = Date.parse(params.get('end_at') || params.get('endAt') || '');
|
var explicitEnd = Date.parse(
|
||||||
if (Number.isFinite(explicitEnd) && explicitEnd > Date.now()) return explicitEnd;
|
params.get('end_at') || params.get('endAt') || ''
|
||||||
|
);
|
||||||
|
if (Number.isFinite(explicitEnd) && explicitEnd > Date.now())
|
||||||
|
return explicitEnd;
|
||||||
|
|
||||||
var hours = Number(params.get('hours'));
|
var hours = Number(params.get('hours'));
|
||||||
if (Number.isFinite(hours) && hours > 0) return Date.now() + hours * 60 * 60 * 1000;
|
if (Number.isFinite(hours) && hours > 0)
|
||||||
|
return Date.now() + hours * 60 * 60 * 1000;
|
||||||
|
|
||||||
// This page is intentionally interface-free for now; when an API is added,
|
// 后端月累充接口当前只返回活动文案周期,不返回毫秒级结束时间;倒计时仍支持 URL 显式覆盖,默认只作为页面视觉计时。
|
||||||
// use the server period end time here and do not recover failed requests with mock data.
|
|
||||||
return Date.now() + 25 * 60 * 60 * 1000 + 61 * 1000;
|
return Date.now() + 25 * 60 * 60 * 1000 + 61 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScale() {
|
function updateScale() {
|
||||||
var scale = Math.min(window.innerWidth / VIEWPORT_WIDTH, 1);
|
var scale = Math.min(window.innerWidth / VIEWPORT_WIDTH, 1);
|
||||||
var scaledHeight = Math.ceil(DESIGN_HEIGHT * (VIEWPORT_WIDTH / DESIGN_WIDTH));
|
var scaledHeight = Math.ceil(
|
||||||
|
designHeight * (VIEWPORT_WIDTH / DESIGN_WIDTH)
|
||||||
|
);
|
||||||
|
|
||||||
document.documentElement.style.setProperty('--app-scale', String(scale));
|
document.documentElement.style.setProperty(
|
||||||
|
'--app-scale',
|
||||||
|
String(scale)
|
||||||
|
);
|
||||||
viewport.style.minHeight = scaledHeight + 'px';
|
viewport.style.minHeight = scaledHeight + 'px';
|
||||||
|
page.style.minHeight = scaledHeight + 'px';
|
||||||
document.body.style.minHeight = Math.ceil(scaledHeight * scale) + 'px';
|
document.body.style.minHeight = Math.ceil(scaledHeight * scale) + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,14 +157,175 @@
|
|||||||
countNodes.seconds.textContent = twoDigits(seconds);
|
countNodes.seconds.textContent = twoDigits(seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeUser(profile, statusData) {
|
||||||
|
profile = profile || {};
|
||||||
|
var params = getParams();
|
||||||
|
return {
|
||||||
|
name: firstValue(
|
||||||
|
profile.userNickname,
|
||||||
|
profile.username,
|
||||||
|
profile.name,
|
||||||
|
params.get('name'),
|
||||||
|
'Aslan'
|
||||||
|
),
|
||||||
|
id: String(
|
||||||
|
firstValue(
|
||||||
|
profile.specialId,
|
||||||
|
profile.displayUserId,
|
||||||
|
profile.display_user_id,
|
||||||
|
profile.account,
|
||||||
|
profile.id,
|
||||||
|
profile.userId,
|
||||||
|
params.get('uid'),
|
||||||
|
params.get('id'),
|
||||||
|
''
|
||||||
|
)
|
||||||
|
),
|
||||||
|
avatar: firstValue(
|
||||||
|
profile.userAvatar,
|
||||||
|
profile.avatar,
|
||||||
|
profile.headImg,
|
||||||
|
profile.headImage,
|
||||||
|
params.get('avatar'),
|
||||||
|
ASSET_BASE + 'profile-avatar.png'
|
||||||
|
),
|
||||||
|
accumulatedRecharge: firstValue(
|
||||||
|
statusData && statusData.monthlyRecharge,
|
||||||
|
params.get('recharge'),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewardProps(resource) {
|
||||||
|
var group =
|
||||||
|
resource && resource.activityResource
|
||||||
|
? resource.activityResource.propsGroup || {}
|
||||||
|
: {};
|
||||||
|
return Array.isArray(group.activityRewardProps)
|
||||||
|
? group.activityRewardProps
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function rule(resource) {
|
||||||
|
return resource && resource.activityResource
|
||||||
|
? resource.activityResource.rule || {}
|
||||||
|
: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function thresholdAmount(resource) {
|
||||||
|
var data = parseJSON(rule(resource).jsonData) || {};
|
||||||
|
return numeric(data.quantity, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cardLayout(count, index) {
|
||||||
|
if (count >= 4) {
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
{ left: 70.5, top: 278 },
|
||||||
|
{ left: 292.5, top: 278 },
|
||||||
|
{ left: 514.5, top: 278 },
|
||||||
|
{ left: 736.5, top: 278 },
|
||||||
|
][index] || { left: 736.5, top: 278 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (count === 3) {
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
{ left: 70.5, top: 278 },
|
||||||
|
{ left: 339.5, top: 278 },
|
||||||
|
{ left: 608.5, top: 278 },
|
||||||
|
][index] || { left: 608.5, top: 278 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
{ left: 111, top: 293 },
|
||||||
|
{ left: 560, top: 293 },
|
||||||
|
][index] || { left: 560, top: 293 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCard(item, threshold, count, index) {
|
||||||
|
var pos = cardLayout(count, index);
|
||||||
|
return {
|
||||||
|
price:
|
||||||
|
item && item.amount
|
||||||
|
? formatUSD(item.amount)
|
||||||
|
: formatUSD(threshold),
|
||||||
|
icon: (item && item.cover) || ASSET_BASE + 'reward-icon.png',
|
||||||
|
left: pos.left,
|
||||||
|
top: pos.top,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeReward(resource, index) {
|
||||||
|
var currentRule = rule(resource);
|
||||||
|
var ruleId = String(currentRule.id || resource.ruleId || '');
|
||||||
|
var threshold = thresholdAmount(resource);
|
||||||
|
var props = rewardProps(resource).slice(0, 4);
|
||||||
|
var receiveStatus = String(resource.receiveStatus || '').toUpperCase();
|
||||||
|
var claimed = receiveStatus === 'RECEIVED';
|
||||||
|
var claimable = receiveStatus === 'NOT_RECEIVED';
|
||||||
|
var cardCount = props.length || fallbackCards.length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
ruleId: ruleId,
|
||||||
|
amount: formatUSD(threshold),
|
||||||
|
top: 1776 + index * 690,
|
||||||
|
background:
|
||||||
|
index % 2 === 0
|
||||||
|
? ASSET_BASE + 'reward-section-a.png'
|
||||||
|
: ASSET_BASE + 'reward-section-b.png',
|
||||||
|
claim: {
|
||||||
|
text: claimed
|
||||||
|
? t('rechargeReward.claimed', 'Claimed')
|
||||||
|
: t('rechargeReward.claim', 'Claim'),
|
||||||
|
claimable: claimable,
|
||||||
|
claimed: claimed,
|
||||||
|
loading: Boolean(state.claiming[ruleId]),
|
||||||
|
},
|
||||||
|
cards: props.length
|
||||||
|
? props.map(function (item, cardIndex) {
|
||||||
|
return normalizeCard(
|
||||||
|
item,
|
||||||
|
threshold,
|
||||||
|
cardCount,
|
||||||
|
cardIndex
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: fallbackCards.map(function (card) {
|
||||||
|
return Object.assign({}, card, {
|
||||||
|
price: formatUSD(threshold),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeRewards(statusData) {
|
||||||
|
var resources =
|
||||||
|
statusData && Array.isArray(statusData.activityResources)
|
||||||
|
? statusData.activityResources
|
||||||
|
: [];
|
||||||
|
return resources
|
||||||
|
.map(function (item, index) {
|
||||||
|
return normalizeReward(item, index);
|
||||||
|
})
|
||||||
|
.filter(function (item) {
|
||||||
|
return item.ruleId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function renderProfile(user) {
|
function renderProfile(user) {
|
||||||
document.querySelector('[data-profile-avatar]').src = user.avatar;
|
document.querySelector('[data-profile-avatar]').src =
|
||||||
document.querySelector('[data-profile-name]').textContent = user.name;
|
user.avatar || ASSET_BASE + 'profile-avatar.png';
|
||||||
|
document.querySelector('[data-profile-name]').textContent =
|
||||||
|
user.name || 'Aslan';
|
||||||
document.querySelector('[data-profile-id]').textContent =
|
document.querySelector('[data-profile-id]').textContent =
|
||||||
t('rechargeReward.idPrefix', 'ID:') + ' ' + user.id;
|
t('rechargeReward.idPrefix', 'ID:') + ' ' + (user.id || '-');
|
||||||
document.querySelector('[data-profile-recharge]').textContent =
|
document.querySelector('[data-profile-recharge]').textContent =
|
||||||
t('rechargeReward.accumulatedRecharge', 'Accumlated Recharge:') +
|
t('rechargeReward.accumulatedRecharge', 'Accumulated Recharge:') +
|
||||||
user.accumulatedRecharge;
|
formatUSD(user.accumulatedRecharge || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRewardCard(card) {
|
function renderRewardCard(card) {
|
||||||
@ -135,31 +349,65 @@
|
|||||||
].join('');
|
].join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderClaimButton(claim) {
|
function renderClaimButton(section) {
|
||||||
var stateClass = claim.claimed ? ' is-claimed' : claim.claimable ? ' is-claimable' : ' is-disabled';
|
var claim = section.claim || {};
|
||||||
|
var stateClass = claim.claimed
|
||||||
|
? ' is-claimed'
|
||||||
|
: claim.claimable
|
||||||
|
? ' is-claimable'
|
||||||
|
: ' is-disabled';
|
||||||
|
var disabled = !claim.claimable || claim.claimed || claim.loading;
|
||||||
return [
|
return [
|
||||||
'<button class="claim-button',
|
'<button class="claim-button',
|
||||||
stateClass,
|
stateClass,
|
||||||
'" type="button"',
|
'" type="button" data-rule-id="',
|
||||||
claim.claimable && !claim.claimed ? '' : ' disabled',
|
escapeHTML(section.ruleId),
|
||||||
|
'"',
|
||||||
|
disabled ? ' disabled' : '',
|
||||||
'>',
|
'>',
|
||||||
'<img class="claim-button-bg" src="',
|
'<img class="claim-button-bg" src="',
|
||||||
ASSET_BASE,
|
ASSET_BASE,
|
||||||
'receive-button-bg.png" alt="" />',
|
'receive-button-bg.png" alt="" />',
|
||||||
'<span>',
|
'<span>',
|
||||||
escapeHTML(claim.text || 'Receive'),
|
escapeHTML(
|
||||||
|
claim.loading
|
||||||
|
? t('rechargeReward.claiming', 'Claiming...')
|
||||||
|
: claim.text || t('rechargeReward.claim', 'Claim')
|
||||||
|
),
|
||||||
'</span>',
|
'</span>',
|
||||||
'</button>',
|
'</button>',
|
||||||
].join('');
|
].join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRewards(rewards) {
|
function renderRewards(rewards) {
|
||||||
|
if (state.loading) {
|
||||||
|
rewardSections.innerHTML =
|
||||||
|
'<p class="reward-message">' +
|
||||||
|
escapeHTML(t('rechargeReward.loading', 'Loading...')) +
|
||||||
|
'</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state.error) {
|
||||||
|
rewardSections.innerHTML =
|
||||||
|
'<p class="reward-message is-error">' +
|
||||||
|
escapeHTML(state.error) +
|
||||||
|
'</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!rewards.length) {
|
||||||
|
rewardSections.innerHTML =
|
||||||
|
'<p class="reward-message">' +
|
||||||
|
escapeHTML(t('rechargeReward.noRewards', 'No rewards yet')) +
|
||||||
|
'</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rewardSections.innerHTML = rewards
|
rewardSections.innerHTML = rewards
|
||||||
.map(function (section) {
|
.map(function (section) {
|
||||||
var title = t('rechargeReward.rechargeTitle', 'Recharge {amount}').replace(
|
var title = t(
|
||||||
'{amount}',
|
'rechargeReward.rechargeTitle',
|
||||||
section.amount
|
'Recharge {amount}'
|
||||||
);
|
).replace('{amount}', section.amount);
|
||||||
return [
|
return [
|
||||||
'<section class="reward-section" style="--section-top:',
|
'<section class="reward-section" style="--section-top:',
|
||||||
section.top,
|
section.top,
|
||||||
@ -177,27 +425,172 @@
|
|||||||
return renderRewardCard(card);
|
return renderRewardCard(card);
|
||||||
})
|
})
|
||||||
.join(''),
|
.join(''),
|
||||||
renderClaimButton(section.claim || { text: 'Receive', claimable: false }),
|
renderClaimButton(section),
|
||||||
'</section>',
|
'</section>',
|
||||||
].join('');
|
].join('');
|
||||||
})
|
})
|
||||||
.join('');
|
.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDesignHeight() {
|
||||||
|
var rewardCount = Math.max(state.rewards.length, 2);
|
||||||
|
designHeight = Math.max(
|
||||||
|
DEFAULT_DESIGN_HEIGHT,
|
||||||
|
1776 + rewardCount * 690 + 120
|
||||||
|
);
|
||||||
|
stage.style.height = designHeight + 'px';
|
||||||
|
if (bgBottom)
|
||||||
|
bgBottom.style.top = Math.max(2695, designHeight - 578) + 'px';
|
||||||
|
updateScale();
|
||||||
|
}
|
||||||
|
|
||||||
function renderPage() {
|
function renderPage() {
|
||||||
document.title = t('rechargeReward.pageTitle', 'Recharge Reward');
|
document.title = t('rechargeReward.pageTitle', 'Recharge Reward');
|
||||||
renderProfile(activityData.user);
|
renderProfile(state.user);
|
||||||
renderRewards(activityData.rewards);
|
updateDesignHeight();
|
||||||
|
renderRewards(state.rewards);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockData() {
|
||||||
|
var params = getParams();
|
||||||
|
var claimed = params.get('claimed') === '1';
|
||||||
|
return Promise.resolve({
|
||||||
|
profile: {
|
||||||
|
userNickname: params.get('name') || 'Aslan',
|
||||||
|
account: params.get('uid') || '12345678',
|
||||||
|
userAvatar:
|
||||||
|
params.get('avatar') || ASSET_BASE + 'profile-avatar.png',
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
monthlyRecharge: numeric(params.get('recharge'), 5998),
|
||||||
|
activityResources: [
|
||||||
|
{
|
||||||
|
receiveStatus: claimed ? 'RECEIVED' : 'NOT_RECEIVED',
|
||||||
|
activityResource: {
|
||||||
|
rule: {
|
||||||
|
id: '1000000000000000001',
|
||||||
|
jsonData: '{"quantity":100}',
|
||||||
|
},
|
||||||
|
propsGroup: { activityRewardProps: [] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
receiveStatus: 'INELIGIBLE',
|
||||||
|
activityResource: {
|
||||||
|
rule: {
|
||||||
|
id: '1000000000000000002',
|
||||||
|
jsonData: '{"quantity":200}',
|
||||||
|
},
|
||||||
|
propsGroup: { activityRewardProps: [] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRemoteData() {
|
||||||
|
if (!window.AslanCommon) {
|
||||||
|
return Promise.reject(new Error('Aslan bridge unavailable'));
|
||||||
|
}
|
||||||
|
return Promise.all([
|
||||||
|
window.AslanCommon.user.profile().catch(function (error) {
|
||||||
|
console.warn('Aslan profile failed', error);
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
window.AslanCommon.rechargeReward.status(),
|
||||||
|
]).then(function (result) {
|
||||||
|
return { profile: result[0], status: result[1] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
state.loading = true;
|
||||||
|
state.error = '';
|
||||||
|
renderPage();
|
||||||
|
|
||||||
|
var params = getParams();
|
||||||
|
var loader =
|
||||||
|
params.get('mock') === '1' || params.get('mock') === 'true'
|
||||||
|
? mockData()
|
||||||
|
: loadRemoteData();
|
||||||
|
|
||||||
|
return loader
|
||||||
|
.then(function (payload) {
|
||||||
|
var statusData = payload.status || {};
|
||||||
|
state.user = normalizeUser(payload.profile, statusData);
|
||||||
|
state.rewards = normalizeRewards(statusData);
|
||||||
|
state.loading = false;
|
||||||
|
state.error = '';
|
||||||
|
renderPage();
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.warn('Aslan recharge reward load failed', error);
|
||||||
|
state.loading = false;
|
||||||
|
state.error =
|
||||||
|
(error && error.message) ||
|
||||||
|
t('rechargeReward.loadFailed', 'Load failed');
|
||||||
|
renderPage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function markClaimed(ruleId) {
|
||||||
|
state.rewards = state.rewards.map(function (item) {
|
||||||
|
if (item.ruleId !== ruleId) return item;
|
||||||
|
item.claim.claimed = true;
|
||||||
|
item.claim.claimable = false;
|
||||||
|
item.claim.loading = false;
|
||||||
|
item.claim.text = t('rechargeReward.claimed', 'Claimed');
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function claimReward(ruleId) {
|
||||||
|
if (!ruleId || state.claiming[ruleId] || !window.AslanCommon) return;
|
||||||
|
state.claiming[ruleId] = true;
|
||||||
|
renderPage();
|
||||||
|
|
||||||
|
// 领取必须只提交后端规则 Long 的字符串形式,避免 JS Number 精度损失导致发错档位。
|
||||||
|
window.AslanCommon.rechargeReward
|
||||||
|
.claim(ruleId)
|
||||||
|
.then(function () {
|
||||||
|
delete state.claiming[ruleId];
|
||||||
|
markClaimed(ruleId);
|
||||||
|
renderPage();
|
||||||
|
showToast(t('rechargeReward.claimSuccess', 'Claimed'));
|
||||||
|
return loadData();
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
delete state.claiming[ruleId];
|
||||||
|
renderPage();
|
||||||
|
showToast(
|
||||||
|
(error && error.message) ||
|
||||||
|
t('rechargeReward.claimFailed', 'Claim failed')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindEvents() {
|
||||||
|
rewardSections.addEventListener('click', function (event) {
|
||||||
|
var button = event.target.closest('[data-rule-id]');
|
||||||
|
if (!button || button.disabled) return;
|
||||||
|
claimReward(button.getAttribute('data-rule-id'));
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', updateScale);
|
||||||
|
window.addEventListener('hyapp:i18n-ready', function () {
|
||||||
|
renderPage();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
updateScale();
|
updateScale();
|
||||||
updateCountdown();
|
updateCountdown();
|
||||||
renderPage();
|
renderPage();
|
||||||
|
bindEvents();
|
||||||
|
loadData();
|
||||||
|
|
||||||
window.setInterval(updateCountdown, 1000);
|
if (countdownTimer) window.clearInterval(countdownTimer);
|
||||||
window.addEventListener('resize', updateScale);
|
countdownTimer = window.setInterval(updateCountdown, 1000);
|
||||||
window.addEventListener('hyapp:i18n-ready', renderPage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|||||||
@ -16,11 +16,7 @@ body {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background: var(--hy-theme-bg);
|
background: var(--hy-theme-bg);
|
||||||
color: #f6e0b2;
|
color: #f6e0b2;
|
||||||
font-family:
|
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
|
||||||
Arial,
|
|
||||||
"Helvetica Neue",
|
|
||||||
Helvetica,
|
|
||||||
sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -138,19 +134,19 @@ body {
|
|||||||
0 0 14px rgba(255, 210, 135, 0.58);
|
0 0 14px rgba(255, 210, 135, 0.58);
|
||||||
}
|
}
|
||||||
|
|
||||||
.count-number[data-count="days"] {
|
.count-number[data-count='days'] {
|
||||||
left: 97px;
|
left: 97px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.count-number[data-count="hours"] {
|
.count-number[data-count='hours'] {
|
||||||
left: 301px;
|
left: 301px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.count-number[data-count="minutes"] {
|
.count-number[data-count='minutes'] {
|
||||||
left: 506px;
|
left: 506px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.count-number[data-count="seconds"] {
|
.count-number[data-count='seconds'] {
|
||||||
left: 706px;
|
left: 706px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +256,33 @@ body {
|
|||||||
width: 900px;
|
width: 900px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reward-message {
|
||||||
|
position: absolute;
|
||||||
|
left: 90px;
|
||||||
|
top: 1810px;
|
||||||
|
z-index: 5;
|
||||||
|
width: 900px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 36px 44px;
|
||||||
|
border: 3px solid rgba(255, 206, 149, 0.4);
|
||||||
|
border-radius: 28px;
|
||||||
|
background: rgba(54, 24, 9, 0.76);
|
||||||
|
color: #f6e0b2;
|
||||||
|
font-size: 38px;
|
||||||
|
font-weight: 900;
|
||||||
|
line-height: 52px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow:
|
||||||
|
0 2px 0 #3a1704,
|
||||||
|
0 0 12px rgba(255, 207, 113, 0.36);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reward-message.is-error {
|
||||||
|
border-color: rgba(255, 112, 112, 0.52);
|
||||||
|
color: #ffd1c2;
|
||||||
|
}
|
||||||
|
|
||||||
.title-pill {
|
.title-pill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -366,6 +389,11 @@ body {
|
|||||||
opacity: 0.68;
|
opacity: 0.68;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.claim-button.is-claimed,
|
||||||
|
.claim-button.is-disabled {
|
||||||
|
filter: grayscale(0.45);
|
||||||
|
}
|
||||||
|
|
||||||
.claim-button-bg {
|
.claim-button-bg {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|||||||
@ -65,6 +65,14 @@
|
|||||||
"rechargeReward.idPrefix": "المعرّف:",
|
"rechargeReward.idPrefix": "المعرّف:",
|
||||||
"rechargeReward.accumulatedRecharge": "إجمالي الشحن:",
|
"rechargeReward.accumulatedRecharge": "إجمالي الشحن:",
|
||||||
"rechargeReward.rechargeTitle": "اشحن {amount}",
|
"rechargeReward.rechargeTitle": "اشحن {amount}",
|
||||||
|
"rechargeReward.claim": "استلام",
|
||||||
|
"rechargeReward.claiming": "جار الاستلام...",
|
||||||
|
"rechargeReward.claimed": "تم الاستلام",
|
||||||
|
"rechargeReward.claimSuccess": "تم الاستلام",
|
||||||
|
"rechargeReward.claimFailed": "فشل الاستلام",
|
||||||
|
"rechargeReward.loading": "جار التحميل...",
|
||||||
|
"rechargeReward.noRewards": "لا توجد مكافآت بعد",
|
||||||
|
"rechargeReward.loadFailed": "فشل التحميل",
|
||||||
"wheel.pageTitle": "عجلة يومي",
|
"wheel.pageTitle": "عجلة يومي",
|
||||||
"wheel.pageLabel": "عجلة يومي",
|
"wheel.pageLabel": "عجلة يومي",
|
||||||
"wheel.classic": "كلاسيكي",
|
"wheel.classic": "كلاسيكي",
|
||||||
@ -480,11 +488,11 @@
|
|||||||
"coinseller_center.load_failed": "فشل التحميل. حاول مرة أخرى لاحقا.",
|
"coinseller_center.load_failed": "فشل التحميل. حاول مرة أخرى لاحقا.",
|
||||||
"coinseller_center.transfer_failed": "فشل التحويل.",
|
"coinseller_center.transfer_failed": "فشل التحويل.",
|
||||||
"coinseller_center.sub_sellers": "بائعو العملات الفرعيون",
|
"coinseller_center.sub_sellers": "بائعو العملات الفرعيون",
|
||||||
"coinseller_center.sub_sellers_desc": "ادع وأدر بائعي العملات الفرعيين المباشرين",
|
"coinseller_center.sub_sellers_desc": "ادع بائعي عملات فرعيين وأدر المعتمدين مباشرة",
|
||||||
"coinseller_center.invite_sub_seller": "دعوة بائع عملات فرعي",
|
"coinseller_center.invite_sub_seller": "دعوة بائع عملات فرعي",
|
||||||
"coinseller_center.invite_sub_seller_hint": "أدخل معرف المستخدم لفتح بائع عملات فرعي مباشر.",
|
"coinseller_center.invite_sub_seller_hint": "أدخل معرف المستخدم. سيظهر البائع بعد المراجعة الرسمية.",
|
||||||
"coinseller_center.invite_now": "ادع الآن",
|
"coinseller_center.invite_now": "ادع الآن",
|
||||||
"coinseller_center.invite_success": "تم إرسال الدعوة.",
|
"coinseller_center.invite_success": "ستراجع الجهة الرسمية دعوتك خلال 24 ساعة.",
|
||||||
"coinseller_center.invite_failed": "فشلت الدعوة.",
|
"coinseller_center.invite_failed": "فشلت الدعوة.",
|
||||||
"coinseller_center.no_sub_sellers": "لا يوجد بائعو عملات فرعيون بعد.",
|
"coinseller_center.no_sub_sellers": "لا يوجد بائعو عملات فرعيون بعد.",
|
||||||
"coinseller_center.sub_seller_wallet": "المحفظة",
|
"coinseller_center.sub_seller_wallet": "المحفظة",
|
||||||
|
|||||||
@ -65,6 +65,14 @@
|
|||||||
"rechargeReward.idPrefix": "ID:",
|
"rechargeReward.idPrefix": "ID:",
|
||||||
"rechargeReward.accumulatedRecharge": "Accumulated Recharge:",
|
"rechargeReward.accumulatedRecharge": "Accumulated Recharge:",
|
||||||
"rechargeReward.rechargeTitle": "Recharge {amount}",
|
"rechargeReward.rechargeTitle": "Recharge {amount}",
|
||||||
|
"rechargeReward.claim": "Claim",
|
||||||
|
"rechargeReward.claiming": "Claiming...",
|
||||||
|
"rechargeReward.claimed": "Claimed",
|
||||||
|
"rechargeReward.claimSuccess": "Claimed",
|
||||||
|
"rechargeReward.claimFailed": "Claim failed",
|
||||||
|
"rechargeReward.loading": "Loading...",
|
||||||
|
"rechargeReward.noRewards": "No rewards yet",
|
||||||
|
"rechargeReward.loadFailed": "Load failed",
|
||||||
"wheel.pageTitle": "Yumi Wheel",
|
"wheel.pageTitle": "Yumi Wheel",
|
||||||
"wheel.pageLabel": "Yumi Wheel",
|
"wheel.pageLabel": "Yumi Wheel",
|
||||||
"wheel.classic": "Classic",
|
"wheel.classic": "Classic",
|
||||||
@ -486,11 +494,11 @@
|
|||||||
"coinseller_center.load_failed": "Load failed. Try again later.",
|
"coinseller_center.load_failed": "Load failed. Try again later.",
|
||||||
"coinseller_center.transfer_failed": "Transfer failed.",
|
"coinseller_center.transfer_failed": "Transfer failed.",
|
||||||
"coinseller_center.sub_sellers": "My sub coin sellers",
|
"coinseller_center.sub_sellers": "My sub coin sellers",
|
||||||
"coinseller_center.sub_sellers_desc": "Invite and manage direct sub coin sellers",
|
"coinseller_center.sub_sellers_desc": "Invite sub coin sellers and manage approved direct sellers",
|
||||||
"coinseller_center.invite_sub_seller": "Invite sub coin seller",
|
"coinseller_center.invite_sub_seller": "Invite sub coin seller",
|
||||||
"coinseller_center.invite_sub_seller_hint": "Enter the user's display ID to open a direct sub coin seller.",
|
"coinseller_center.invite_sub_seller_hint": "Enter the user's display ID. The seller will appear after official review.",
|
||||||
"coinseller_center.invite_now": "Invite now",
|
"coinseller_center.invite_now": "Invite now",
|
||||||
"coinseller_center.invite_success": "Invitation submitted.",
|
"coinseller_center.invite_success": "Official will review your invitation within 24 hours.",
|
||||||
"coinseller_center.invite_failed": "Invite failed.",
|
"coinseller_center.invite_failed": "Invite failed.",
|
||||||
"coinseller_center.no_sub_sellers": "No sub coin sellers yet.",
|
"coinseller_center.no_sub_sellers": "No sub coin sellers yet.",
|
||||||
"coinseller_center.sub_seller_wallet": "Wallet",
|
"coinseller_center.sub_seller_wallet": "Wallet",
|
||||||
|
|||||||
@ -65,6 +65,14 @@
|
|||||||
"rechargeReward.idPrefix": "ID:",
|
"rechargeReward.idPrefix": "ID:",
|
||||||
"rechargeReward.accumulatedRecharge": "Recarga acumulada:",
|
"rechargeReward.accumulatedRecharge": "Recarga acumulada:",
|
||||||
"rechargeReward.rechargeTitle": "Recarga {amount}",
|
"rechargeReward.rechargeTitle": "Recarga {amount}",
|
||||||
|
"rechargeReward.claim": "Reclamar",
|
||||||
|
"rechargeReward.claiming": "Reclamando...",
|
||||||
|
"rechargeReward.claimed": "Reclamado",
|
||||||
|
"rechargeReward.claimSuccess": "Reclamado",
|
||||||
|
"rechargeReward.claimFailed": "Error al reclamar",
|
||||||
|
"rechargeReward.loading": "Cargando...",
|
||||||
|
"rechargeReward.noRewards": "No hay recompensas todavía",
|
||||||
|
"rechargeReward.loadFailed": "Error al cargar",
|
||||||
"wheel.pageTitle": "Rueda de Yumi",
|
"wheel.pageTitle": "Rueda de Yumi",
|
||||||
"wheel.pageLabel": "Rueda de Yumi",
|
"wheel.pageLabel": "Rueda de Yumi",
|
||||||
"wheel.classic": "Clásico",
|
"wheel.classic": "Clásico",
|
||||||
@ -480,11 +488,11 @@
|
|||||||
"coinseller_center.load_failed": "Error al cargar. Inténtalo de nuevo más tarde.",
|
"coinseller_center.load_failed": "Error al cargar. Inténtalo de nuevo más tarde.",
|
||||||
"coinseller_center.transfer_failed": "Transferencia fallida.",
|
"coinseller_center.transfer_failed": "Transferencia fallida.",
|
||||||
"coinseller_center.sub_sellers": "Mis subvendedores de monedas",
|
"coinseller_center.sub_sellers": "Mis subvendedores de monedas",
|
||||||
"coinseller_center.sub_sellers_desc": "Invita y gestiona subvendedores directos",
|
"coinseller_center.sub_sellers_desc": "Invita subvendedores y gestiona los directos aprobados",
|
||||||
"coinseller_center.invite_sub_seller": "Invitar subvendedor",
|
"coinseller_center.invite_sub_seller": "Invitar subvendedor",
|
||||||
"coinseller_center.invite_sub_seller_hint": "Ingresa el ID visible del usuario para abrir un subvendedor directo.",
|
"coinseller_center.invite_sub_seller_hint": "Ingresa el ID visible del usuario. Aparecera despues de la revision oficial.",
|
||||||
"coinseller_center.invite_now": "Invitar ahora",
|
"coinseller_center.invite_now": "Invitar ahora",
|
||||||
"coinseller_center.invite_success": "Invitación enviada.",
|
"coinseller_center.invite_success": "El equipo oficial revisara tu invitacion en 24 horas.",
|
||||||
"coinseller_center.invite_failed": "Error al invitar.",
|
"coinseller_center.invite_failed": "Error al invitar.",
|
||||||
"coinseller_center.no_sub_sellers": "Aún no hay subvendedores.",
|
"coinseller_center.no_sub_sellers": "Aún no hay subvendedores.",
|
||||||
"coinseller_center.sub_seller_wallet": "Billetera",
|
"coinseller_center.sub_seller_wallet": "Billetera",
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
"rechargeReward.idPrefix": "ID:",
|
"rechargeReward.idPrefix": "ID:",
|
||||||
"rechargeReward.accumulatedRecharge": "Recharge akumulatif:",
|
"rechargeReward.accumulatedRecharge": "Recharge akumulatif:",
|
||||||
"rechargeReward.rechargeTitle": "Recharge {amount}",
|
"rechargeReward.rechargeTitle": "Recharge {amount}",
|
||||||
|
"rechargeReward.claim": "Klaim",
|
||||||
|
"rechargeReward.claiming": "Mengklaim...",
|
||||||
|
"rechargeReward.claimed": "Diklaim",
|
||||||
|
"rechargeReward.claimSuccess": "Diklaim",
|
||||||
|
"rechargeReward.claimFailed": "Klaim gagal",
|
||||||
|
"rechargeReward.loading": "Memuat...",
|
||||||
|
"rechargeReward.noRewards": "Belum ada hadiah",
|
||||||
|
"rechargeReward.loadFailed": "Gagal memuat",
|
||||||
"wheel.pageTitle": "Yumi Wheel",
|
"wheel.pageTitle": "Yumi Wheel",
|
||||||
"wheel.pageLabel": "Yumi Wheel",
|
"wheel.pageLabel": "Yumi Wheel",
|
||||||
"wheel.classic": "Classic",
|
"wheel.classic": "Classic",
|
||||||
@ -447,11 +455,11 @@
|
|||||||
"coinseller_center.load_failed": "Gagal memuat. Coba lagi nanti.",
|
"coinseller_center.load_failed": "Gagal memuat. Coba lagi nanti.",
|
||||||
"coinseller_center.transfer_failed": "Transfer gagal.",
|
"coinseller_center.transfer_failed": "Transfer gagal.",
|
||||||
"coinseller_center.sub_sellers": "Sub penjual koin saya",
|
"coinseller_center.sub_sellers": "Sub penjual koin saya",
|
||||||
"coinseller_center.sub_sellers_desc": "Undang dan kelola sub penjual koin langsung",
|
"coinseller_center.sub_sellers_desc": "Undang sub penjual koin dan kelola seller langsung yang disetujui",
|
||||||
"coinseller_center.invite_sub_seller": "Undang sub penjual koin",
|
"coinseller_center.invite_sub_seller": "Undang sub penjual koin",
|
||||||
"coinseller_center.invite_sub_seller_hint": "Masukkan ID tampilan pengguna untuk membuka sub penjual koin langsung.",
|
"coinseller_center.invite_sub_seller_hint": "Masukkan ID tampilan pengguna. Seller akan muncul setelah tinjauan resmi.",
|
||||||
"coinseller_center.invite_now": "Undang sekarang",
|
"coinseller_center.invite_now": "Undang sekarang",
|
||||||
"coinseller_center.invite_success": "Undangan terkirim.",
|
"coinseller_center.invite_success": "Pihak resmi akan meninjau undangan Anda dalam 24 jam.",
|
||||||
"coinseller_center.invite_failed": "Undangan gagal.",
|
"coinseller_center.invite_failed": "Undangan gagal.",
|
||||||
"coinseller_center.no_sub_sellers": "Belum ada sub penjual koin.",
|
"coinseller_center.no_sub_sellers": "Belum ada sub penjual koin.",
|
||||||
"coinseller_center.sub_seller_wallet": "Dompet",
|
"coinseller_center.sub_seller_wallet": "Dompet",
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
"rechargeReward.idPrefix": "ID:",
|
"rechargeReward.idPrefix": "ID:",
|
||||||
"rechargeReward.accumulatedRecharge": "Toplam yükleme:",
|
"rechargeReward.accumulatedRecharge": "Toplam yükleme:",
|
||||||
"rechargeReward.rechargeTitle": "{amount} yükle",
|
"rechargeReward.rechargeTitle": "{amount} yükle",
|
||||||
|
"rechargeReward.claim": "Al",
|
||||||
|
"rechargeReward.claiming": "Alınıyor...",
|
||||||
|
"rechargeReward.claimed": "Alındı",
|
||||||
|
"rechargeReward.claimSuccess": "Alındı",
|
||||||
|
"rechargeReward.claimFailed": "Alma başarısız",
|
||||||
|
"rechargeReward.loading": "Yükleniyor...",
|
||||||
|
"rechargeReward.noRewards": "Henüz ödül yok",
|
||||||
|
"rechargeReward.loadFailed": "Yükleme başarısız",
|
||||||
"wheel.pageTitle": "Yumi Çarkı",
|
"wheel.pageTitle": "Yumi Çarkı",
|
||||||
"wheel.pageLabel": "Yumi Çarkı",
|
"wheel.pageLabel": "Yumi Çarkı",
|
||||||
"wheel.classic": "Klasik",
|
"wheel.classic": "Klasik",
|
||||||
@ -447,11 +455,11 @@
|
|||||||
"coinseller_center.load_failed": "Yükleme başarısız. Daha sonra tekrar deneyin.",
|
"coinseller_center.load_failed": "Yükleme başarısız. Daha sonra tekrar deneyin.",
|
||||||
"coinseller_center.transfer_failed": "Transfer başarısız.",
|
"coinseller_center.transfer_failed": "Transfer başarısız.",
|
||||||
"coinseller_center.sub_sellers": "Alt coin sellerlarım",
|
"coinseller_center.sub_sellers": "Alt coin sellerlarım",
|
||||||
"coinseller_center.sub_sellers_desc": "Doğrudan alt coin seller davet edin ve yönetin",
|
"coinseller_center.sub_sellers_desc": "Alt coin seller davet edin ve onaylı doğrudan sellerları yönetin",
|
||||||
"coinseller_center.invite_sub_seller": "Alt coin seller davet et",
|
"coinseller_center.invite_sub_seller": "Alt coin seller davet et",
|
||||||
"coinseller_center.invite_sub_seller_hint": "Doğrudan alt coin seller açmak için kullanıcının görünen ID'sini girin.",
|
"coinseller_center.invite_sub_seller_hint": "Kullanıcının görünen ID'sini girin. Seller resmi incelemeden sonra görünür.",
|
||||||
"coinseller_center.invite_now": "Şimdi davet et",
|
"coinseller_center.invite_now": "Şimdi davet et",
|
||||||
"coinseller_center.invite_success": "Davet gönderildi.",
|
"coinseller_center.invite_success": "Yetkililer davetinizi 24 saat içinde inceleyecek.",
|
||||||
"coinseller_center.invite_failed": "Davet başarısız.",
|
"coinseller_center.invite_failed": "Davet başarısız.",
|
||||||
"coinseller_center.no_sub_sellers": "Henüz alt coin seller yok.",
|
"coinseller_center.no_sub_sellers": "Henüz alt coin seller yok.",
|
||||||
"coinseller_center.sub_seller_wallet": "Cüzdan",
|
"coinseller_center.sub_seller_wallet": "Cüzdan",
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
"rechargeReward.idPrefix": "ID:",
|
"rechargeReward.idPrefix": "ID:",
|
||||||
"rechargeReward.accumulatedRecharge": "累计充值:",
|
"rechargeReward.accumulatedRecharge": "累计充值:",
|
||||||
"rechargeReward.rechargeTitle": "充值 {amount}",
|
"rechargeReward.rechargeTitle": "充值 {amount}",
|
||||||
|
"rechargeReward.claim": "领取",
|
||||||
|
"rechargeReward.claiming": "领取中...",
|
||||||
|
"rechargeReward.claimed": "已领取",
|
||||||
|
"rechargeReward.claimSuccess": "领取成功",
|
||||||
|
"rechargeReward.claimFailed": "领取失败",
|
||||||
|
"rechargeReward.loading": "加载中...",
|
||||||
|
"rechargeReward.noRewards": "暂无奖励",
|
||||||
|
"rechargeReward.loadFailed": "加载失败",
|
||||||
"wheel.pageTitle": "Yumi 转盘",
|
"wheel.pageTitle": "Yumi 转盘",
|
||||||
"wheel.pageLabel": "Yumi 转盘",
|
"wheel.pageLabel": "Yumi 转盘",
|
||||||
"wheel.classic": "Classic",
|
"wheel.classic": "Classic",
|
||||||
@ -453,11 +461,11 @@
|
|||||||
"coinseller_center.load_failed": "加载失败,请稍后重试。",
|
"coinseller_center.load_failed": "加载失败,请稍后重试。",
|
||||||
"coinseller_center.transfer_failed": "转账失败。",
|
"coinseller_center.transfer_failed": "转账失败。",
|
||||||
"coinseller_center.sub_sellers": "我的子币商",
|
"coinseller_center.sub_sellers": "我的子币商",
|
||||||
"coinseller_center.sub_sellers_desc": "邀请并管理直开子币商",
|
"coinseller_center.sub_sellers_desc": "邀请子币商,审核通过后管理直属子币商",
|
||||||
"coinseller_center.invite_sub_seller": "邀请子币商",
|
"coinseller_center.invite_sub_seller": "邀请子币商",
|
||||||
"coinseller_center.invite_sub_seller_hint": "输入用户展示 ID,直开为你的子币商。",
|
"coinseller_center.invite_sub_seller_hint": "输入用户展示 ID,提交申请后由官方审核。",
|
||||||
"coinseller_center.invite_now": "立即邀请",
|
"coinseller_center.invite_now": "立即邀请",
|
||||||
"coinseller_center.invite_success": "邀请已提交。",
|
"coinseller_center.invite_success": "官方会在24小时内审核您的邀请。",
|
||||||
"coinseller_center.invite_failed": "邀请失败。",
|
"coinseller_center.invite_failed": "邀请失败。",
|
||||||
"coinseller_center.no_sub_sellers": "暂无子币商。",
|
"coinseller_center.no_sub_sellers": "暂无子币商。",
|
||||||
"coinseller_center.sub_seller_wallet": "钱包",
|
"coinseller_center.sub_seller_wallet": "钱包",
|
||||||
|
|||||||
516
common_aslan/aslan-common.js
Normal file
516
common_aslan/aslan-common.js
Normal file
@ -0,0 +1,516 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PROD_API_BASE = 'https://api.atuchat.com/';
|
||||||
|
var LOCAL_API_BASE = 'http://127.0.0.1:1100/';
|
||||||
|
var APP_CODE = 'aslan';
|
||||||
|
var DEFAULT_ORIGIN = 'ATYOU';
|
||||||
|
var readyPromise = null;
|
||||||
|
var headers = {
|
||||||
|
authorization: '',
|
||||||
|
'req-app-intel':
|
||||||
|
'version=1.0.0;build=1;model=H5;sysVersion=web;channel=Web',
|
||||||
|
'req-client': 'H5',
|
||||||
|
'req-imei': 'H5-STATIC',
|
||||||
|
'req-lang': 'en',
|
||||||
|
'req-sys-origin': 'origin=ATYOU;originChild=ATYOU',
|
||||||
|
'req-version': 'V2',
|
||||||
|
'req-zone': 'Asia/Shanghai',
|
||||||
|
'Req-Atyou': 'true',
|
||||||
|
};
|
||||||
|
|
||||||
|
function currentParams() {
|
||||||
|
var params = new URLSearchParams(window.location.search || '');
|
||||||
|
var hash = window.location.hash || '';
|
||||||
|
if (hash.indexOf('?') >= 0) {
|
||||||
|
new URLSearchParams(hash.split('?').slice(1).join('?')).forEach(
|
||||||
|
function (value, key) {
|
||||||
|
if (!params.has(key)) params.set(key, value);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function query(name) {
|
||||||
|
return currentParams().get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBaseURL(value) {
|
||||||
|
return String(value || '').replace(/\/+$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveEnv() {
|
||||||
|
var env = String(query('env') || '')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase();
|
||||||
|
return env === 'local' || env === 'test' || env === 'dev' ? env : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function baseURL() {
|
||||||
|
var override =
|
||||||
|
query('apiBase') ||
|
||||||
|
query('api_base') ||
|
||||||
|
query('aslan_api_base') ||
|
||||||
|
window.ASLAN_API_BASE_URL ||
|
||||||
|
(window.AslanCommonConfig && window.AslanCommonConfig.apiBase);
|
||||||
|
if (override) return normalizeBaseURL(override);
|
||||||
|
return resolveEnv() === 'local'
|
||||||
|
? normalizeBaseURL(LOCAL_API_BASE)
|
||||||
|
: normalizeBaseURL(PROD_API_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildURL(path, queryData) {
|
||||||
|
var url = new URL(
|
||||||
|
String(path || '').replace(/^\/+/, ''),
|
||||||
|
baseURL() + '/'
|
||||||
|
);
|
||||||
|
Object.keys(queryData || {}).forEach(function (key) {
|
||||||
|
var value = queryData[key];
|
||||||
|
if (value === undefined || value === null || value === '') return;
|
||||||
|
url.searchParams.set(key, value);
|
||||||
|
});
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAuthorization(value) {
|
||||||
|
var text = String(value || '').trim();
|
||||||
|
if (!text) return '';
|
||||||
|
return /^Bearer\s+/i.test(text) ? text : 'Bearer ' + text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitHeaderPairs(value) {
|
||||||
|
var result = {};
|
||||||
|
String(value || '')
|
||||||
|
.split(';')
|
||||||
|
.forEach(function (item) {
|
||||||
|
var index = item.indexOf('=');
|
||||||
|
if (index > -1) {
|
||||||
|
result[item.slice(0, index).trim()] = item
|
||||||
|
.slice(index + 1)
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function putHeader(target, key, value) {
|
||||||
|
if (
|
||||||
|
value === undefined ||
|
||||||
|
value === null ||
|
||||||
|
value === '' ||
|
||||||
|
target[key]
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target[key] = String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeHeaderCandidate(value, depth) {
|
||||||
|
depth = depth || 0;
|
||||||
|
if (depth > 4 || value === null || value === undefined) return {};
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
var trimmed = value.trim();
|
||||||
|
if (!trimmed) return {};
|
||||||
|
if (trimmed.charAt(0) === '{' || trimmed.charAt(0) === '[') {
|
||||||
|
try {
|
||||||
|
return normalizeHeaderCandidate(
|
||||||
|
JSON.parse(trimmed),
|
||||||
|
depth + 1
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { authorization: trimmed };
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.reduce(function (result, item) {
|
||||||
|
return Object.assign(
|
||||||
|
result,
|
||||||
|
normalizeHeaderCandidate(item, depth + 1)
|
||||||
|
);
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
if (typeof value !== 'object') return {};
|
||||||
|
|
||||||
|
var appIntel = splitHeaderPairs(
|
||||||
|
value['Req-App-Intel'] || value['req-app-intel']
|
||||||
|
);
|
||||||
|
var sysOrigin = splitHeaderPairs(
|
||||||
|
value['Req-Sys-Origin'] || value['req-sys-origin']
|
||||||
|
);
|
||||||
|
var normalized = {};
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'authorization',
|
||||||
|
value.Authorization ||
|
||||||
|
value.authorization ||
|
||||||
|
value.token ||
|
||||||
|
value.accessToken
|
||||||
|
);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'reqLang',
|
||||||
|
value['Req-Lang'] ||
|
||||||
|
value['req-lang'] ||
|
||||||
|
value.reqLang ||
|
||||||
|
value.lang
|
||||||
|
);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'appVersion',
|
||||||
|
appIntel.version || value.appVersion || value['App-Version']
|
||||||
|
);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'buildVersion',
|
||||||
|
appIntel.build || value.buildVersion
|
||||||
|
);
|
||||||
|
putHeader(normalized, 'model', appIntel.model || value.model);
|
||||||
|
putHeader(normalized, 'channel', appIntel.channel || value.channel);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'reqImei',
|
||||||
|
appIntel['Req-Imei'] ||
|
||||||
|
appIntel.imei ||
|
||||||
|
value['Req-Imei'] ||
|
||||||
|
value['req-imei'] ||
|
||||||
|
value.reqImei
|
||||||
|
);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'origin',
|
||||||
|
sysOrigin.origin || value.sysOrigin || value.origin
|
||||||
|
);
|
||||||
|
putHeader(
|
||||||
|
normalized,
|
||||||
|
'child',
|
||||||
|
sysOrigin.originChild ||
|
||||||
|
sysOrigin.child ||
|
||||||
|
value.sysOriginChild ||
|
||||||
|
value.child
|
||||||
|
);
|
||||||
|
|
||||||
|
['headerInfo', 'headers', 'auth', 'data', 'state'].forEach(
|
||||||
|
function (key) {
|
||||||
|
Object.assign(
|
||||||
|
normalized,
|
||||||
|
normalizeHeaderCandidate(value[key], depth + 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHeadersFromApp(rawOrObject) {
|
||||||
|
var data = normalizeHeaderCandidate(rawOrObject || {});
|
||||||
|
var next = {};
|
||||||
|
if (data.authorization) {
|
||||||
|
next.authorization = normalizeAuthorization(data.authorization);
|
||||||
|
}
|
||||||
|
if (data.reqLang) next['req-lang'] = data.reqLang;
|
||||||
|
if (
|
||||||
|
data.appVersion ||
|
||||||
|
data.buildVersion ||
|
||||||
|
data.model ||
|
||||||
|
data.channel
|
||||||
|
) {
|
||||||
|
next['req-app-intel'] = [
|
||||||
|
data.appVersion ? 'version=' + data.appVersion : '',
|
||||||
|
data.buildVersion ? 'build=' + data.buildVersion : '',
|
||||||
|
data.model ? 'model=' + data.model : '',
|
||||||
|
data.channel ? 'channel=' + data.channel : '',
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(';');
|
||||||
|
}
|
||||||
|
if (data.reqImei) next['req-imei'] = data.reqImei;
|
||||||
|
if (data.origin) {
|
||||||
|
next['req-sys-origin'] = [
|
||||||
|
'origin=' + data.origin,
|
||||||
|
'originChild=' + (data.child || data.origin),
|
||||||
|
].join(';');
|
||||||
|
}
|
||||||
|
headers = Object.assign(headers, next);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function discoverQueryHeaders() {
|
||||||
|
return {
|
||||||
|
authorization:
|
||||||
|
query('authorization') ||
|
||||||
|
query('Authorization') ||
|
||||||
|
query('token') ||
|
||||||
|
query('accessToken') ||
|
||||||
|
query('access_token'),
|
||||||
|
reqLang: query('lang') || query('language') || query('locale'),
|
||||||
|
origin: query('sysOrigin') || query('origin') || DEFAULT_ORIGIN,
|
||||||
|
child:
|
||||||
|
query('sysOriginChild') ||
|
||||||
|
query('originChild') ||
|
||||||
|
DEFAULT_ORIGIN,
|
||||||
|
channel: query('channel') || query('appChannel'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStorageHeaders(storage) {
|
||||||
|
var collected = {};
|
||||||
|
if (!storage) return collected;
|
||||||
|
[
|
||||||
|
'authorization',
|
||||||
|
'Authorization',
|
||||||
|
'token',
|
||||||
|
'accessToken',
|
||||||
|
'headerInfo',
|
||||||
|
'headersFromApp',
|
||||||
|
'appHeaders',
|
||||||
|
'user',
|
||||||
|
'userInfo',
|
||||||
|
].forEach(function (key) {
|
||||||
|
try {
|
||||||
|
Object.assign(
|
||||||
|
collected,
|
||||||
|
normalizeHeaderCandidate(storage.getItem(key))
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
return collected;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDiscoveredHeaders() {
|
||||||
|
setHeadersFromApp(discoverQueryHeaders());
|
||||||
|
setHeadersFromApp(window.__APP_HEADERS__);
|
||||||
|
setHeadersFromApp(window.__HEADER_INFO__);
|
||||||
|
setHeadersFromApp(window.headerInfo);
|
||||||
|
try {
|
||||||
|
setHeadersFromApp(readStorageHeaders(window.localStorage));
|
||||||
|
setHeadersFromApp(readStorageHeaders(window.sessionStorage));
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureAslanAppCode() {
|
||||||
|
document.documentElement.dataset.hyAppCode = APP_CODE;
|
||||||
|
var params = currentParams();
|
||||||
|
if (
|
||||||
|
params.get('app_code') ||
|
||||||
|
params.get('app') ||
|
||||||
|
params.get('appCode') ||
|
||||||
|
!window.history ||
|
||||||
|
!window.history.replaceState
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var url = new URL(window.location.href);
|
||||||
|
url.searchParams.set('app_code', APP_CODE);
|
||||||
|
window.history.replaceState(null, '', url.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAppEnvironment() {
|
||||||
|
return Boolean(
|
||||||
|
window.app ||
|
||||||
|
window.FlutterApp ||
|
||||||
|
window.FlutterPageControl ||
|
||||||
|
window.webkit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestAccessOrigin() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var settled = false;
|
||||||
|
var timeoutId = null;
|
||||||
|
function finish(raw) {
|
||||||
|
if (raw) setHeadersFromApp(raw);
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
if (timeoutId) window.clearTimeout(timeoutId);
|
||||||
|
resolve(raw || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.renderData = finish;
|
||||||
|
window.getIosAccessOriginParam = finish;
|
||||||
|
|
||||||
|
if (!isAppEnvironment()) {
|
||||||
|
finish(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aslan Flutter 在页面完成后注入 window.app.getAccessOrigin;这里轮询短时间等待,避免首屏请求早于注入而丢登录态。
|
||||||
|
if (
|
||||||
|
window.app &&
|
||||||
|
typeof window.app.getAccessOrigin === 'function'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
finish(window.app.getAccessOrigin());
|
||||||
|
return;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
window.FlutterApp &&
|
||||||
|
typeof window.FlutterApp.postMessage === 'function'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
window.FlutterApp.postMessage('requestAccessOrigin');
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var attempt = 0;
|
||||||
|
var poll = function () {
|
||||||
|
attempt += 1;
|
||||||
|
if (
|
||||||
|
window.app &&
|
||||||
|
typeof window.app.getAccessOrigin === 'function'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
finish(window.app.getAccessOrigin());
|
||||||
|
return;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
if (!settled && attempt < 30) window.setTimeout(poll, 80);
|
||||||
|
};
|
||||||
|
poll();
|
||||||
|
timeoutId = window.setTimeout(function () {
|
||||||
|
finish(null);
|
||||||
|
}, 2400);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectToApp() {
|
||||||
|
if (readyPromise) return readyPromise;
|
||||||
|
ensureAslanAppCode();
|
||||||
|
applyDiscoveredHeaders();
|
||||||
|
readyPromise = requestAccessOrigin().then(function () {
|
||||||
|
return {
|
||||||
|
baseURL: baseURL(),
|
||||||
|
headers: Object.assign({}, headers),
|
||||||
|
authenticated: Boolean(headers.authorization),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return readyPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseResponse(response) {
|
||||||
|
return response.text().then(function (text) {
|
||||||
|
var payload = text ? JSON.parse(text) : {};
|
||||||
|
if (!response.ok) {
|
||||||
|
var httpError = new Error(
|
||||||
|
payload.message ||
|
||||||
|
payload.errorMsg ||
|
||||||
|
response.statusText ||
|
||||||
|
'request_failed'
|
||||||
|
);
|
||||||
|
httpError.status = response.status;
|
||||||
|
httpError.payload = payload;
|
||||||
|
throw httpError;
|
||||||
|
}
|
||||||
|
if (payload && payload.status === false) {
|
||||||
|
var apiError = new Error(
|
||||||
|
payload.message ||
|
||||||
|
payload.errorMsg ||
|
||||||
|
payload.error ||
|
||||||
|
'api_request_failed'
|
||||||
|
);
|
||||||
|
apiError.payload = payload;
|
||||||
|
apiError.code = payload.errorCode || payload.code;
|
||||||
|
throw apiError;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
payload &&
|
||||||
|
Object.prototype.hasOwnProperty.call(payload, 'body')
|
||||||
|
) {
|
||||||
|
return payload.body;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
payload &&
|
||||||
|
Object.prototype.hasOwnProperty.call(payload, 'data')
|
||||||
|
) {
|
||||||
|
return payload.data;
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function request(path, options) {
|
||||||
|
var opts = options || {};
|
||||||
|
var body = opts.body;
|
||||||
|
if (body && typeof body === 'object' && !(body instanceof FormData)) {
|
||||||
|
body = JSON.stringify(body);
|
||||||
|
}
|
||||||
|
return connectToApp().then(function () {
|
||||||
|
var requestHeaders = Object.assign({}, headers, opts.headers || {});
|
||||||
|
if (!requestHeaders.authorization)
|
||||||
|
delete requestHeaders.authorization;
|
||||||
|
if (body) {
|
||||||
|
requestHeaders['content-type'] =
|
||||||
|
requestHeaders['content-type'] || 'application/json';
|
||||||
|
}
|
||||||
|
return window
|
||||||
|
.fetch(buildURL(path, opts.query), {
|
||||||
|
method: opts.method || 'GET',
|
||||||
|
headers: requestHeaders,
|
||||||
|
body: body,
|
||||||
|
credentials: 'omit',
|
||||||
|
cache: 'no-store',
|
||||||
|
})
|
||||||
|
.then(parseResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function back() {
|
||||||
|
if (
|
||||||
|
window.FlutterPageControl &&
|
||||||
|
window.FlutterPageControl.postMessage
|
||||||
|
) {
|
||||||
|
window.FlutterPageControl.postMessage('close_page');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (window.HyAppBridge && window.HyAppBridge.back) {
|
||||||
|
window.HyAppBridge.back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.AslanCommon = {
|
||||||
|
baseURL: baseURL,
|
||||||
|
buildURL: buildURL,
|
||||||
|
headers: function () {
|
||||||
|
return Object.assign({}, headers);
|
||||||
|
},
|
||||||
|
connectToApp: connectToApp,
|
||||||
|
setHeadersFromApp: setHeadersFromApp,
|
||||||
|
request: request,
|
||||||
|
get: function (path, queryData) {
|
||||||
|
return request(path, { method: 'GET', query: queryData });
|
||||||
|
},
|
||||||
|
post: function (path, body, queryData) {
|
||||||
|
return request(path, {
|
||||||
|
method: 'POST',
|
||||||
|
body: body,
|
||||||
|
query: queryData,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
back: back,
|
||||||
|
user: {
|
||||||
|
profile: function () {
|
||||||
|
return request('/user/user-profile/user-id', { method: 'GET' });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rechargeReward: {
|
||||||
|
status: function () {
|
||||||
|
return request(
|
||||||
|
'/activity/cumulative-recharge/recharge-reward',
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
claim: function (ruleId) {
|
||||||
|
return request('/activity/cumulative-recharge', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { id: String(ruleId || '') },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -701,9 +701,15 @@
|
|||||||
: Array.isArray(source)
|
: Array.isArray(source)
|
||||||
? source
|
? source
|
||||||
: [];
|
: [];
|
||||||
return items.map(function (item, index) {
|
return items
|
||||||
return normalizeSubSeller(item, index);
|
.map(function (item, index) {
|
||||||
});
|
return normalizeSubSeller(item, index);
|
||||||
|
})
|
||||||
|
.filter(function (item) {
|
||||||
|
var status = String(item.status || '').toLowerCase();
|
||||||
|
// 列表接口的服务端契约只返回 active 直属关系;这里再过滤一次,避免异常数据把 pending 申请展示成可转账子币商。
|
||||||
|
return !status || status === 'active';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyMockData() {
|
function applyMockData() {
|
||||||
@ -1301,6 +1307,14 @@
|
|||||||
function inviteSubSeller() {
|
function inviteSubSeller() {
|
||||||
var input = $('inviteSubSellerInput');
|
var input = $('inviteSubSellerInput');
|
||||||
var displayID = String(input.value || '').trim();
|
var displayID = String(input.value || '').trim();
|
||||||
|
if (!data.subSellerPermission.canInvite) {
|
||||||
|
setStatus(
|
||||||
|
$('inviteSubSellerStatus'),
|
||||||
|
t('coinseller_center.invite_failed', 'Invite failed.'),
|
||||||
|
'warning'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!displayID) {
|
if (!displayID) {
|
||||||
setStatus(
|
setStatus(
|
||||||
$('inviteSubSellerStatus'),
|
$('inviteSubSellerStatus'),
|
||||||
@ -1310,22 +1324,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state.isMock) {
|
if (state.isMock) {
|
||||||
data.subSellers.unshift({
|
|
||||||
uid: displayID,
|
|
||||||
userId: displayID,
|
|
||||||
name: t(
|
|
||||||
'coinseller_center.user_name_template',
|
|
||||||
'User {id}'
|
|
||||||
).replace('{id}', displayID),
|
|
||||||
avatar: avatarData(displayID, '#efe4ff', '#7d57c7'),
|
|
||||||
status: 'active',
|
|
||||||
balance: 0,
|
|
||||||
});
|
|
||||||
input.value = '';
|
input.value = '';
|
||||||
renderSubSellers();
|
|
||||||
closeModal('inviteSubSellerModal');
|
closeModal('inviteSubSellerModal');
|
||||||
toast(
|
toast(
|
||||||
t('coinseller_center.invite_success', 'Invitation submitted.')
|
t(
|
||||||
|
'coinseller_center.invite_success',
|
||||||
|
'Official will review your invitation within 24 hours.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1345,41 +1350,27 @@
|
|||||||
t('coinseller_center.loading', 'Loading...'),
|
t('coinseller_center.loading', 'Loading...'),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
// 直开子币商是有状态写操作,必须使用 command_id 让移动端重试或重复点击时由服务端保持幂等。
|
// 邀请子币商现在只创建待审核申请;command_id 保证移动端重试不会重复生成多个 pending 申请。
|
||||||
window.HyAppAPI.wallet
|
window.HyAppAPI.wallet
|
||||||
.inviteCoinSellerSubSeller({
|
.inviteCoinSellerSubSeller({
|
||||||
command_id: subSellerCommandID('invite'),
|
command_id: subSellerCommandID('invite'),
|
||||||
target_display_user_id: displayID,
|
target_display_user_id: displayID,
|
||||||
})
|
})
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
var payload = unwrapData(response) || {};
|
|
||||||
var seller = normalizeSubSeller(
|
|
||||||
payload.child ||
|
|
||||||
payload.sub_seller ||
|
|
||||||
payload.subSeller ||
|
|
||||||
payload,
|
|
||||||
data.subSellers.length
|
|
||||||
);
|
|
||||||
if (seller.uid) {
|
|
||||||
data.subSellers = data.subSellers.filter(function (item) {
|
|
||||||
return String(item.uid) !== String(seller.uid);
|
|
||||||
});
|
|
||||||
data.subSellers.unshift(seller);
|
|
||||||
}
|
|
||||||
input.value = '';
|
input.value = '';
|
||||||
setStatus(
|
setStatus(
|
||||||
$('inviteSubSellerStatus'),
|
$('inviteSubSellerStatus'),
|
||||||
t(
|
t(
|
||||||
'coinseller_center.invite_success',
|
'coinseller_center.invite_success',
|
||||||
'Invitation submitted.'
|
'Official will review your invitation within 24 hours.'
|
||||||
),
|
),
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
renderSubSellers();
|
// 申请提交成功不代表父子关系已经生效,列表必须继续以服务端 active 关系为准。
|
||||||
toast(
|
toast(
|
||||||
t(
|
t(
|
||||||
'coinseller_center.invite_success',
|
'coinseller_center.invite_success',
|
||||||
'Invitation submitted.'
|
'Official will review your invitation within 24 hours.'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
closeModal('inviteSubSellerModal');
|
closeModal('inviteSubSellerModal');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user