From 224808a3e344d1213da103da0e5da5b3142b87e2 Mon Sep 17 00:00:00 2001 From: zhx Date: Tue, 30 Jun 2026 20:50:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=82=80=E8=AF=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- activity/invite/index.html | 5 +- activity/invite/script.js | 127 ++++++++++++++++++++++++++++++++++++- activity/invite/style.css | 14 ++-- 3 files changed, 138 insertions(+), 8 deletions(-) diff --git a/activity/invite/index.html b/activity/invite/index.html index 2063efc..e9ed401 100644 --- a/activity/invite/index.html +++ b/activity/invite/index.html @@ -7,7 +7,7 @@ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" /> Invite Friends - +
Bind User @@ -315,6 +316,6 @@ - + diff --git a/activity/invite/script.js b/activity/invite/script.js index 296a109..458e755 100644 --- a/activity/invite/script.js +++ b/activity/invite/script.js @@ -20,6 +20,7 @@ 'ios_url', 'url', ]; + var BIND_INVITE_VISIBLE_WINDOW_MS = 48 * 60 * 60 * 1000; var params = new URLSearchParams(window.location.search); var state = { inviteCode: firstParam(INVITE_CODE_KEYS), @@ -27,6 +28,9 @@ inviterAvatar: firstParam(SHARE_AVATAR_KEYS), inviteLink: '', currentUser: null, + currentUserCreatedAtMS: 0, + currentUserTimingLoaded: false, + serverTimeMS: 0, pendingInviteCode: '', searchedInviter: null, inviteRewardStatus: null, @@ -58,12 +62,17 @@ return textValue(value).toUpperCase(); } - function readPath(source, path) { + function readRawPath(source, path) { var value = source; for (var i = 0; i < path.length; i += 1) { if (!value || typeof value !== 'object') return ''; value = value[path[i]]; } + return value; + } + + function readPath(source, path) { + var value = readRawPath(source, path); return textValue(value); } @@ -75,6 +84,25 @@ return ''; } + function normalizeTimestampMS(value) { + if (value === undefined || value === null || value === '') return 0; + if (typeof value === 'string' && !String(value).trim()) return 0; + var number = Number(value); + if (Number.isFinite(number) && number > 0) { + return number < 100000000000 ? number * 1000 : number; + } + var parsed = Date.parse(value); + return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; + } + + function firstTimestampMS(source, paths) { + for (var i = 0; i < paths.length; i += 1) { + var value = normalizeTimestampMS(readRawPath(source, paths[i])); + if (value) return value; + } + return 0; + } + function currentUserPayload(data, profile) { var target = profile || data || {}; return Boolean( @@ -84,6 +112,8 @@ target.displayUserId || target.username || target.nickname || + target.created_at_ms !== undefined || + target.createdAtMs !== undefined || target.profile_completed !== undefined || target.profileCompleted !== undefined ); @@ -137,10 +167,97 @@ return payload && payload.user ? payload.user : payload; } + function applyCurrentUserTiming(data, profile) { + var serverTimeMS = firstTimestampMS(data, [ + ['server_time_ms'], + ['serverTimeMS'], + ['serverTimeMs'], + ['server_time'], + ['serverTime'], + ]); + var createdAtMS = firstTimestampMS(data, [ + ['profile', 'created_at_ms'], + ['profile', 'createdAtMs'], + ['profile', 'created_at'], + ['profile', 'createdAt'], + ['profile', 'registered_at_ms'], + ['profile', 'registeredAtMs'], + ['profile', 'registered_at'], + ['profile', 'registeredAt'], + ['created_at_ms'], + ['createdAtMs'], + ['created_at'], + ['createdAt'], + ['registered_at_ms'], + ['registeredAtMs'], + ['registered_at'], + ['registeredAt'], + ]); + if (!createdAtMS) { + createdAtMS = firstTimestampMS(profile, [ + ['created_at_ms'], + ['createdAtMs'], + ['created_at'], + ['createdAt'], + ['registered_at_ms'], + ['registeredAtMs'], + ['registered_at'], + ['registeredAt'], + ]); + } + if (serverTimeMS) state.serverTimeMS = serverTimeMS; + if (createdAtMS) state.currentUserCreatedAtMS = createdAtMS; + } + + function bindInviteReferenceTimeMS() { + return state.serverTimeMS || Date.now(); + } + + function canShowBindInviteButton() { + var api = window.HyAppAPI || {}; + var hasToken = api.getAccessToken && api.getAccessToken(); + if (hasToken && !state.currentUserTimingLoaded) return false; + var current = state.currentUser || {}; + var createdAtMS = + state.currentUserCreatedAtMS || + firstTimestampMS(current, [ + ['created_at_ms'], + ['createdAtMs'], + ['created_at'], + ['createdAt'], + ['registered_at_ms'], + ['registeredAtMs'], + ['registered_at'], + ['registeredAt'], + ]); + if (!createdAtMS) return true; + // 48 小时窗口必须用服务端返回的当前时间优先判断;接口缺少时间时才退回本机时间,避免用户手动改系统时间影响显隐。 + return ( + bindInviteReferenceTimeMS() - createdAtMS <= + BIND_INVITE_VISIBLE_WINDOW_MS + ); + } + + function renderBindInviteVisibility() { + var button = $('#bindInviteButton'); + if (!button) return; + var visible = canShowBindInviteButton(); + button.hidden = !visible; + button.disabled = !visible; + if (visible || !$('#bindInviteModal') || $('#bindInviteModal').hidden) { + return; + } + closeBindModal(); + } + function applyCurrentUser(payload) { var data = readOverviewPayload(payload || {}); var profile = data.profile || data; - if (currentUserPayload(data, profile)) mergeCurrentUser(profile); + applyCurrentUserTiming(data, profile); + if (currentUserPayload(data, profile)) { + state.currentUserTimingLoaded = true; + mergeCurrentUser(profile); + } var inviteCode = firstPath(data, [ ['invite', 'my_invite_code'], ['invite', 'myInviteCode'], @@ -186,6 +303,7 @@ $('#statEligible').textContent = validInviteCount; } renderInviteShare(); + renderBindInviteVisibility(); } function loadCurrentUser() { @@ -826,6 +944,10 @@ } function openBindModal() { + if (!canShowBindInviteButton()) { + renderBindInviteVisibility(); + return; + } var api = window.HyAppAPI || {}; if (!api.getAccessToken || !api.getAccessToken()) { toast(t('invite.loginRequired', 'Please log in first')); @@ -1089,6 +1211,7 @@ renderRank(); updateCountdown(); setInterval(updateCountdown, 1000); + renderBindInviteVisibility(); bindEvents(); renderInviteActivityReward(null); Promise.all([ diff --git a/activity/invite/style.css b/activity/invite/style.css index bd20eea..88d5556 100644 --- a/activity/invite/style.css +++ b/activity/invite/style.css @@ -318,16 +318,20 @@ p { .invite-field { position: relative; + width: 100%; + min-width: 0; height: calc(93 * var(--u)); + overflow: hidden; background: url('./assets/link-input.svg') center / 100% 100% no-repeat; } .link-box { - display: flex; - align-items: center; - justify-content: flex-start; + display: block; + width: 100%; min-width: 0; + max-width: 100%; height: 100%; + line-height: calc(93 * var(--u)); padding: 0 calc(112 * var(--u)) 0 calc(52 * var(--u)); overflow: hidden; color: var(--gold); @@ -335,11 +339,13 @@ p { font-weight: 700; text-overflow: ellipsis; white-space: nowrap; + direction: ltr; + unicode-bidi: plaintext; } .invite-field.is-code .link-box { - justify-content: center; padding-left: calc(112 * var(--u)); + text-align: center; } .invite-code {