diff --git a/activity/agency-opening/script.js b/activity/agency-opening/script.js index 6250507..84b001a 100644 --- a/activity/agency-opening/script.js +++ b/activity/agency-opening/script.js @@ -110,6 +110,8 @@ data.qualification || data.qualifications || data.agency || {}; var record = data.record || data.opening_record || data.openingRecord || {}; + var application = + data.application || data.opening_application || data.openingApplication || {}; var joined = Boolean( firstValue(data, ['joined', 'has_joined', 'hasJoined'], false) ); @@ -197,7 +199,20 @@ ['reward', 'reward_coins', 'rewardCoins'], '500K' ), + scoreEndMS: + Number( + firstValue( + record, + ['score_end_ms', 'scoreEndMs'], + firstValue( + application, + ['score_end_ms', 'scoreEndMs'], + 0 + ) + ) + ) || 0, }, + application: application, joined: joined, }; } @@ -368,7 +383,10 @@ : Promise.resolve({ joined: true, qualification: { - opening_status: t('agencyOpening.joined', 'Joined'), + opening_status: t( + 'agencyOpening.pendingReview', + 'Pending Review' + ), }, }); @@ -388,13 +406,9 @@ 'status_text', 'statusText', ], - t('agencyOpening.joined', 'Joined') + t('agencyOpening.pendingReview', 'Pending Review') ), }); - next.qualification.openingStatus = t( - 'agencyOpening.joined', - 'Joined' - ); next.qualification.eligible = false; applyStatus(next); showToast( diff --git a/activity/wheel/assets/other/advanced_gift.webp b/activity/wheel/assets/other/advanced_gift.webp new file mode 100644 index 0000000..ae03cc0 Binary files /dev/null and b/activity/wheel/assets/other/advanced_gift.webp differ diff --git a/activity/wheel/assets/other/christmasCheckIn_lottery_bg.png b/activity/wheel/assets/other/christmasCheckIn_lottery_bg.png new file mode 100644 index 0000000..6dfd208 Binary files /dev/null and b/activity/wheel/assets/other/christmasCheckIn_lottery_bg.png differ diff --git a/activity/wheel/assets/other/christmasCheckIn_lottery_go.png b/activity/wheel/assets/other/christmasCheckIn_lottery_go.png new file mode 100644 index 0000000..c29bb8e Binary files /dev/null and b/activity/wheel/assets/other/christmasCheckIn_lottery_go.png differ diff --git a/activity/wheel/assets/other/christmasCheckIn_lottery_select.png b/activity/wheel/assets/other/christmasCheckIn_lottery_select.png new file mode 100644 index 0000000..506e7af Binary files /dev/null and b/activity/wheel/assets/other/christmasCheckIn_lottery_select.png differ diff --git a/activity/wheel/assets/other/christmasCheckIn_lottery_unselect.png b/activity/wheel/assets/other/christmasCheckIn_lottery_unselect.png new file mode 100644 index 0000000..6b2e631 Binary files /dev/null and b/activity/wheel/assets/other/christmasCheckIn_lottery_unselect.png differ diff --git a/activity/wheel/assets/other/gold.png b/activity/wheel/assets/other/gold.png new file mode 100644 index 0000000..0da2270 Binary files /dev/null and b/activity/wheel/assets/other/gold.png differ diff --git a/activity/wheel/assets/other/gold_new.png b/activity/wheel/assets/other/gold_new.png new file mode 100644 index 0000000..843642b Binary files /dev/null and b/activity/wheel/assets/other/gold_new.png differ diff --git a/activity/wheel/assets/other/lucky_box_back.png b/activity/wheel/assets/other/lucky_box_back.png new file mode 100644 index 0000000..9f356b7 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_back.png differ diff --git a/activity/wheel/assets/other/lucky_box_bg_new.png b/activity/wheel/assets/other/lucky_box_bg_new.png new file mode 100644 index 0000000..6fec5b8 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_bg_new.png differ diff --git a/activity/wheel/assets/other/lucky_box_bottom.png b/activity/wheel/assets/other/lucky_box_bottom.png new file mode 100644 index 0000000..10eabfb Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_bottom.png differ diff --git a/activity/wheel/assets/other/lucky_box_btn.png b/activity/wheel/assets/other/lucky_box_btn.png new file mode 100644 index 0000000..8c59b96 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_btn.png differ diff --git a/activity/wheel/assets/other/lucky_box_center.png b/activity/wheel/assets/other/lucky_box_center.png new file mode 100644 index 0000000..ed7a4df Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_center.png differ diff --git a/activity/wheel/assets/other/lucky_box_close.png b/activity/wheel/assets/other/lucky_box_close.png new file mode 100644 index 0000000..f6f01b9 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_close.png differ diff --git a/activity/wheel/assets/other/lucky_box_defalute.png b/activity/wheel/assets/other/lucky_box_defalute.png new file mode 100644 index 0000000..b3de5e0 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_defalute.png differ diff --git a/activity/wheel/assets/other/lucky_box_go.png b/activity/wheel/assets/other/lucky_box_go.png new file mode 100644 index 0000000..7ffb4bd Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_go.png differ diff --git a/activity/wheel/assets/other/lucky_box_gold.png b/activity/wheel/assets/other/lucky_box_gold.png new file mode 100644 index 0000000..8ee9a08 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_gold.png differ diff --git a/activity/wheel/assets/other/lucky_box_light.png b/activity/wheel/assets/other/lucky_box_light.png new file mode 100644 index 0000000..de4d681 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_light.png differ diff --git a/activity/wheel/assets/other/lucky_box_light2.png b/activity/wheel/assets/other/lucky_box_light2.png new file mode 100644 index 0000000..7d789f7 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_light2.png differ diff --git a/activity/wheel/assets/other/lucky_box_middle.png b/activity/wheel/assets/other/lucky_box_middle.png new file mode 100644 index 0000000..b03c44a Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_middle.png differ diff --git a/activity/wheel/assets/other/lucky_box_reward.png b/activity/wheel/assets/other/lucky_box_reward.png new file mode 100644 index 0000000..a1909c5 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_reward.png differ diff --git a/activity/wheel/assets/other/lucky_box_reward_bg.png b/activity/wheel/assets/other/lucky_box_reward_bg.png new file mode 100644 index 0000000..8ae7295 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_reward_bg.png differ diff --git a/activity/wheel/assets/other/lucky_box_rule.png b/activity/wheel/assets/other/lucky_box_rule.png new file mode 100644 index 0000000..ae9030f Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_rule.png differ diff --git a/activity/wheel/assets/other/lucky_box_select.png b/activity/wheel/assets/other/lucky_box_select.png new file mode 100644 index 0000000..5c15814 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_select.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_bg_new.png b/activity/wheel/assets/other/lucky_box_three_bg_new.png new file mode 100644 index 0000000..4cf9d9b Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_bg_new.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_btn.png b/activity/wheel/assets/other/lucky_box_three_btn.png new file mode 100644 index 0000000..80a97c8 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_btn.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_default.png b/activity/wheel/assets/other/lucky_box_three_default.png new file mode 100644 index 0000000..1367459 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_default.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_go.png b/activity/wheel/assets/other/lucky_box_three_go.png new file mode 100644 index 0000000..92a80d9 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_go.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_gold.png b/activity/wheel/assets/other/lucky_box_three_gold.png new file mode 100644 index 0000000..7e543ea Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_gold.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_history.png b/activity/wheel/assets/other/lucky_box_three_history.png new file mode 100644 index 0000000..4dfb8e3 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_history.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_notice.png b/activity/wheel/assets/other/lucky_box_three_notice.png new file mode 100644 index 0000000..e81b96e Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_notice.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_reward_bg.png b/activity/wheel/assets/other/lucky_box_three_reward_bg.png new file mode 100644 index 0000000..b799b9e Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_reward_bg.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_rule.png b/activity/wheel/assets/other/lucky_box_three_rule.png new file mode 100644 index 0000000..7aad68e Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_rule.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_select.png b/activity/wheel/assets/other/lucky_box_three_select.png new file mode 100644 index 0000000..c273f75 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_select.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_unbtn.png b/activity/wheel/assets/other/lucky_box_three_unbtn.png new file mode 100644 index 0000000..1bbc15b Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_unbtn.png differ diff --git a/activity/wheel/assets/other/lucky_box_three_unselect.png b/activity/wheel/assets/other/lucky_box_three_unselect.png new file mode 100644 index 0000000..be74d2a Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_three_unselect.png differ diff --git a/activity/wheel/assets/other/lucky_box_title_top.png b/activity/wheel/assets/other/lucky_box_title_top.png new file mode 100644 index 0000000..0ad9136 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_title_top.png differ diff --git a/activity/wheel/assets/other/lucky_box_top.png b/activity/wheel/assets/other/lucky_box_top.png new file mode 100644 index 0000000..a3428b1 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_top.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_bg_new.png b/activity/wheel/assets/other/lucky_box_tow_bg_new.png new file mode 100644 index 0000000..5cb3c25 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_bg_new.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_btn1.png b/activity/wheel/assets/other/lucky_box_tow_btn1.png new file mode 100644 index 0000000..2332af7 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_btn1.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_btn2.png b/activity/wheel/assets/other/lucky_box_tow_btn2.png new file mode 100644 index 0000000..eb6fb1f Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_btn2.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_btn3.png b/activity/wheel/assets/other/lucky_box_tow_btn3.png new file mode 100644 index 0000000..d0e5b22 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_btn3.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_default.png b/activity/wheel/assets/other/lucky_box_tow_default.png new file mode 100644 index 0000000..b781e9c Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_default.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_gold.png b/activity/wheel/assets/other/lucky_box_tow_gold.png new file mode 100644 index 0000000..9878254 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_gold.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_light.png b/activity/wheel/assets/other/lucky_box_tow_light.png new file mode 100644 index 0000000..0582b0b Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_light.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_light2.png b/activity/wheel/assets/other/lucky_box_tow_light2.png new file mode 100644 index 0000000..0fe03a4 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_light2.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_middle.png b/activity/wheel/assets/other/lucky_box_tow_middle.png new file mode 100644 index 0000000..0d8eeed Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_middle.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_notice.png b/activity/wheel/assets/other/lucky_box_tow_notice.png new file mode 100644 index 0000000..58af24b Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_notice.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_pointer.png b/activity/wheel/assets/other/lucky_box_tow_pointer.png new file mode 100644 index 0000000..d525716 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_pointer.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward.png b/activity/wheel/assets/other/lucky_box_tow_reward.png new file mode 100644 index 0000000..e32bcf1 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_bg.png b/activity/wheel/assets/other/lucky_box_tow_reward_bg.png new file mode 100644 index 0000000..3fa0f95 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_bg.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_bottom.png b/activity/wheel/assets/other/lucky_box_tow_reward_bottom.png new file mode 100644 index 0000000..d1e461a Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_bottom.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_center.png b/activity/wheel/assets/other/lucky_box_tow_reward_center.png new file mode 100644 index 0000000..54a4b2f Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_center.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_desc.png b/activity/wheel/assets/other/lucky_box_tow_reward_desc.png new file mode 100644 index 0000000..937ce34 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_desc.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_top.png b/activity/wheel/assets/other/lucky_box_tow_reward_top.png new file mode 100644 index 0000000..744ffe9 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_top.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_reward_yuan.png b/activity/wheel/assets/other/lucky_box_tow_reward_yuan.png new file mode 100644 index 0000000..cac2161 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_reward_yuan.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_rule.png b/activity/wheel/assets/other/lucky_box_tow_rule.png new file mode 100644 index 0000000..caeec4d Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_rule.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_rule_top.png b/activity/wheel/assets/other/lucky_box_tow_rule_top.png new file mode 100644 index 0000000..2ca2ac1 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_rule_top.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_turntable.png b/activity/wheel/assets/other/lucky_box_tow_turntable.png new file mode 100644 index 0000000..64ba704 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_turntable.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_unbtn1.png b/activity/wheel/assets/other/lucky_box_tow_unbtn1.png new file mode 100644 index 0000000..ecb2169 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_unbtn1.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_unbtn2.png b/activity/wheel/assets/other/lucky_box_tow_unbtn2.png new file mode 100644 index 0000000..6d0e4ed Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_unbtn2.png differ diff --git a/activity/wheel/assets/other/lucky_box_tow_unbtn3.png b/activity/wheel/assets/other/lucky_box_tow_unbtn3.png new file mode 100644 index 0000000..9f797bd Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_tow_unbtn3.png differ diff --git a/activity/wheel/assets/other/lucky_box_unbtn.png b/activity/wheel/assets/other/lucky_box_unbtn.png new file mode 100644 index 0000000..716d222 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_unbtn.png differ diff --git a/activity/wheel/assets/other/lucky_box_unselect.png b/activity/wheel/assets/other/lucky_box_unselect.png new file mode 100644 index 0000000..e2eb8d9 Binary files /dev/null and b/activity/wheel/assets/other/lucky_box_unselect.png differ diff --git a/activity/wheel/index.html b/activity/wheel/index.html new file mode 100644 index 0000000..4c2c0ee --- /dev/null +++ b/activity/wheel/index.html @@ -0,0 +1,423 @@ + + + + + + Yumi Wheel + + + + +
+
+
+ {{ common('loading') }} +
+
+ + +
+
+
+
+ + {{ replaceTwo('userAward', + item.nickname, item.value) }} +
+
+
+
+
+
+
+ + {{ replaceTwo('userAward', item.nickname, + item.value) }} +
+
+
+ +
+
+ +
+
+
+
+ +
+ {{ item.value }} +
+
+
+
+ + + +
+ {{ common('rewardUnavailable') }} +
+ + +
+
+
+ +
+ +
+ +
+ + +
+
+ {{ + userBalance }} +
+
+ +
+
+ +
{{ common('rule') }}
+
+
+

{{ t('rule1') }}

+

{{ t('rule2') }}

+

{{ t('rule3') }}

+
+
+
+
+ +
+ +
+ +
+
+
+
{{ common('rewards') }}
+ +
+
+
+
+ +
+ X{{ item.count }} +
+
+ + +
+
+
+ +
+ +
+ +
+
+
+
+
+ + + + + + + + + diff --git a/activity/wheel/script.js b/activity/wheel/script.js new file mode 100644 index 0000000..480b775 --- /dev/null +++ b/activity/wheel/script.js @@ -0,0 +1,1355 @@ +(function () { + var ASSET_BASE = './assets/other/'; + var COMMON_FALLBACK = { + loading: 'Loading', + rule: 'rule', + rewards: 'Rewards', + balance: 'Balance', + noDate: 'No more data', + balanceNotEnough: 'Insufficient balance', + rewardUnavailable: 'Rewards are not available yet', + requestFailed: 'Request failed', + }; + var WHEEL_FALLBACK = { + classic: 'Classic', + inLove: 'luxury', + advanced: 'Advanced', + historyRecord: 'History Record', + rewardTips: + 'Congratulations on receiving: A precious gift worth {} gold coins! Already put in the backpack', + drawAgain: 'Draw again', + userAward: 'Congratulations to {1} for receiving the {2} award', + rule1: '1. Select a wheel and draw with coins.', + rule2: '2. Rewards are issued to the backpack after a successful draw.', + rule3: '3. This activity has no relationship with Apple or Google.', + }; + var TABS = [ + { key: 'classic', labelKey: 'classic' }, + { key: 'luxury', labelKey: 'inLove' }, + { key: 'advanced', labelKey: 'advanced' }, + ]; + var CONFIGS = { + classic: { + key: 'classic', + amountKey: 'luckyBoxDrawAmount', + enabledKey: 'luckyBoxEnabled', + pageSize: 10, + type: 'grid', + gridClass: 'grid-classic', + stageClass: 'wheel-classic', + lightPrefix: 'lucky_box_', + minSpeed: 2000, + sequence: [1, 2, 3, 5, 8, 7, 6, 4, 1, 2, 3, 5, 8, 7, 6, 4, 1], + }, + luxury: { + key: 'luxury', + amountKey: 'middleLuckyBoxDrawAmount', + enabledKey: 'middleLuckyBoxEnabled', + pageSize: 20, + type: 'round', + gridClass: 'grid-luxury', + stageClass: 'wheel-luxury', + lightPrefix: 'lucky_box_tow_', + hasMarqueeBox: true, + }, + advanced: { + key: 'advanced', + amountKey: 'advancedLuckyBoxDrawAmount', + enabledKey: 'advancedLuckyBoxEnabled', + pageSize: 10, + type: 'grid', + gridClass: 'grid-advanced', + stageClass: 'wheel-advanced', + minSpeed: 1000, + hasMarqueeBox: true, + sequence: [1, 2, 3, 4, 6, 8, 12, 11, 10, 9, 7, 5, 1], + }, + }; + + function query() { + 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 readQuery(name) { + return query().get(name) || ''; + } + + function toast(message) { + if (window.HyAppToast && window.HyAppToast.show) { + window.HyAppToast.show(message); + return; + } + window.alert(message); + } + + function stateFor() { + return { + rewards: [], + gridItems: [], + activeIndex: null, + isSpinning: false, + spinInterval: null, + spinSpeed: 50, + targetIndex: null, + goldBtn: [ + { name: '1 Time', value: 1 }, + { name: '10 Time', value: 10 }, + { name: '50 Time', value: 50 }, + ], + activeBtnIndex: 1, + showRule: false, + showRecord: false, + showReward: false, + currentReward: { rewardValue: 0, rewards: [] }, + drawAmount: 0, + historyRecord: [], + roomId: '', + loading: false, + finished: true, + pageNo: 1, + isInit: false, + pageLoading: false, + drawFailed: false, + currentBackground: 'light', + backgroundInterval: null, + rotateDeg: 0, + rotationTimer: null, + }; + } + + function envelopeData(response) { + if (response && Object.prototype.hasOwnProperty.call(response, 'data')) + return response.data; + return response; + } + + function firstPresentValue(source, keys) { + source = source || {}; + for (var index = 0; index < keys.length; index += 1) { + var value = source[keys[index]]; + if (value !== undefined && value !== null && value !== '') + return value; + } + return ''; + } + + function normalizeCompareValue(value) { + return String(value || '') + .trim() + .toLowerCase(); + } + + function resolveAssetUrl(url) { + var value = String(url || '').trim(); + if (!value) return ''; + if ( + /^(https?:)?\/\//i.test(value) || + /^(data|blob):/i.test(value) || + value.indexOf('/') === 0 || + value.indexOf('./') === 0 || + value.indexOf('../') === 0 + ) + return value; + return ASSET_BASE + value; + } + + function isDynamicAssetUrl(url) { + var clean = String(url || '') + .split('?')[0] + .split('#')[0]; + return /\.(svga|pag|mp4|webm|mov)$/i.test(clean); + } + + function positiveModulo(value, size) { + return ((value % size) + size) % size; + } + + function roundPrizeAngle(index, count) { + var sectorAngle = 360 / Math.max(1, count || 1); + // 奖品图标本身按这个角度排布,指针停止也必须使用同一个基准,否则会停在扇区中间而不是奖品上。 + return index * sectorAngle + sectorAngle / 50; + } + + function normalizeImageObject(source, keys, fallbackKey) { + var target = Object.assign({}, source || {}); + var image = firstPresentValue(target, keys); + if (image) target[fallbackKey] = resolveAssetUrl(image); + return target; + } + + function normalizeGridItem(item) { + var target = Object.assign({}, item || {}); + var merchandise = normalizeImageObject( + target.merchandise || target, + [ + 'coverUrl', + 'cover', + 'resourceCover', + 'avatar', + 'icon', + 'imageUrl', + ], + 'coverUrl' + ); + target.merchandise = merchandise; + return target; + } + + function parseJSON(value) { + if (!value || typeof value !== 'string') return {}; + try { + return JSON.parse(value); + } catch (error) { + return {}; + } + } + + function normalizeWheelReward(item) { + var target = Object.assign({}, item || {}); + var metadata = parseJSON( + firstPresentValue(target, ['metadataJson', 'metadata_json']) + ); + var rewardType = firstPresentValue(target, [ + 'rewardType', + 'reward_type', + ]); + var metadataResourceId = firstPresentValue(metadata, [ + 'resource_id', + 'resourceId', + ]); + var rewardId = + firstPresentValue(target, [ + 'rewardId', + 'reward_id', + 'resourceId', + 'resource_id', + ]) || metadataResourceId; + var metadataAssetUrl = firstPresentValue(metadata, [ + 'asset_url', + 'assetUrl', + ]); + var previewUrl = + firstPresentValue(metadata, ['preview_url', 'previewUrl']) || + (isDynamicAssetUrl(metadataAssetUrl) ? '' : metadataAssetUrl) || + firstPresentValue(target, [ + 'coverUrl', + 'cover', + 'resourceCover', + 'avatar', + 'icon', + 'imageUrl', + 'previewUrl', + 'preview_url', + ]); + var animationUrl = firstPresentValue(metadata, [ + 'animation_url', + 'animationUrl', + ]); + if ( + !isDynamicAssetUrl(animationUrl) && + isDynamicAssetUrl(metadataAssetUrl) + ) { + animationUrl = metadataAssetUrl; + } + var displayName = firstPresentValue(target, [ + 'displayName', + 'display_name', + 'name', + 'rewardName', + ]); + var rewardCoins = Number( + firstPresentValue(target, [ + 'rewardCoins', + 'reward_coins', + 'value', + ]) || 0 + ); + var displayValue = Number( + firstPresentValue(target, [ + 'displayValue', + 'display_value', + 'rewardValue', + 'reward_value', + 'value', + 'rewardCoins', + 'reward_coins', + ]) || 0 + ); + var rewardCount = Number( + firstPresentValue(target, [ + 'rewardCount', + 'reward_count', + 'count', + ]) || 1 + ); + + target.id = + firstPresentValue(target, ['id', 'tierId', 'tier_id']) || + rewardId || + displayName; + target.tierId = firstPresentValue(target, ['tierId', 'tier_id']); + target.rewardId = rewardId; + target.rewardConfigId = firstPresentValue(target, [ + 'rewardConfigId', + 'reward_config_id', + ]); + target.resourceId = + firstPresentValue(target, ['resourceId', 'resource_id']) || + metadataResourceId; + target.rewardType = rewardType; + target.value = displayValue || rewardCoins || rewardCount; + target.displayGoldAmount = target.value; + target.rewardCount = rewardCount; + target.count = rewardCount; + target.name = displayName; + target.coverUrl = resolveAssetUrl(previewUrl); + target.animationUrl = + rewardType === 'coin' ? '' : resolveAssetUrl(animationUrl); + target.merchandise = { + name: displayName, + coverUrl: target.coverUrl, + animationUrl: target.animationUrl, + }; + return normalizeGridItem(target); + } + + function normalizeWheelRewards(data) { + data = data || {}; + var items = Array.isArray(data) + ? data + : data.rewards || data.tiers || (data.config && data.config.tiers); + return Array.isArray(items) + ? items.map(normalizeWheelReward).map(normalizeGridItem) + : []; + } + + function normalizeRewardItem(item) { + var target = normalizeImageObject( + item, + [ + 'coverUrl', + 'cover', + 'resourceCover', + 'avatar', + 'icon', + 'imageUrl', + 'previewUrl', + 'preview_url', + ], + 'coverUrl' + ); + var metadata = parseJSON( + firstPresentValue(target, ['metadataJson', 'metadata_json']) + ); + var assetUrl = + firstPresentValue(metadata, ['asset_url', 'assetUrl']) || + firstPresentValue(target, ['assetUrl', 'asset_url']); + if (isDynamicAssetUrl(target.coverUrl)) target.coverUrl = ''; + if (!target.coverUrl && assetUrl && !isDynamicAssetUrl(assetUrl)) { + target.coverUrl = resolveAssetUrl(assetUrl); + } + var animationUrl = + firstPresentValue(metadata, ['animation_url', 'animationUrl']) || + firstPresentValue(target, ['animationUrl', 'animation_url']); + if (!isDynamicAssetUrl(animationUrl) && isDynamicAssetUrl(assetUrl)) { + animationUrl = assetUrl; + } + target.animationUrl = isDynamicAssetUrl(animationUrl) + ? resolveAssetUrl(animationUrl) + : ''; + return target; + } + + function rewardCountValue(item) { + var value = Number( + firstPresentValue(item, ['count', 'rewardCount', 'reward_count']) || + 0 + ); + return value > 0 ? value : 1; + } + + function rewardGroupKey(item) { + item = item || {}; + var metadata = parseJSON( + firstPresentValue(item, ['metadataJson', 'metadata_json']) + ); + var metadataResourceId = firstPresentValue(metadata, [ + 'resource_id', + 'resourceId', + ]); + return [ + firstPresentValue(item, [ + 'resourceId', + 'resource_id', + 'rewardId', + 'reward_id', + 'id', + ]) || metadataResourceId, + firstPresentValue(item, [ + 'rewardType', + 'reward_type', + 'resourceType', + 'resource_type', + ]) || + firstPresentValue(metadata, ['resource_type', 'resourceType']), + firstPresentValue(item, ['animationUrl', 'animation_url']), + firstPresentValue(item, [ + 'coverUrl', + 'cover_url', + 'previewUrl', + 'preview_url', + 'cover', + ]), + firstPresentValue(item, [ + 'name', + 'displayName', + 'display_name', + 'rewardName', + 'reward_name', + ]), + rewardDisplayValue(item), + ] + .map(function (value) { + return normalizeCompareValue(value); + }) + .join('|'); + } + + function aggregateRewardItems(items) { + var map = {}; + var list = []; + (items || []).forEach(function (item) { + var key = rewardGroupKey(item); + var count = rewardCountValue(item); + if (!map[key]) { + map[key] = Object.assign({}, item, { + count: 0, + rewardCount: 0, + }); + list.push(map[key]); + } + map[key].count += count; + map[key].rewardCount = map[key].count; + }); + return list; + } + + function normalizeHistoryRecord(record) { + var target = Object.assign({}, record || {}); + var rewards = Array.isArray(target.rewards) ? target.rewards : []; + target.rewards = rewards.map(normalizeRewardItem); + return target; + } + + function normalizeHintItem(item) { + return normalizeImageObject( + item, + [ + 'avatar', + 'coverUrl', + 'cover', + 'resourceCover', + 'icon', + 'imageUrl', + ], + 'avatar' + ); + } + + function prizePreviewSource(item) { + item = item || {}; + var merchandise = item.merchandise || {}; + var assetUrl = + firstPresentValue(merchandise, ['assetUrl', 'asset_url']) || + firstPresentValue(item, ['assetUrl', 'asset_url']); + var animationUrl = + firstPresentValue(merchandise, ['animationUrl', 'animation_url']) || + firstPresentValue(item, ['animationUrl', 'animation_url']); + if (!isDynamicAssetUrl(animationUrl) && isDynamicAssetUrl(assetUrl)) { + animationUrl = assetUrl; + } + var coverUrl = + firstPresentValue(merchandise, [ + 'coverUrl', + 'cover', + 'previewUrl', + 'preview_url', + ]) || + firstPresentValue(item, [ + 'coverUrl', + 'cover', + 'resourceCover', + 'previewUrl', + 'preview_url', + 'avatar', + 'icon', + 'imageUrl', + ]) || + (isDynamicAssetUrl(assetUrl) ? '' : assetUrl); + animationUrl = resolveAssetUrl(animationUrl); + return { + animationUrl: isDynamicAssetUrl(animationUrl) ? animationUrl : '', + coverUrl: resolveAssetUrl(coverUrl), + }; + } + + function normalizeDrawResult(data) { + var target = Object.assign({ rewardValue: 0, rewards: [] }, data || {}); + var rewards = Array.isArray(target.rewards) ? target.rewards : []; + target.rawRewards = rewards.slice(); + if ( + rewards.length === 0 && + firstPresentValue(target, [ + 'selectedTierId', + 'selected_tier_id', + 'rewardType', + 'reward_type', + 'rewardId', + 'reward_id', + ]) + ) { + rewards = [normalizeWheelReward(target)]; + target.rawRewards = [Object.assign({}, data || {})]; + } + target.rewards = rewards + .map(normalizeWheelReward) + .map(normalizeRewardItem); + target.rewards = aggregateRewardItems(target.rewards); + if (target.rewards.length > 0) { + var aggregateValue = target.rewards.reduce(function (sum, item) { + return sum + rewardDisplayValue(item) * rewardCountValue(item); + }, 0); + if (aggregateValue > 0) target.rewardValue = aggregateValue; + } + return target; + } + + function normalizeWalletBalance(payload) { + var data = envelopeData(payload) || {}; + var list = Array.isArray(data) + ? data + : data.balances || data.values || data.list || []; + var info = Array.isArray(list) + ? list.find(function (item) { + var type = firstPresentValue(item, [ + 'asset_type', + 'assetType', + 'walletType', + 'type', + ]); + return String(type || '').toUpperCase() === 'COIN'; + }) + : null; + return info + ? Number( + firstPresentValue(info, [ + 'available_amount', + 'availableAmount', + 'balance', + 'amount', + ]) || 0 + ) + : 0; + } + + function createCommandID(prefix) { + var random = ''; + if (window.crypto && window.crypto.getRandomValues) { + var values = new Uint32Array(2); + window.crypto.getRandomValues(values); + random = values[0].toString(36) + values[1].toString(36); + } else { + random = Math.random().toString(36).slice(2); + } + return ( + String(prefix || 'wheel') + + '_' + + Date.now().toString(36) + + '_' + + random + ); + } + + function firstDrawReward(drawResult) { + drawResult = drawResult || {}; + if ( + Array.isArray(drawResult.rawRewards) && + drawResult.rawRewards.length > 0 + ) + return drawResult.rawRewards[0]; + if (Array.isArray(drawResult.records) && drawResult.records.length > 0) + return drawResult.records[0]; + if (Array.isArray(drawResult.rewards) && drawResult.rewards.length > 0) + return drawResult.rewards[0]; + return null; + } + + function rewardDisplayValue(reward) { + return Number( + firstPresentValue(reward, [ + 'value', + 'displayGoldAmount', + 'goldAmount', + 'rewardValue', + 'amount', + ]) || 0 + ); + } + + function gridItemDisplayValue(item) { + return Number( + firstPresentValue(item, [ + 'value', + 'displayGoldAmount', + 'goldAmount', + ]) || 0 + ); + } + + function resolveRewardTargetIndex(gridItems, drawResult) { + var reward = firstDrawReward(drawResult); + if (!reward || !Array.isArray(gridItems) || gridItems.length === 0) + return 0; + var rewardMetadata = parseJSON( + firstPresentValue(reward, ['metadataJson', 'metadata_json']) + ); + var metadataResourceId = firstPresentValue(rewardMetadata, [ + 'resource_id', + 'resourceId', + ]); + var rewardId = normalizeCompareValue( + firstPresentValue(reward, [ + 'id', + 'tierId', + 'tier_id', + 'selectedTierId', + 'selected_tier_id', + 'rewardId', + 'reward_id', + 'rewardConfigId', + 'reward_config_id', + 'resourceId', + 'resource_id', + ]) || metadataResourceId + ); + var rewardName = normalizeCompareValue( + firstPresentValue(reward, [ + 'name', + 'resourceName', + 'resource_name', + 'rewardName', + 'reward_name', + ]) || + firstPresentValue(rewardMetadata, [ + 'resource_name', + 'resourceName', + 'resource_code', + 'resourceCode', + ]) + ); + var rewardCover = normalizeCompareValue( + firstPresentValue(reward, [ + 'coverUrl', + 'cover_url', + 'cover', + 'resourceCover', + 'resource_cover', + 'previewUrl', + 'preview_url', + ]) || + firstPresentValue(rewardMetadata, [ + 'preview_url', + 'previewUrl', + 'asset_url', + 'assetUrl', + ]) + ); + var rewardValue = rewardDisplayValue(reward); + + function matchBy(predicate) { + for (var index = 0; index < gridItems.length; index += 1) { + if (predicate(gridItems[index] || {})) return index; + } + return -1; + } + + var byId = rewardId + ? matchBy(function (item) { + return ( + normalizeCompareValue( + firstPresentValue(item, [ + 'id', + 'rewardId', + 'reward_id', + 'rewardConfigId', + 'reward_config_id', + 'resourceId', + 'resource_id', + ]) + ) === rewardId + ); + }) + : -1; + if (byId >= 0) return byId; + + var byCoverValue = rewardCover + ? matchBy(function (item) { + var merchandise = item.merchandise || {}; + return ( + normalizeCompareValue( + firstPresentValue(merchandise, ['coverUrl', 'cover']) + ) === rewardCover && + (!rewardValue || + gridItemDisplayValue(item) === rewardValue) + ); + }) + : -1; + if (byCoverValue >= 0) return byCoverValue; + + var byNameValue = rewardName + ? matchBy(function (item) { + var merchandise = item.merchandise || {}; + return ( + normalizeCompareValue( + firstPresentValue(merchandise, [ + 'name', + 'resourceName', + 'resource_name', + 'rewardName', + 'reward_name', + ]) + ) === rewardName && + (!rewardValue || + gridItemDisplayValue(item) === rewardValue) + ); + }) + : -1; + if (byNameValue >= 0) return byNameValue; + + var byValue = rewardValue + ? matchBy(function (item) { + return gridItemDisplayValue(item) === rewardValue; + }) + : -1; + return byValue >= 0 ? byValue : 0; + } + + new Vue({ + el: '#app', + data: function () { + return { + tabs: TABS, + currentLanguage: 'en', + currentPage: 'classic', + userBalance: 0, + pageLoading: true, + enabled: { + classic: true, + luxury: true, + advanced: true, + }, + preview: { + open: false, + coverUrl: '', + animationUrl: '', + animationReady: false, + }, + pages: { + classic: stateFor(), + luxury: stateFor(), + advanced: stateFor(), + }, + }; + }, + computed: { + active: function () { + return this.pages[this.currentPage]; + }, + currentConfig: function () { + return CONFIGS[this.currentPage]; + }, + pageClass: function () { + return this.currentConfig.stageClass; + }, + durationSpeed: function () { + var count = this.active.rewards.length || 1; + return 10 * count + 's'; + }, + marqueeRewards: function () { + return this.active.rewards.concat(this.active.rewards); + }, + balanceEnough: function () { + return ( + this.userBalance >= + this.active.goldBtn[this.active.activeBtnIndex].value * + this.active.drawAmount + ); + }, + }, + created: function () { + this.currentLanguage = this.resolveLanguage(); + document.documentElement.lang = this.currentLanguage; + document.documentElement.dir = + this.currentLanguage === 'ar' ? 'rtl' : 'ltr'; + this.currentPage = this.firstPageFromURL(); + this.initRoomID(); + this.loadData(); + }, + beforeDestroy: function () { + this.closePrizePreview(); + if (this.previewPlayer && this.previewPlayer.destroy) { + this.previewPlayer.destroy(); + } + Object.keys(this.pages).forEach( + function (key) { + this.stopTimers(this.pages[key]); + }.bind(this) + ); + }, + methods: { + resolveLanguage: function () { + if (window.HyAppI18n && window.HyAppI18n.lang) + return window.HyAppI18n.lang(); + return readQuery('appLanguage') || readQuery('lang') || 'en'; + }, + t: function (key) { + var fullKey = 'wheel.' + key; + var fallback = WHEEL_FALLBACK[key] || fullKey; + return window.HyAppI18n && window.HyAppI18n.t + ? window.HyAppI18n.t(fullKey, fallback) + : fallback; + }, + common: function (key) { + var fullKey = 'wheel.common.' + key; + var fallback = COMMON_FALLBACK[key] || key; + return window.HyAppI18n && window.HyAppI18n.t + ? window.HyAppI18n.t(fullKey, fallback) + : fallback; + }, + replaceOne: function (key, value) { + return this.t(key).replace(/{}/g, value); + }, + replaceTwo: function (key, first, second) { + return this.t(key) + .replace(/\{1}/g, first) + .replace(/\{2}/g, second); + }, + asset: function (name) { + return ASSET_BASE + name; + }, + ensurePreviewPlayer: function () { + var target = this.$refs.previewEffect; + if (!target || !window.HyAppEffectPlayer) return null; + if ( + this.previewPlayer && + this.previewPlayer.container === target + ) + return this.previewPlayer; + if (this.previewPlayer && this.previewPlayer.destroy) { + this.previewPlayer.destroy(); + } + this.previewPlayer = window.HyAppEffectPlayer.create(target, { + activeClass: 'is-active', + fit: 'contain', + loop: true, + muted: true, + svgaScript: '../../common/vendor/svga.min.js', + waitForWindowLoad: false, + }); + return this.previewPlayer; + }, + openPrizePreview: function (item) { + var source = prizePreviewSource(item); + if (!source.animationUrl && !source.coverUrl) return; + this.closePrizePreview(); + this.preview = { + open: true, + coverUrl: source.coverUrl, + animationUrl: source.animationUrl, + animationReady: false, + }; + // 动态资源优先,但必须保留静态图兜底;播放器加载失败时用户仍能看到预览图,不出现空黑层。 + this.$nextTick(function () { + if (!this.preview.animationUrl) return; + var player = this.ensurePreviewPlayer(); + if (!player) return; + var animationUrl = this.preview.animationUrl; + player + .play(animationUrl, { + svgaScript: '../../common/vendor/svga.min.js', + waitForWindowLoad: false, + }) + .then( + function () { + if ( + this.preview.open && + this.preview.animationUrl === animationUrl + ) { + this.preview.animationReady = true; + } + }.bind(this) + ) + .catch( + function () { + if ( + this.preview.open && + this.preview.animationUrl === animationUrl + ) { + this.preview.animationReady = false; + } + }.bind(this) + ); + }); + }, + closePrizePreview: function () { + if (this.previewPlayer) this.previewPlayer.stop(); + this.preview = { + open: false, + coverUrl: '', + animationUrl: '', + animationReady: false, + }; + }, + firstPageFromURL: function () { + var page = readQuery('wheel') || readQuery('tab') || ''; + var hash = window.location.hash || ''; + if (page === 'middle') page = 'luxury'; + if (!page && hash.indexOf('advanced') !== -1) page = 'advanced'; + if (!page && hash.indexOf('middle') !== -1) page = 'luxury'; + return CONFIGS[page] ? page : 'classic'; + }, + initRoomID: function () { + var roomId = readQuery('roomId') || readQuery('room_id') || ''; + Object.keys(this.pages).forEach( + function (key) { + this.pages[key].roomId = roomId; + }.bind(this) + ); + }, + wheelAPI: function () { + if (!window.HyAppAPI || !window.HyAppAPI.activityWheel) { + return null; + } + return window.HyAppAPI.activityWheel; + }, + loadData: function () { + this.pageLoading = true; + return this.getUserWalletInfo() + .then( + function () { + this.pageLoading = false; + this.loadPageData(this.currentPage); + }.bind(this) + ) + .catch( + function () { + // 钱包接口依赖登录态,失败时不能让活动页白屏;后续抽奖仍会由余额判断和服务端扣费共同拦截。 + this.pageLoading = false; + this.loadPageData(this.currentPage); + }.bind(this) + ); + }, + getUserWalletInfo: function () { + if (!window.HyAppAPI || !window.HyAppAPI.wallet) + return Promise.reject(new Error('HyAppAPI unavailable')); + return window.HyAppAPI.wallet.balances('COIN').then( + function (res) { + this.userBalance = normalizeWalletBalance(res); + }.bind(this) + ); + }, + loadPageData: function (page) { + var state = this.pages[page]; + var config = CONFIGS[page]; + this.configHandle(state, config); + this.recordsHandle(state, config); + this.userRecordsHandle(state, config); + }, + rewardsListHandle: function (state, config) { + var api = this.wheelAPI(); + if (!api) + return Promise.reject(new Error('HyAppAPI unavailable')); + return api + .config(config.key) + .then( + function (res) { + state.isInit = true; + var data = envelopeData(res) || {}; + var drawPrice = Number( + firstPresentValue(data, [ + 'drawPriceCoins', + 'draw_price_coins', + 'drawPrice', + 'draw_price', + ]) || 0 + ); + if (drawPrice > 0) state.drawAmount = drawPrice; + this.enabled[config.key] = + firstPresentValue(data, [ + 'enabled', + config.enabledKey, + ]) !== false; + // 后端配置来自资源组:金币只要求预览图字段为空也能展示金额,礼物/道具/装扮则统一读取 metadata 的预览图和动态图。 + state.gridItems = this.enabled[config.key] + ? normalizeWheelRewards(data) + : []; + }.bind(this) + ) + .catch(function (error) { + state.isInit = true; + state.gridItems = []; + console.warn('wheel rewards load failed', error); + }); + }, + drawHandle: function (state, config) { + var api = this.wheelAPI(); + if (!api) { + state.drawFailed = true; + this.stopSpinning(state); + toast(this.common('requestFailed')); + return Promise.resolve(); + } + return api + .draw(config.key, { + command_id: createCommandID(config.key), + amount: + state.goldBtn[state.activeBtnIndex].value * + state.drawAmount, + times: state.goldBtn[state.activeBtnIndex].value, + roomId: state.roomId, + }) + .then( + function (res) { + var data = normalizeDrawResult(envelopeData(res)); + state.drawFailed = false; + if (data.coin_balance_after !== undefined) { + this.userBalance = Number( + data.coin_balance_after || 0 + ); + } else { + this.getUserWalletInfo(); + } + this.recordsHandle(state, config); + state.currentReward = data; + state.targetIndex = resolveRewardTargetIndex( + state.gridItems, + data + ); + }.bind(this) + ) + .catch( + function (error) { + state.drawFailed = true; + this.stopSpinning(state); + toast( + error.message || this.common('requestFailed') + ); + }.bind(this) + ); + }, + recordsHandle: function (state, config) { + var api = this.wheelAPI(); + if (!api) return Promise.resolve(); + state.loading = true; + if (state.isInit) state.pageNo += 1; + return api + .history(config.key, { + pageNo: state.pageNo, + pageSize: config.pageSize, + }) + .then(function (res) { + var data = envelopeData(res) || {}; + var records = Array.isArray(data.records) + ? data.records + : []; + if (records.length === 0) state.finished = true; + state.loading = false; + // 历史记录和中奖弹窗使用同一批奖品字段,统一标准化后再追加,分页加载不会把裸文件名带进 DOM。 + state.historyRecord = state.historyRecord.concat( + records.map(normalizeHistoryRecord) + ); + }) + .catch(function () { + state.loading = false; + state.finished = true; + }); + }, + userRecordsHandle: function (state, config) { + var api = this.wheelAPI(); + if (!api) return Promise.resolve(); + return api + .hints(config.key) + .then(function (res) { + var data = envelopeData(res) || {}; + if (Array.isArray(data.values)) + state.rewards = data.values.map(normalizeHintItem); + }) + .catch(function () { + state.rewards = []; + }); + }, + configHandle: function (state, config) { + return this.rewardsListHandle(state, config).then( + function () { + if (!this.enabled[this.currentPage]) + this.handleSelect(this.firstEnabledPage()); + }.bind(this) + ); + }, + firstEnabledPage: function () { + for (var index = 0; index < TABS.length; index += 1) { + if (this.enabled[TABS[index].key]) return TABS[index].key; + } + return 'classic'; + }, + handleGoldBtn: function (index) { + this.active.activeBtnIndex = index; + }, + handleSelect: function (tab) { + if (!CONFIGS[tab] || !this.enabled[tab]) return; + this.currentPage = tab; + if (!this.pages[tab].gridItems.length) this.loadPageData(tab); + }, + startLottery: function () { + var state = this.active; + var config = this.currentConfig; + if (!state.gridItems.length || state.drawAmount <= 0) { + toast(this.common('rewardUnavailable')); + return; + } + if (!this.balanceEnough) { + toast(this.common('balanceNotEnough')); + return; + } + if (state.isSpinning) return; + state.showReward = false; + state.drawFailed = false; + state.isInit = false; + state.finished = false; + state.pageNo = 1; + state.historyRecord = []; + state.targetIndex = null; + state.activeIndex = null; + if (config.type === 'round') this.backgroundChange(state); + this.startSpinning(state, config); + this.drawHandle(state, config); + this.stopShowReward(state, config); + }, + startSpinning: function (state, config) { + if (config.type === 'round') { + this.startRoundSpinning(state); + return; + } + state.isSpinning = true; + var sequenceIndex = 0; + var spinCount = 0; + var maxFastSpins = 25; + var speedIncrement = 100; + var minSpeed = config.minSpeed; + state.spinInterval = window.setInterval( + function () { + state.activeIndex = config.sequence[sequenceIndex] - 1; + sequenceIndex = + (sequenceIndex + 1) % config.sequence.length; + spinCount += 1; + if (config.key === 'classic') { + state.currentBackground = + state.currentBackground === 'light' + ? 'light2' + : 'light'; + } + if ( + spinCount > maxFastSpins && + state.targetIndex !== null + ) { + state.spinSpeed += speedIncrement; + if ( + Math.abs( + state.activeIndex - state.targetIndex + ) <= 4 + ) + state.spinSpeed += speedIncrement * 2; + if ( + state.activeIndex === state.targetIndex && + state.spinSpeed >= minSpeed + ) + this.stopSpinning(state); + } + }.bind(this), + state.spinSpeed + ); + }, + startRoundSpinning: function (state) { + var startWait = Date.now(); + var waitStartDeg = state.rotateDeg; + state.isSpinning = true; + if (state.rotationTimer) + window.cancelAnimationFrame(state.rotationTimer); + + var animateToTarget = function () { + var count = Math.max(1, state.gridItems.length || 1); + var targetIndex = Number(state.targetIndex || 0); + var duration = 4200; + var startTime = Date.now(); + var startDeg = state.rotateDeg; + var currentDeg = positiveModulo(startDeg, 360); + var targetBaseDeg = roundPrizeAngle(targetIndex, count); + var forwardDelta = positiveModulo( + targetBaseDeg - currentDeg, + 360 + ); + // 指针转盘必须等接口给出真实 targetIndex 后,从当前角度继续正向缓停到奖品图标角度;不能归零或使用假结果。 + var targetDeg = startDeg + 360 * 6 + forwardDelta; + var animate = function () { + var elapsed = Date.now() - startTime; + var progress = Math.min(1, elapsed / duration); + var easedProgress = this.roundStopEase(progress); + state.rotateDeg = + startDeg + (targetDeg - startDeg) * easedProgress; + if (progress >= 1) { + state.isSpinning = false; + state.rotateDeg = targetDeg; + state.rotationTimer = null; + this.showDrawReward(state); + return; + } + state.rotationTimer = + window.requestAnimationFrame(animate); + }.bind(this); + animate(); + }.bind(this); + + var waitForTarget = function () { + if ( + state.targetIndex !== null && + state.targetIndex !== undefined + ) { + animateToTarget(); + return; + } + state.rotateDeg = + waitStartDeg + ((Date.now() - startWait) / 1000) * 720; + state.rotationTimer = + window.requestAnimationFrame(waitForTarget); + }; + waitForTarget(); + }, + customEase: function (value) { + return value < 0.5 + ? 2 * value * value + : 1 - Math.pow(-2 * value + 2, 3) / 2; + }, + roundStopEase: function (value) { + return 1 - Math.pow(1 - value, 4); + }, + backgroundChange: function (state) { + state.backgroundInterval = window.setInterval(function () { + state.currentBackground = + state.currentBackground === 'light' + ? 'light2' + : 'light'; + }, 100); + }, + showDrawReward: function (state) { + if (state.drawFailed || state.targetIndex === null) return; + if ( + state.targetIndex !== null && + state.targetIndex !== undefined && + typeof state.activeIndex === 'number' + ) { + state.activeIndex = state.targetIndex; + } + state.showReward = true; + state.isInit = true; + window.clearInterval(state.backgroundInterval); + }, + stopShowReward: function (state, config) { + if (config && config.type === 'round') return; + window.setTimeout( + function () { + this.showDrawReward(state); + }.bind(this), + 3300 + ); + }, + stopSpinning: function (state) { + this.stopTimers(state); + state.isSpinning = false; + state.spinSpeed = 50; + state.activeIndex = + state.targetIndex !== null && + state.targetIndex !== undefined + ? state.targetIndex + : null; + }, + stopTimers: function (state) { + window.clearInterval(state.spinInterval); + window.clearInterval(state.backgroundInterval); + if (state.rotationTimer) + window.cancelAnimationFrame(state.rotationTimer); + state.spinInterval = null; + state.rotationTimer = null; + }, + getPrizePosition: function (index) { + var count = Math.max(1, this.active.gridItems.length || 1); + var radius = 150; + var center = { x: 50, y: 50 }; + var itemAngle = roundPrizeAngle(index, count); + var angle = (itemAngle * Math.PI) / 180; + var distance = radius * 0.25; + var x = center.x + Math.sin(angle) * distance; + var y = center.y - Math.cos(angle) * distance; + var textRotation = itemAngle; + return { + left: x + '%', + top: y + '%', + transform: + 'translate(-50%, -50%) rotate(' + textRotation + 'deg)', + }; + }, + buttonStyle: function (index) { + if (this.currentPage !== 'luxury') return {}; + var name = + 'lucky_box_tow_' + + (index === this.active.activeBtnIndex ? '' : 'un') + + 'btn' + + (index + 1) + + '.png'; + return { backgroundImage: 'url(' + this.asset(name) + ')' }; + }, + pointerStyle: function () { + if (this.currentPage !== 'luxury') return {}; + return { '--pointer-rotate': this.active.rotateDeg + 'deg' }; + }, + formatDate: function (time, format) { + if (!time) return ''; + var date = new Date( + Number(time) || String(time).replace(/-/g, '/') + ); + function zero(value) { + return (value < 10 ? '0' : '') + value; + } + return (format || 'yyyy-MM-dd HH:mm:ss').replace( + /yyyy|MM|dd|HH|mm|ss/g, + function (token) { + if (token === 'yyyy') return zero(date.getFullYear()); + if (token === 'MM') return zero(date.getMonth() + 1); + if (token === 'dd') return zero(date.getDate()); + if (token === 'HH') return zero(date.getHours()); + if (token === 'mm') return zero(date.getMinutes()); + return zero(date.getSeconds()); + } + ); + }, + }, + }); +})(); diff --git a/activity/wheel/style.css b/activity/wheel/style.css new file mode 100644 index 0000000..770b0cb --- /dev/null +++ b/activity/wheel/style.css @@ -0,0 +1,1183 @@ +[v-cloak] { + display: none; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-height: 100%; + margin: 0; + font-family: Arial, Helvetica, sans-serif; + background: #10101a; + -webkit-font-smoothing: antialiased; +} + +button { + border: 0; + padding: 0; + font: inherit; + color: inherit; + background: transparent; + -webkit-tap-highlight-color: transparent; +} + +.wheel-page { + --wheel-vw: min(0.2666667vw, 2.048px); + min-height: 100vh; + overflow-x: hidden; +} + +#app { + width: min(100vw, 768px); + min-height: 100vh; + margin: 0 auto; + overflow: hidden; + background: var(--hy-theme-bg); +} + +.wheel-loading { + min-height: 100vh; + display: grid; + place-items: center; + color: var(--hy-theme-primary); + font-size: calc(16 * var(--wheel-vw)); +} + +.wheel-stage { + width: 100%; + height: calc(600 * var(--wheel-vw)); + position: relative; + margin: 0 auto; + background-repeat: no-repeat; + background-size: 100% 100%; +} + +.wheel-classic { + background: linear-gradient(to bottom, #4244dd, #82ceff); +} + +.wheel-classic .wheel-stage { + background-image: url('./assets/other/lucky_box_bg_new.png'); +} + +.wheel-luxury { + background: linear-gradient(to bottom, #cfd2fd, #e39dbf); +} + +.wheel-luxury .wheel-stage { + height: calc(595 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_tow_bg_new.png'); +} + +.wheel-advanced { + background: #794724; +} + +.wheel-advanced .wheel-stage { + background-image: url('./assets/other/lucky_box_three_bg_new.png'); +} + +.lucky-tab { + display: flex; + align-items: center; + gap: calc(10 * var(--wheel-vw)); + position: absolute; + top: calc(60 * var(--wheel-vw)); + left: 50%; + z-index: 3; + width: 100%; + padding: 0 calc(20 * var(--wheel-vw)); + transform: translateX(-50%); +} + +.wheel-luxury .lucky-tab { + top: calc(58 * var(--wheel-vw)); +} + +.tab-item { + flex: 1; + height: calc(40 * var(--wheel-vw)); + color: #fff; + line-height: calc(36 * var(--wheel-vw)); + text-align: center; + font-size: calc(14 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_defalute.png') no-repeat center / + 100% 100%; +} + +.tab-item.luxury { + background-image: url('./assets/other/lucky_box_tow_default.png'); +} + +.tab-item.advanced { + background-image: url('./assets/other/lucky_box_three_default.png'); +} + +.tab-item.classic.active { + background-image: url('./assets/other/lucky_box_middle.png'); +} + +.tab-item.luxury.active { + background-image: url('./assets/other/lucky_box_tow_middle.png'); +} + +.tab-item.advanced.active { + background-image: url('./assets/other/lucky_box_three_gold.png'); + color: #fdd656; +} + +.marquee-content, +.marquee-box { + position: absolute; + left: 50%; + z-index: 2; + overflow: hidden; + transform: translateX(-50%); +} + +.marquee-content { + top: calc(113 * var(--wheel-vw)); + width: 68%; +} + +.marquee-box { + top: calc(104 * var(--wheel-vw)); + width: 75%; + height: calc(28 * var(--wheel-vw)); + padding: calc(4 * var(--wheel-vw)) calc(25 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_tow_notice.png') no-repeat + center / 100% 100%; +} + +.wheel-advanced .marquee-box { + top: calc(113 * var(--wheel-vw)); + width: 85%; + height: calc(31 * var(--wheel-vw)); + padding: calc(5 * var(--wheel-vw)) calc(30 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_three_notice.png'); +} + +.marquee-box .marquee-content { + position: static; + width: 100%; + transform: none; +} + +.reward { + display: inline-flex; + white-space: nowrap; + animation: marquee-scroll linear infinite; +} + +.reward.reward-active { + animation-name: marquee-scroll-ar; +} + +.reward-list { + display: flex; + align-items: center; + gap: calc(2 * var(--wheel-vw)); + margin-right: calc(20 * var(--wheel-vw)); + color: #fff; + font-size: calc(12 * var(--wheel-vw)); +} + +.reward-list .img { + width: calc(20 * var(--wheel-vw)); + height: calc(20 * var(--wheel-vw)); + border-radius: 50%; +} + +.lucky-content { + position: absolute; + top: calc(140 * var(--wheel-vw)); + left: 50%; + width: 90%; + height: calc(320 * var(--wheel-vw)); + transform: translateX(-50%); +} + +.wheel-luxury .lucky-content { + top: calc(145 * var(--wheel-vw)); + width: 91%; + height: calc(353 * var(--wheel-vw)); +} + +.wheel-advanced .lucky-content { + top: calc(155 * var(--wheel-vw)); + width: 93%; +} + +.content { + position: relative; + width: 100%; + height: 100%; +} + +.wheel-classic .content { + padding: calc(16 * var(--wheel-vw)) calc(18 * var(--wheel-vw)) + calc(18 * var(--wheel-vw)); +} + +.wheel-luxury .content { + padding: calc(34 * var(--wheel-vw)) calc(26 * var(--wheel-vw)); + overflow: hidden; +} + +.right { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.wheel-luxury .right { + top: calc(42 * var(--wheel-vw)); + left: 50%; + width: calc(300 * var(--wheel-vw)); + height: calc(302 * var(--wheel-vw)); + transform: translateX(-50%); +} + +.lottery-grid { + position: relative; + z-index: 1; + width: 100%; + height: 100%; +} + +.grid-classic { + display: grid; + grid-template-columns: repeat(3, calc(96 * var(--wheel-vw))); + grid-template-rows: repeat(3, calc(94 * var(--wheel-vw))); + gap: calc(3 * var(--wheel-vw)); +} + +.grid-advanced { + display: grid; + grid-template-columns: repeat(4, calc(84 * var(--wheel-vw))); + grid-template-rows: repeat(4, calc(84 * var(--wheel-vw))); + gap: calc(4 * var(--wheel-vw)); +} + +.turntable-content { + position: absolute; + inset: 0; + background: url('./assets/other/lucky_box_tow_turntable.png') no-repeat + center / 100% 100%; +} + +.grid-item { + position: relative; + width: 100%; + height: 100%; + text-align: center; + font-weight: 700; +} + +.grid-classic .grid-item { + padding: calc(10 * var(--wheel-vw)); + color: #572403; + font-size: calc(12 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_unselect.png') no-repeat center / + 100% 100%; +} + +.grid-classic .grid-item.active { + background-image: url('./assets/other/lucky_box_select.png'); +} + +.grid-advanced .grid-item { + padding: calc(10 * var(--wheel-vw)); + color: #fdd656; + font-size: calc(12 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_three_unselect.png') no-repeat + center / 100% 100%; +} + +.grid-advanced .grid-item.active { + background-image: url('./assets/other/lucky_box_three_select.png'); +} + +.grid-luxury .grid-item { + position: absolute; + display: block; + width: calc(76 * var(--wheel-vw)); + height: calc(76 * var(--wheel-vw)); + color: #ed417f; + font-size: calc(12 * var(--wheel-vw)); +} + +.grid-luxury .grid-item:nth-child(2n) { + color: #fff; +} + +.grid-item .img { + width: 80%; + height: 80%; + object-fit: contain; +} + +.grid-item, +.previewable-box { + cursor: zoom-in; +} + +.grid-luxury .grid-item .img { + width: calc(55 * var(--wheel-vw)); + height: calc(55 * var(--wheel-vw)); +} + +.gift-webp { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.item-gold { + display: flex; + align-items: center; + justify-content: center; + gap: calc(4 * var(--wheel-vw)); +} + +.grid-classic .item-gold { + position: absolute; + bottom: calc(8 * var(--wheel-vw)); + left: 50%; + transform: translateX(-50%); +} + +.grid-luxury .item-gold { + position: absolute; + bottom: calc(-5 * var(--wheel-vw)); + left: 50%; + transform: translateX(-50%); +} + +.item-gold img { + width: calc(15 * var(--wheel-vw)); + height: calc(15 * var(--wheel-vw)); +} + +.start-button { + cursor: pointer; + background-repeat: no-repeat; + background-position: center; + background-size: 100% 100%; +} + +.start-button:disabled, +.btn:disabled { + cursor: not-allowed; + filter: grayscale(0.35); + opacity: 0.72; +} + +.wheel-empty { + position: absolute; + left: 50%; + top: 50%; + z-index: 4; + width: calc(210 * var(--wheel-vw)); + min-height: calc(52 * var(--wheel-vw)); + display: grid; + place-items: center; + padding: calc(8 * var(--wheel-vw)) calc(12 * var(--wheel-vw)); + color: #fff; + font-size: calc(13 * var(--wheel-vw)); + font-weight: 700; + line-height: 1.25; + text-align: center; + border: calc(1 * var(--wheel-vw)) solid rgba(255, 255, 255, 0.65); + border-radius: calc(10 * var(--wheel-vw)); + background: rgba(0, 0, 0, 0.55); + transform: translate(-50%, -50%); + pointer-events: none; +} + +.grid-classic .start-button { + grid-column: 2; + grid-row: 2; + width: 100%; + height: 100%; + background-image: url('./assets/other/lucky_box_go.png'); +} + +.grid-luxury .start-button { + position: absolute; + top: 50%; + left: 50%; + width: calc(220 * var(--wheel-vw)); + height: calc(220 * var(--wheel-vw)); + transform: translate(-50%, -50%) rotate(var(--pointer-rotate, 0deg)); + background-image: url('./assets/other/lucky_box_tow_pointer.png'); +} + +.grid-luxury .start-button:disabled { + filter: none; + opacity: 1; +} + +.grid-advanced .start-button { + grid-column: 2 / 4; + grid-row: 2 / 4; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + gap: calc(8 * var(--wheel-vw)); + width: 100%; + height: 100%; + padding-bottom: calc(38 * var(--wheel-vw)); + color: #fff; + font-size: calc(14 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_three_go.png'); +} + +.grid-advanced .start-button strong { + display: flex; + align-items: center; + gap: calc(4 * var(--wheel-vw)); + color: #fffe47; +} + +.grid-advanced .start-button i { + display: inline-block; + width: calc(16 * var(--wheel-vw)); + height: calc(16 * var(--wheel-vw)); + background: url('./assets/other/gold_new.png') no-repeat center / 100% 100%; +} + +.btn-start { + position: absolute; + left: 50%; + bottom: calc(78 * var(--wheel-vw)); + z-index: 3; + display: flex; + gap: calc(10 * var(--wheel-vw)); + width: 82%; + color: #fff; + transform: translateX(-50%); +} + +.wheel-luxury .btn-start { + bottom: calc(10 * var(--wheel-vw)); + width: 95%; + gap: calc(2 * var(--wheel-vw)); +} + +.wheel-advanced .btn-start { + bottom: calc(20 * var(--wheel-vw)); + width: 100%; + gap: calc(2 * var(--wheel-vw)); + padding: 0 calc(10 * var(--wheel-vw)); + color: #fdd656; +} + +.btn { + flex: 1; + height: calc(62 * var(--wheel-vw)); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: calc(3 * var(--wheel-vw)); + padding-bottom: calc(10 * var(--wheel-vw)); + font-size: calc(14 * var(--wheel-vw)); + font-weight: 700; + background: url('./assets/other/lucky_box_unbtn.png') no-repeat center / + 100% 100%; +} + +.btn.active { + background-image: url('./assets/other/lucky_box_btn.png'); +} + +.wheel-luxury .btn { + height: calc(70 * var(--wheel-vw)); + padding-bottom: calc(25 * var(--wheel-vw)); + background-repeat: no-repeat; + background-position: center; + background-size: 100% 100%; +} + +.wheel-advanced .btn { + background-image: url('./assets/other/lucky_box_three_unbtn.png'); + padding-bottom: 0; +} + +.wheel-advanced .btn.active { + color: #920e00; + background-image: url('./assets/other/lucky_box_three_btn.png'); +} + +.desc-content { + position: absolute; + top: calc(160 * var(--wheel-vw)); + right: 0; + z-index: 4; + display: flex; + flex-direction: column; + gap: calc(35 * var(--wheel-vw)); +} + +.wheel-advanced .desc-content { + top: calc(243 * var(--wheel-vw)); + gap: calc(38 * var(--wheel-vw)); +} + +.desc-content button { + width: calc(40 * var(--wheel-vw)); + height: calc(50 * var(--wheel-vw)); + background-repeat: no-repeat; + background-position: center; + background-size: 100% 100%; +} + +.desc-content .rule { + background-image: url('./assets/other/lucky_box_rule.png'); +} + +.wheel-luxury .desc-content .rule { + background-image: url('./assets/other/lucky_box_tow_rule.png'); +} + +.desc-content .record { + background-image: url('./assets/other/lucky_box_reward.png'); +} + +.wheel-luxury .desc-content .record { + background-image: url('./assets/other/lucky_box_tow_reward.png'); +} + +.user-gold { + position: absolute; + bottom: calc(22 * var(--wheel-vw)); + left: 50%; + z-index: 3; + width: calc(150 * var(--wheel-vw)); + height: calc(40 * var(--wheel-vw)); + display: flex; + align-items: center; + justify-content: center; + gap: calc(6 * var(--wheel-vw)); + color: #fef303; + font-size: calc(14 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_gold.png') no-repeat center / 100% + 100%; + transform: translateX(-50%); +} + +.wheel-luxury .user-gold { + bottom: calc(88 * var(--wheel-vw)); + color: #fff; + background-image: url('./assets/other/lucky_box_tow_gold.png'); +} + +.user-gold img { + width: calc(22 * var(--wheel-vw)); + height: calc(22 * var(--wheel-vw)); +} + +.wheel-popup { + position: fixed; + top: 0; + bottom: 0; + left: 50%; + z-index: 20; + width: min(100vw, 768px); + overflow: auto; + background: rgba(0, 0, 0, 0.58); + transform: translateX(-50%); +} + +.rule-content, +.popup-content, +.reward-content { + position: relative; + color: #fff; +} + +.popup-close { + position: absolute; + z-index: 10; + width: calc(35 * var(--wheel-vw)); + height: calc(35 * var(--wheel-vw)); + font-size: calc(28 * var(--wheel-vw)); + line-height: 1; +} + +.rule-content { + width: 100%; + padding: calc(40 * var(--wheel-vw)) calc(20 * var(--wheel-vw)) + calc(20 * var(--wheel-vw)); +} + +.rule-close { + right: calc(30 * var(--wheel-vw)); + top: calc(52 * var(--wheel-vw)); + color: #fff; +} + +.rule-title, +.bg-title { + position: absolute; + left: 50%; + z-index: 2; + color: #fff; + font-weight: 700; + text-align: center; + transform: translateX(-50%); +} + +.rule-title { + top: calc(10 * var(--wheel-vw)); + width: calc(250 * var(--wheel-vw)); + height: calc(60 * var(--wheel-vw)); + padding-top: calc(2 * var(--wheel-vw)); + font-size: calc(16 * var(--wheel-vw)); + line-height: calc(60 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_title_top.png') no-repeat center / + 100% 100%; +} + +.rule-top { + width: 100%; + height: calc(30 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_top.png') no-repeat center / 100% + 100%; +} + +.rule-center { + width: 100%; + height: calc(300 * var(--wheel-vw)); + margin-top: calc(-2 * var(--wheel-vw)); + overflow: auto; + padding: calc(20 * var(--wheel-vw)) calc(20 * var(--wheel-vw)) 0; + color: #fff; + font-size: calc(16 * var(--wheel-vw)); + font-weight: 700; + background: url('./assets/other/lucky_box_center.png') no-repeat center / + 100% 100%; +} + +.rule-bottom { + width: 100%; + height: calc(30 * var(--wheel-vw)); + margin-top: calc(-2 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_bottom.png') no-repeat center / + 100% 100%; +} + +.rule-desc { + margin: 0 0 calc(10 * var(--wheel-vw)); + word-break: break-word; +} + +.popup-content { + padding: calc(10 * var(--wheel-vw)) calc(15 * var(--wheel-vw)); + background: linear-gradient(to bottom, #4244dd, #80d2ff); +} + +.popup-content .bg-title { + top: calc(20 * var(--wheel-vw)); + width: calc(250 * var(--wheel-vw)); + height: calc(60 * var(--wheel-vw)); + padding-top: calc(2 * var(--wheel-vw)); + font-size: calc(14 * var(--wheel-vw)); + line-height: calc(60 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_title_top.png') no-repeat center / + 100% 100%; +} + +.popup-content .rule-close { + top: calc(32 * var(--wheel-vw)); +} + +.popup-content .rule-center { + height: calc(450 * var(--wheel-vw)); + padding: 0 calc(12 * var(--wheel-vw)); +} + +.record-list { + padding-top: calc(10 * var(--wheel-vw)); +} + +.record-item { + margin-bottom: calc(10 * var(--wheel-vw)); + padding: calc(8 * var(--wheel-vw)); + border: calc(1 * var(--wheel-vw)) solid #fff; + border-radius: calc(10 * var(--wheel-vw)); +} + +.item-title { + display: grid; + grid-template-columns: repeat(3, 1fr); + margin-bottom: calc(10 * var(--wheel-vw)); + text-align: center; +} + +.item-title .left { + text-align: left; +} + +.item-title .right { + text-align: right; +} + +.box-content { + display: grid; + grid-template-columns: repeat(4, 1fr); + color: #fff; + font-size: calc(14 * var(--wheel-vw)); +} + +.box-desc { + color: #fff; + text-align: center; +} + +.box { + width: calc(70 * var(--wheel-vw)); + height: calc(70 * var(--wheel-vw)); + margin: 0 auto calc(10 * var(--wheel-vw)); + padding: calc(5 * var(--wheel-vw)); + border: calc(1 * var(--wheel-vw)) solid #fff; + border-radius: calc(8 * var(--wheel-vw)); + background: linear-gradient(133deg, #2c3aa1 0%, #5881e9 100%); +} + +.box .img { + width: 100%; + height: 100%; + object-fit: contain; +} + +.finished-text { + text-align: center; + color: rgba(255, 255, 255, 0.65); + font-size: calc(13 * var(--wheel-vw)); +} + +.reward-content { + width: 100%; + height: calc(520 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_reward_bg.png') no-repeat center / + 100% 100%; +} + +.reward-content .bg { + position: absolute; + top: calc(120 * var(--wheel-vw)); + left: 50%; + z-index: -1; + width: calc(320 * var(--wheel-vw)); + height: calc(370 * var(--wheel-vw)); + border-radius: calc(20 * var(--wheel-vw)); + background: linear-gradient(133deg, #2c3aa1 0%, #5881e9 100%); + transform: translateX(-50%); +} + +.reward-content .title { + position: absolute; + top: calc(105 * var(--wheel-vw)); + left: 50%; + color: #fff; + font-size: calc(16 * var(--wheel-vw)); + font-weight: 700; + text-align: center; + transform: translateX(-50%); +} + +.reward-close { + top: calc(100 * var(--wheel-vw)); + right: calc(25 * var(--wheel-vw)); + color: transparent; + background: url('./assets/other/lucky_box_close.png') no-repeat center / + 100% 100%; +} + +.reward-content .content { + position: absolute; + top: calc(150 * var(--wheel-vw)); + left: 50%; + width: calc(300 * var(--wheel-vw)); + height: calc(330 * var(--wheel-vw)); + display: flex; + flex-direction: column; + transform: translateX(-50%); +} + +.reward-content .box-content { + display: flex; + flex: 1 1 auto; + flex-wrap: wrap; + align-items: center; + align-content: flex-start; + justify-content: space-around; + gap: calc(10 * var(--wheel-vw)) calc(2 * var(--wheel-vw)); + min-height: 0; + margin-top: calc(10 * var(--wheel-vw)); + overflow: auto; + font-size: calc(12 * var(--wheel-vw)); +} + +.reward-content .tips { + width: 85%; + margin: calc(5 * var(--wheel-vw)) auto calc(10 * var(--wheel-vw)); + color: #fff; + font-size: calc(12 * var(--wheel-vw)); + line-height: calc(15 * var(--wheel-vw)); + text-align: center; +} + +.again-btn { + display: block; + flex: 0 0 auto; + width: 85%; + height: calc(48 * var(--wheel-vw)); + margin: calc(8 * var(--wheel-vw)) auto 0; + color: #fff; + font-size: calc(16 * var(--wheel-vw)); + font-weight: 700; + line-height: calc(48 * var(--wheel-vw)); + text-align: center; + border: calc(2 * var(--wheel-vw)) solid #fff; + border-radius: calc(10 * var(--wheel-vw)); + background: linear-gradient(to right, #1897ff, #2472ff); +} + +.wheel-luxury .rule-content { + padding: calc(40 * var(--wheel-vw)) calc(20 * var(--wheel-vw)) + calc(20 * var(--wheel-vw)); +} + +.wheel-luxury .rule-content::after, +.wheel-luxury .rule-content::before, +.wheel-luxury .popup-content::after, +.wheel-luxury .popup-content::before { + content: ''; + position: absolute; + left: 50%; + z-index: 1; + width: 88%; + height: calc(120 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_tow_reward_yuan.png') no-repeat + center / 100% 100%; + transform: translateX(-50%); +} + +.wheel-luxury .rule-content::after { + top: calc(50 * var(--wheel-vw)); +} + +.wheel-luxury .rule-content::before { + bottom: calc(30 * var(--wheel-vw)); + transform: translateX(-50%) rotate(180deg); +} + +.wheel-luxury .rule-title, +.wheel-luxury .popup-content .bg-title { + width: calc(220 * var(--wheel-vw)); + height: calc(40 * var(--wheel-vw)); + font-size: calc(14 * var(--wheel-vw)); + line-height: calc(35 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_tow_rule_top.png'); +} + +.wheel-luxury .rule-title { + top: calc(32 * var(--wheel-vw)); + width: calc(180 * var(--wheel-vw)); + height: calc(35 * var(--wheel-vw)); + line-height: calc(30 * var(--wheel-vw)); +} + +.wheel-luxury .rule-top { + height: calc(50 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_tow_reward_top.png'); +} + +.wheel-luxury .rule-center { + position: relative; + z-index: 2; + height: calc(300 * var(--wheel-vw)); + padding: 0 calc(20 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_tow_reward_center.png'); +} + +.wheel-luxury .rule-bottom { + height: calc(50 * var(--wheel-vw)); + background-image: url('./assets/other/lucky_box_tow_reward_bottom.png'); +} + +.wheel-luxury .popup-content { + padding: calc(15 * var(--wheel-vw)); + background: transparent; +} + +.wheel-luxury .popup-content::after { + top: calc(25 * var(--wheel-vw)); +} + +.wheel-luxury .popup-content::before { + bottom: calc(25 * var(--wheel-vw)); + transform: translateX(-50%) rotate(180deg); +} + +.wheel-luxury .popup-content .bg-title { + top: calc(6 * var(--wheel-vw)); +} + +.wheel-luxury .popup-content .rule-center { + height: calc(430 * var(--wheel-vw)); + padding: 0 calc(12 * var(--wheel-vw)); +} + +.wheel-luxury .record-item { + border: 0; + background: rgba(126, 26, 63, 0.2); +} + +.wheel-luxury .box { + background: linear-gradient(133deg, #e93476 0%, #ff7ea6 100%); +} + +.wheel-luxury .reward-content { + width: 90%; + height: calc(410 * var(--wheel-vw)); + margin: calc(38 * var(--wheel-vw)) auto 0; + background-image: url('./assets/other/lucky_box_tow_reward_bg.png'); +} + +.wheel-luxury .reward-content .bg { + top: 0; + width: calc(330 * var(--wheel-vw)); + height: calc(350 * var(--wheel-vw)); + background: linear-gradient(133deg, #fd67b1 0%, #fe6cab 100%); +} + +.wheel-luxury .reward-content .title { + top: calc(-35 * var(--wheel-vw)); + width: calc(280 * var(--wheel-vw)); + height: calc(70 * var(--wheel-vw)); + line-height: calc(75 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_tow_reward_desc.png') no-repeat + center / 100% 100%; +} + +.wheel-luxury .reward-close { + top: calc(15 * var(--wheel-vw)); + right: calc(15 * var(--wheel-vw)); + color: #fff; + background: transparent; +} + +.wheel-luxury .reward-content .content { + top: calc(40 * var(--wheel-vw)); +} + +.wheel-luxury .reward-content .box-content { + margin-top: 0; +} + +.wheel-luxury .reward-content .tips { + margin: calc(2 * var(--wheel-vw)) auto calc(6 * var(--wheel-vw)); +} + +.wheel-luxury .again-btn { + height: calc(38 * var(--wheel-vw)); + line-height: calc(38 * var(--wheel-vw)); + background: linear-gradient(to bottom, #ff85b4, #db2e6c); +} + +.wheel-luxury .reward-content .box { + width: calc(78 * var(--wheel-vw)); + height: calc(78 * var(--wheel-vw)); +} + +.wheel-advanced .rule-content { + width: 90%; + margin: calc(20 * var(--wheel-vw)) auto 0; + padding: 0; + overflow: hidden; + background: url('./assets/other/lucky_box_three_rule.png') no-repeat + center / 100% 100%; +} + +.wheel-advanced .rule-close, +.wheel-advanced .popup-content .rule-close, +.wheel-advanced .reward-close { + right: calc(10 * var(--wheel-vw)); + color: #4e0301; + background: transparent; +} + +.wheel-advanced .rule-title, +.wheel-advanced .popup-content .bg-title { + top: calc(40 * var(--wheel-vw)); + color: #fff; + font-size: calc(16 * var(--wheel-vw)); + line-height: normal; + background: transparent; +} + +.wheel-advanced .rule-content .rule-center { + height: calc(300 * var(--wheel-vw)); + margin-top: calc(60 * var(--wheel-vw)); + background: transparent; +} + +.wheel-advanced .popup-content { + width: 95%; + margin: 0 auto; + overflow: hidden; + padding: 0 0 calc(8 * var(--wheel-vw)); + background: url('./assets/other/lucky_box_three_history.png') no-repeat + center / 100% 100%; +} + +.wheel-advanced .popup-content .rule-close { + top: calc(50 * var(--wheel-vw)); +} + +.wheel-advanced .popup-content .rule-center { + height: calc(450 * var(--wheel-vw)); + margin-top: calc(80 * var(--wheel-vw)); + padding: 0 calc(12 * var(--wheel-vw)); + background: transparent; +} + +.wheel-advanced .record-item { + border: 0; + background: rgba(126, 26, 63, 0.2); +} + +.wheel-advanced .box { + background: linear-gradient(133deg, #4d0201 0%, #be210f 100%); +} + +.wheel-advanced .reward-content { + width: 90%; + height: calc(440 * var(--wheel-vw)); + margin: calc(60 * var(--wheel-vw)) auto 0; + background-image: url('./assets/other/lucky_box_three_reward_bg.png'); +} + +.wheel-advanced .reward-content .bg { + top: calc(50 * var(--wheel-vw)); + width: calc(330 * var(--wheel-vw)); + height: calc(390 * var(--wheel-vw)); + background: linear-gradient(133deg, #ffaf37 0%, #f27f13 100%); +} + +.wheel-advanced .reward-content .title { + top: calc(46 * var(--wheel-vw)); +} + +.wheel-advanced .reward-close { + top: calc(55 * var(--wheel-vw)); +} + +.wheel-advanced .reward-content .content { + top: calc(90 * var(--wheel-vw)); +} + +.wheel-advanced .again-btn { + background: linear-gradient(to bottom, #be210f, #4d0201); +} + +.material-preview-overlay { + position: fixed; + inset: 0; + z-index: 80; + display: flex; + align-items: center; + justify-content: center; + padding: calc(env(safe-area-inset-top) + 28px) calc(24 * var(--wheel-vw)) + calc(env(safe-area-inset-bottom) + 28px); + background: rgba(0, 0, 0, 0.88); +} + +.material-preview-close { + position: absolute; + top: calc(env(safe-area-inset-top) + 12px); + right: calc(16 * var(--wheel-vw)); + z-index: 2; + width: calc(42 * var(--wheel-vw)); + height: calc(42 * var(--wheel-vw)); + color: #fff; + font-size: calc(36 * var(--wheel-vw)); + font-weight: 700; + line-height: 1; +} + +.material-preview-stage { + position: relative; + width: min(calc(100vw - 48px), calc(640 * var(--wheel-vw))); + height: min( + calc( + 100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - + 96px + ), + calc(640 * var(--wheel-vw)) + ); + pointer-events: none; +} + +.material-preview-image, +.material-preview-effect { + position: absolute; + inset: 0; + display: block; + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; +} + +.material-preview-image { + object-fit: contain; + object-position: center; +} + +.material-preview-image.is-dynamic-hidden { + visibility: hidden; +} + +.material-preview-effect { + display: none; +} + +.material-preview-effect.is-active { + display: block; +} + +.material-preview-effect video, +.material-preview-effect canvas { + width: 100%; + height: 100%; + object-fit: contain; +} + +@keyframes marquee-scroll { + from { + transform: translateX(0); + } + to { + transform: translateX(-50%); + } +} + +@keyframes marquee-scroll-ar { + from { + transform: translateX(0); + } + to { + transform: translateX(50%); + } +} diff --git a/common/api.js b/common/api.js index 52e2fb1..f865729 100644 --- a/common/api.js +++ b/common/api.js @@ -756,6 +756,53 @@ var default_api = 'https://api.global-interaction.com/'; }, }; + // 转盘 H5 只通过 gateway 活动接口读配置、抽奖、查记录和跑马灯提示;页面不再内置 mock 奖品,避免后台资源组未配置时前端仍展示假奖池。 + // 抽奖 command_id 由页面点击时生成并随请求提交,服务端用它做幂等,网络重试不会重复扣费或重复发奖。 + var activityWheelAPI = { + config: function (wheelID) { + return request( + '/api/v1/activity/wheel/' + + encodeURIComponent(wheelID || 'classic') + + '/config', + { method: 'GET' } + ); + }, + draw: function (wheelID, payload) { + return request( + '/api/v1/activity/wheel/' + + encodeURIComponent(wheelID || 'classic') + + '/draw', + { + method: 'POST', + body: payload || {}, + } + ); + }, + history: function (wheelID, params) { + return request( + '/api/v1/activity/wheel/' + + encodeURIComponent(wheelID || 'classic') + + '/history', + { + method: 'POST', + query: params || {}, + body: {}, + } + ); + }, + hints: function (wheelID) { + return request( + '/api/v1/activity/wheel/' + + encodeURIComponent(wheelID || 'classic') + + '/hints', + { + method: 'POST', + body: {}, + } + ); + }, + }; + // 邀请活动 H5 只关心当前用户本月状态和领取动作;有效人数、累计充值和最高档差额都以后端聚合事实为准。 // 领取时页面必须传入本次点击生成的 command_id,服务端按用户、周期、档位和 command_id 做幂等发奖。 var inviteActivityRewardAPI = { @@ -938,6 +985,7 @@ var default_api = 'https://api.global-interaction.com/'; roleInvitations: roleInvitationAPI, managerCenter: managerCenterAPI, superadminCenter: superadminCenterAPI, + activityWheel: activityWheelAPI, level: levelAPI, task: taskAPI, weeklyStar: weeklyStarAPI, diff --git a/common/i18n.js b/common/i18n.js index 9c1f9e9..e742bb5 100644 --- a/common/i18n.js +++ b/common/i18n.js @@ -106,11 +106,7 @@ function resolveLang() { var requestedLang = queryLang(); if (requestedLang) return normalizeLang(requestedLang) || DEFAULT_LANG; - return ( - normalizeLang(storageGet(STORAGE_KEY)) || - normalizeLang(window.navigator.language) || - DEFAULT_LANG - ); + return DEFAULT_LANG; } function load(lang) { diff --git a/common/locales/ar.json b/common/locales/ar.json index 10b6a25..b7cc8fd 100644 --- a/common/locales/ar.json +++ b/common/locales/ar.json @@ -65,6 +65,27 @@ "rechargeReward.idPrefix": "المعرّف:", "rechargeReward.accumulatedRecharge": "إجمالي الشحن:", "rechargeReward.rechargeTitle": "اشحن {amount}", + "wheel.pageTitle": "عجلة يومي", + "wheel.pageLabel": "عجلة يومي", + "wheel.classic": "كلاسيكي", + "wheel.inLove": "رفاهية", + "wheel.advanced": "متقدم", + "wheel.historyRecord": "سجل التاريخ", + "wheel.rewardTips": "تهانينا على استلام: هدية ثمينة بقيمة {} قطعة ذهبية! وُضعت في حقيبة الظهر.", + "wheel.drawAgain": "اسحب مرة أخرى.", + "wheel.userAward": "تهانينا لـ {1} على حصوله على جائزة {2}", + "wheel.roomId": "لا يمكن أن يكون معرف الغرفة فارغًا", + "wheel.rule1": "1. اختر عجلة واسحب باستخدام العملات.", + "wheel.rule2": "2. يتم إرسال الجوائز إلى الحقيبة بعد نجاح السحب.", + "wheel.rule3": "3. لا علاقة لهذا النشاط بشركة Apple أو Google.", + "wheel.common.loading": "جارٍ التحميل", + "wheel.common.rule": "قاعدة", + "wheel.common.rewards": "المكافآت", + "wheel.common.balance": "الرصيد", + "wheel.common.noDate": "لا مزيد من البيانات", + "wheel.common.balanceNotEnough": "رصيد غير كاف", + "wheel.common.rewardUnavailable": "المكافآت غير متاحة بعد", + "wheel.common.requestFailed": "فشل الطلب", "invite.pageAria": "دعوة الأصدقاء", "invite.heroAria": "ادع الأصدقاء واكسب المال", "invite.countdownAria": "العد التنازلي", @@ -557,6 +578,7 @@ "agencyOpening.joined": "تم الانضمام", "agencyOpening.notJoined": "لم ينضم", "agencyOpening.applied": "تم التقديم", + "agencyOpening.pendingReview": "بانتظار المراجعة", "agencyOpening.applySuccess": "تم إرسال الطلب.", "agencyOpening.applyFailed": "فشل الطلب. حاول لاحقا.", "agencyOpening.rewardsTitle": "مكافآت الافتتاح", @@ -567,8 +589,8 @@ "agencyOpening.rule2": "يجب أن يكون عدد المضيفين أكثر من 10.", "agencyOpening.rule3": "يجب أن يكون عمر الوكالة أقل من 7 أيام.", "agencyOpening.rule4": "يمكن لكل وكالة المشاركة مرة واحدة فقط.", - "agencyOpening.rule5": "لا يمكن تشغيل فعالية الافتتاح مع برنامج دعم الوكالات في نفس الوقت.", - "agencyOpening.rule6": "ترسل المكافآت خلال 7 أيام بعد المراجعة.", + "agencyOpening.rule5": "تبدأ إيرادات الافتتاح بعد موافقة المسؤول وتحتسب لمدة 24 ساعة فقط.", + "agencyOpening.rule6": "ترسل المكافآت تلقائيا بعد انتهاء الفعالية.", "agencyOpening.recordTitle": "سجل الافتتاح", "agencyOpening.guildName": "اسم النقابة:", "agencyOpening.created": "تاريخ الإنشاء:", diff --git a/common/locales/en.json b/common/locales/en.json index c5db14e..8ea5f17 100644 --- a/common/locales/en.json +++ b/common/locales/en.json @@ -65,6 +65,27 @@ "rechargeReward.idPrefix": "ID:", "rechargeReward.accumulatedRecharge": "Accumulated Recharge:", "rechargeReward.rechargeTitle": "Recharge {amount}", + "wheel.pageTitle": "Yumi Wheel", + "wheel.pageLabel": "Yumi Wheel", + "wheel.classic": "Classic", + "wheel.inLove": "luxury", + "wheel.advanced": "Advanced", + "wheel.historyRecord": "History Record", + "wheel.rewardTips": "Congratulations on receiving: A precious gift worth {} gold coins! Already put in the backpack", + "wheel.drawAgain": "Draw again", + "wheel.userAward": "Congratulations to {1} for receiving the {2} award", + "wheel.roomId": "Room ID cannot be empty", + "wheel.rule1": "1. Select a wheel and draw with coins.", + "wheel.rule2": "2. Rewards are issued to the backpack after a successful draw.", + "wheel.rule3": "3. This activity has no relationship with Apple or Google.", + "wheel.common.loading": "Loading", + "wheel.common.rule": "rule", + "wheel.common.rewards": "Rewards", + "wheel.common.balance": "Balance", + "wheel.common.noDate": "No more data", + "wheel.common.balanceNotEnough": "Insufficient balance", + "wheel.common.rewardUnavailable": "Rewards are not available yet", + "wheel.common.requestFailed": "Request failed", "invite.pageAria": "Invite friends", "invite.heroAria": "Invite friends make money", "invite.countdownAria": "Countdown", @@ -563,6 +584,7 @@ "agencyOpening.joined": "Joined", "agencyOpening.notJoined": "Not Joined", "agencyOpening.applied": "Applied", + "agencyOpening.pendingReview": "Pending Review", "agencyOpening.applySuccess": "Application submitted.", "agencyOpening.applyFailed": "Application failed. Try again later.", "agencyOpening.rewardsTitle": "Opening Rewards", @@ -573,8 +595,8 @@ "agencyOpening.rule2": "Host count must be more than 10.", "agencyOpening.rule3": "Agency age must be less than 7 days.", "agencyOpening.rule4": "Each agency can join only once in lifetime.", - "agencyOpening.rule5": "Opening Event cannot run with Agency Support Program at the same time.", - "agencyOpening.rule6": "Rewards will be sent within 7 days after review.", + "agencyOpening.rule5": "Opening revenue starts after admin approval and counts for 24 hours only.", + "agencyOpening.rule6": "Rewards will be sent automatically after the activity ends.", "agencyOpening.recordTitle": "Opening Record", "agencyOpening.guildName": "Guild Name:", "agencyOpening.created": "Created:", diff --git a/common/locales/es.json b/common/locales/es.json index cd12ecf..207416a 100644 --- a/common/locales/es.json +++ b/common/locales/es.json @@ -65,6 +65,27 @@ "rechargeReward.idPrefix": "ID:", "rechargeReward.accumulatedRecharge": "Recarga acumulada:", "rechargeReward.rechargeTitle": "Recarga {amount}", + "wheel.pageTitle": "Rueda de Yumi", + "wheel.pageLabel": "Rueda de Yumi", + "wheel.classic": "Clásico", + "wheel.inLove": "lujo", + "wheel.advanced": "Avanzado", + "wheel.historyRecord": "Historial", + "wheel.rewardTips": "Felicidades por recibir: un regalo valioso de {} monedas de oro. Ya está en la mochila", + "wheel.drawAgain": "Girar otra vez", + "wheel.userAward": "Felicidades a {1} por recibir el premio {2}", + "wheel.roomId": "El ID de la sala no puede estar vacío", + "wheel.rule1": "1. Selecciona una rueda y gira con monedas.", + "wheel.rule2": "2. Las recompensas se envían a la mochila tras un sorteo exitoso.", + "wheel.rule3": "3. Esta actividad no tiene relación con Apple ni Google.", + "wheel.common.loading": "Cargando", + "wheel.common.rule": "regla", + "wheel.common.rewards": "Recompensas", + "wheel.common.balance": "Saldo", + "wheel.common.noDate": "No hay más datos", + "wheel.common.balanceNotEnough": "Saldo insuficiente", + "wheel.common.rewardUnavailable": "Las recompensas aún no están disponibles", + "wheel.common.requestFailed": "Solicitud fallida", "invite.pageAria": "Invitar amigos", "invite.heroAria": "Invita amigos y gana dinero", "invite.countdownAria": "Cuenta regresiva", @@ -557,6 +578,7 @@ "agencyOpening.joined": "Unido", "agencyOpening.notJoined": "No unido", "agencyOpening.applied": "Solicitado", + "agencyOpening.pendingReview": "Pendiente de revisión", "agencyOpening.applySuccess": "Solicitud enviada.", "agencyOpening.applyFailed": "Solicitud fallida. Inténtalo más tarde.", "agencyOpening.rewardsTitle": "Recompensas de apertura", @@ -567,8 +589,8 @@ "agencyOpening.rule2": "La cantidad de hosts debe ser mayor que 10.", "agencyOpening.rule3": "La agencia debe tener menos de 7 días.", "agencyOpening.rule4": "Cada agencia solo puede participar una vez.", - "agencyOpening.rule5": "El evento de apertura no puede ejecutarse junto con el Programa de soporte de agencias.", - "agencyOpening.rule6": "Las recompensas se enviarán dentro de 7 días después de la revisión.", + "agencyOpening.rule5": "Los ingresos de apertura comienzan tras la aprobación del admin y solo cuentan durante 24 horas.", + "agencyOpening.rule6": "Las recompensas se envían automáticamente cuando termina la actividad.", "agencyOpening.recordTitle": "Registro de apertura", "agencyOpening.guildName": "Nombre del gremio:", "agencyOpening.created": "Creado:", diff --git a/common/locales/id.json b/common/locales/id.json index e900cc7..2b461f5 100644 --- a/common/locales/id.json +++ b/common/locales/id.json @@ -32,6 +32,27 @@ "rechargeReward.idPrefix": "ID:", "rechargeReward.accumulatedRecharge": "Recharge akumulatif:", "rechargeReward.rechargeTitle": "Recharge {amount}", + "wheel.pageTitle": "Yumi Wheel", + "wheel.pageLabel": "Yumi Wheel", + "wheel.classic": "Classic", + "wheel.inLove": "Luxury", + "wheel.advanced": "Advanced", + "wheel.historyRecord": "Riwayat Hadiah", + "wheel.rewardTips": "Selamat mendapatkan: hadiah bernilai {} koin emas! Sudah masuk ke backpack", + "wheel.drawAgain": "Undi lagi", + "wheel.userAward": "Selamat kepada {1} karena menerima hadiah {2}", + "wheel.roomId": "ID room tidak boleh kosong", + "wheel.rule1": "1. Pilih wheel dan undi dengan koin.", + "wheel.rule2": "2. Hadiah dikirim ke backpack setelah undian berhasil.", + "wheel.rule3": "3. Aktivitas ini tidak berhubungan dengan Apple atau Google.", + "wheel.common.loading": "Memuat", + "wheel.common.rule": "Aturan", + "wheel.common.rewards": "Hadiah", + "wheel.common.balance": "Saldo", + "wheel.common.noDate": "Tidak ada data lagi", + "wheel.common.balanceNotEnough": "Saldo tidak cukup", + "wheel.common.rewardUnavailable": "Hadiah belum tersedia", + "wheel.common.requestFailed": "Permintaan gagal", "invite.pageAria": "Undang teman", "invite.heroAria": "Undang teman dan hasilkan uang", "invite.countdownAria": "Hitung mundur", @@ -524,6 +545,7 @@ "agencyOpening.joined": "Sudah bergabung", "agencyOpening.notJoined": "Belum bergabung", "agencyOpening.applied": "Sudah diajukan", + "agencyOpening.pendingReview": "Menunggu peninjauan", "agencyOpening.applySuccess": "Pengajuan terkirim.", "agencyOpening.applyFailed": "Pengajuan gagal. Coba lagi nanti.", "agencyOpening.rewardsTitle": "Hadiah Pembukaan", @@ -534,8 +556,8 @@ "agencyOpening.rule2": "Jumlah host harus lebih dari 10.", "agencyOpening.rule3": "Usia agensi harus kurang dari 7 hari.", "agencyOpening.rule4": "Setiap agensi hanya dapat ikut sekali seumur hidup.", - "agencyOpening.rule5": "Event Pembukaan tidak dapat berjalan bersama Program Dukungan Agensi.", - "agencyOpening.rule6": "Hadiah dikirim dalam 7 hari setelah peninjauan.", + "agencyOpening.rule5": "Pendapatan pembukaan mulai dihitung setelah disetujui admin dan hanya berlaku 24 jam.", + "agencyOpening.rule6": "Hadiah dikirim otomatis setelah aktivitas berakhir.", "agencyOpening.recordTitle": "Catatan Pembukaan", "agencyOpening.guildName": "Nama guild:", "agencyOpening.created": "Dibuat:", diff --git a/common/locales/tr.json b/common/locales/tr.json index 0d0b7ab..26809b1 100644 --- a/common/locales/tr.json +++ b/common/locales/tr.json @@ -32,6 +32,27 @@ "rechargeReward.idPrefix": "ID:", "rechargeReward.accumulatedRecharge": "Toplam yükleme:", "rechargeReward.rechargeTitle": "{amount} yükle", + "wheel.pageTitle": "Yumi Çarkı", + "wheel.pageLabel": "Yumi Çarkı", + "wheel.classic": "Klasik", + "wheel.inLove": "lüks", + "wheel.advanced": "Gelişmiş", + "wheel.historyRecord": "Tarih Kaydı", + "wheel.rewardTips": "Aldığınız için tebrikler: {} altın değerinde değerli bir hediye! Zaten sırt çantasına koydum", + "wheel.drawAgain": "Tekrar çekiliş", + "wheel.userAward": "{1}'i {2} ödülünü aldığı için tebrik ederiz", + "wheel.roomId": "Oda kimliği boş olamaz", + "wheel.rule1": "1. Bir çark seçin ve coin ile çekiliş yapın.", + "wheel.rule2": "2. Başarılı çekilişten sonra ödüller çantaya gönderilir.", + "wheel.rule3": "3. Bu etkinliğin Apple veya Google ile ilişkisi yoktur.", + "wheel.common.loading": "Yükleniyor", + "wheel.common.rule": "kural", + "wheel.common.rewards": "Ödüller", + "wheel.common.balance": "Bakiye", + "wheel.common.noDate": "Artık veri yok", + "wheel.common.balanceNotEnough": "Yetersiz bakiye", + "wheel.common.rewardUnavailable": "Ödüller henüz mevcut değil", + "wheel.common.requestFailed": "İstek başarısız", "invite.pageAria": "Arkadaş davet et", "invite.heroAria": "Arkadaş davet et, para kazan", "invite.countdownAria": "Geri sayım", @@ -524,6 +545,7 @@ "agencyOpening.joined": "Katıldı", "agencyOpening.notJoined": "Katılmadı", "agencyOpening.applied": "Başvuruldu", + "agencyOpening.pendingReview": "İnceleme bekliyor", "agencyOpening.applySuccess": "Başvuru gönderildi.", "agencyOpening.applyFailed": "Başvuru başarısız. Daha sonra tekrar deneyin.", "agencyOpening.rewardsTitle": "Açılış Ödülleri", @@ -534,8 +556,8 @@ "agencyOpening.rule2": "Host sayısı 10'dan fazla olmalıdır.", "agencyOpening.rule3": "Ajans yaşı 7 günden az olmalıdır.", "agencyOpening.rule4": "Her ajans ömür boyu yalnızca bir kez katılabilir.", - "agencyOpening.rule5": "Açılış Etkinliği Ajans Destek Programı ile aynı anda çalışamaz.", - "agencyOpening.rule6": "Ödüller incelemeden sonra 7 gün içinde gönderilir.", + "agencyOpening.rule5": "Açılış geliri admin onayından sonra başlar ve yalnızca 24 saat sayılır.", + "agencyOpening.rule6": "Ödüller etkinlik bittikten sonra otomatik gönderilir.", "agencyOpening.recordTitle": "Açılış Kaydı", "agencyOpening.guildName": "Lonca adı:", "agencyOpening.created": "Oluşturuldu:", diff --git a/common/locales/zh.json b/common/locales/zh.json index ee9d61f..1539a7a 100644 --- a/common/locales/zh.json +++ b/common/locales/zh.json @@ -32,6 +32,27 @@ "rechargeReward.idPrefix": "ID:", "rechargeReward.accumulatedRecharge": "累计充值:", "rechargeReward.rechargeTitle": "充值 {amount}", + "wheel.pageTitle": "Yumi 转盘", + "wheel.pageLabel": "Yumi 转盘", + "wheel.classic": "Classic", + "wheel.inLove": "Luxury", + "wheel.advanced": "Advanced", + "wheel.historyRecord": "中奖历史", + "wheel.rewardTips": "恭喜获得:价值 {} 金币的珍贵礼物!已放入背包", + "wheel.drawAgain": "再抽一次", + "wheel.userAward": "恭喜 {1} 获得 {2} 奖励", + "wheel.roomId": "房间 ID 不能为空", + "wheel.rule1": "1. 选择转盘并消耗金币抽奖。", + "wheel.rule2": "2. 抽中奖品后会发放到背包。", + "wheel.rule3": "3. 本活动与 Apple 或 Google 无关。", + "wheel.common.loading": "加载中", + "wheel.common.rule": "规则", + "wheel.common.rewards": "奖励", + "wheel.common.balance": "余额", + "wheel.common.noDate": "没有更多数据", + "wheel.common.balanceNotEnough": "余额不足", + "wheel.common.rewardUnavailable": "奖池暂未开放", + "wheel.common.requestFailed": "请求失败", "invite.pageAria": "邀请好友", "invite.heroAria": "邀请好友赚钱", "invite.countdownAria": "倒计时", @@ -530,6 +551,7 @@ "agencyOpening.joined": "已参加", "agencyOpening.notJoined": "未参加", "agencyOpening.applied": "已申请", + "agencyOpening.pendingReview": "待审核", "agencyOpening.applySuccess": "申请已提交", "agencyOpening.applyFailed": "申请失败,请稍后再试", "agencyOpening.rewardsTitle": "开业奖励", @@ -540,8 +562,8 @@ "agencyOpening.rule2": "主播数量必须大于 10。", "agencyOpening.rule3": "代理创建时间必须小于 7 天。", "agencyOpening.rule4": "每个代理终身只能参加一次。", - "agencyOpening.rule5": "开业活动不能和代理扶持计划同时进行。", - "agencyOpening.rule6": "奖励会在审核通过后 7 天内发放。", + "agencyOpening.rule5": "开业流水从后台同意后开始计算,只统计 24 小时内的房间流水。", + "agencyOpening.rule6": "活动结束后按开业流水档位自动发放奖励。", "agencyOpening.recordTitle": "开业记录", "agencyOpening.guildName": "公会名称:", "agencyOpening.created": "创建时间:", diff --git a/gonghui/manager-center/index.html b/gonghui/manager-center/index.html index 2ad0a4c..448ae4f 100644 --- a/gonghui/manager-center/index.html +++ b/gonghui/manager-center/index.html @@ -11,7 +11,7 @@ @@ -474,6 +474,6 @@ - + diff --git a/gonghui/manager-center/script.js b/gonghui/manager-center/script.js index 5fa3690..06a0b57 100644 --- a/gonghui/manager-center/script.js +++ b/gonghui/manager-center/script.js @@ -15,6 +15,15 @@ 'send-frame': 'avatar_frame', 'send-car': 'vehicle', }; + var ACTION_PERMISSION_KEYS = { + 'send-frame': 'canGrantAvatarFrame', + 'send-car': 'canGrantVehicle', + 'update-user-level': 'canUpdateUserLevel', + 'add-bd-leader': 'canAddBdLeader', + 'add-admin': 'canAddAdmin', + 'add-superadmin': 'canAddSuperadmin', + 'block-user': 'canBlockUser', + }; var RESOURCE_GRANT_DURATIONS = [ { label: '7 days', ms: 7 * DAY_MS }, { label: '30 days', ms: 30 * DAY_MS }, @@ -32,6 +41,7 @@ loading: true, denied: false, overview: null, + permissions: {}, resourcesByType: {}, }; var blockState = { @@ -210,6 +220,73 @@ }; } + function normalizePermissions(raw) { + raw = raw || {}; + return { + canGrantAvatarFrame: + raw.canGrantAvatarFrame !== undefined + ? Boolean(raw.canGrantAvatarFrame) + : raw.can_grant_avatar_frame !== undefined + ? Boolean(raw.can_grant_avatar_frame) + : true, + canGrantVehicle: + raw.canGrantVehicle !== undefined + ? Boolean(raw.canGrantVehicle) + : raw.can_grant_vehicle !== undefined + ? Boolean(raw.can_grant_vehicle) + : true, + canUpdateUserLevel: + raw.canUpdateUserLevel !== undefined + ? Boolean(raw.canUpdateUserLevel) + : raw.can_update_user_level !== undefined + ? Boolean(raw.can_update_user_level) + : true, + canAddBdLeader: + raw.canAddBdLeader !== undefined + ? Boolean(raw.canAddBdLeader) + : raw.can_add_bd_leader !== undefined + ? Boolean(raw.can_add_bd_leader) + : true, + canAddAdmin: + raw.canAddAdmin !== undefined + ? Boolean(raw.canAddAdmin) + : raw.can_add_admin !== undefined + ? Boolean(raw.can_add_admin) + : true, + canAddSuperadmin: + raw.canAddSuperadmin !== undefined + ? Boolean(raw.canAddSuperadmin) + : raw.can_add_superadmin !== undefined + ? Boolean(raw.can_add_superadmin) + : true, + canBlockUser: + raw.canBlockUser !== undefined + ? Boolean(raw.canBlockUser) + : raw.can_block_user !== undefined + ? Boolean(raw.can_block_user) + : true, + }; + } + + function canUseAction(action) { + var key = ACTION_PERMISSION_KEYS[action]; + if (!key) return true; + return pageState.permissions[key] !== false; + } + + function renderActionPermissions() { + document.querySelectorAll('[data-action]').forEach(function (button) { + var action = button.getAttribute('data-action'); + button.hidden = !canUseAction(action); + }); + } + + function ensureActionAllowed(action) { + if (canUseAction(action)) return true; + toast('Permission denied.'); + return false; + } + function apiSearchUser(keyword) { if (!api || !api.searchUsers) { return Promise.reject(new Error('API not available.')); @@ -231,8 +308,12 @@ .overview() .then(function (data) { pageState.overview = data || {}; + pageState.permissions = normalizePermissions( + pageState.overview.permissions || pageState.overview + ); + renderActionPermissions(); setDenied(false); - return refreshBlocks(); + return canUseAction('block-user') ? refreshBlocks() : Promise.resolve(); }) .catch(function (error) { setDenied(true); @@ -503,6 +584,7 @@ toast('Permission denied.'); return; } + if (!ensureActionAllowed('block-user')) return; var modal = $('blockModal'); if (!modal) return; resetBlockSearch(); @@ -539,6 +621,7 @@ toast('Permission denied.'); return; } + if (!ensureActionAllowed('update-user-level')) return; var modal = $('levelModal'); if (!modal) return; resetLevelSearch(); @@ -693,6 +776,7 @@ toast('Permission denied.'); return; } + if (!ensureActionAllowed(action)) return; ensureGrantModal(); grantState.action = action; grantState.resourceType = RESOURCE_TYPES[action] || ''; @@ -915,6 +999,7 @@ toast('Permission denied.'); return; } + if (!ensureActionAllowed(action)) return; ensureBDLeaderModal(); bdLeaderState.action = action; bdLeaderState.title = ACTION_LABELS[action] || 'Add BD Leader'; @@ -1016,6 +1101,9 @@ document.querySelectorAll('[data-action]').forEach(function (button) { button.addEventListener('click', function () { var action = button.getAttribute('data-action'); + if (!ensureActionAllowed(action)) { + return; + } if (action === 'block-user') { openBlockModal(); return;