cp活动
This commit is contained in:
parent
de739902dc
commit
5d1d743990
@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" href="../../common/theme.css?v=20260608-cp" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="./style.css?v=20260625-cp-plaza-api-reward-auto"
|
||||
href="./style.css?v=20260716-cp-formation-gift-carousel"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
@ -177,7 +177,7 @@
|
||||
})();
|
||||
</script>
|
||||
<script src="../../common/i18n.js?v=20260608-cp"></script>
|
||||
<script src="../../common/api.js?v=20260625-cp-plaza-api"></script>
|
||||
<script src="./script.js?v=20260625-cp-plaza-api-reward-auto-coin"></script>
|
||||
<script src="../../common/api.js?v=20260716-cp-formation-gift"></script>
|
||||
<script src="./script.js?v=20260716-cp-formation-gift-carousel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -10,6 +10,11 @@
|
||||
var REWARD_PANEL_BOTTOM_PADDING = 80;
|
||||
var REWARD_STAGE_BOTTOM_PADDING = 133;
|
||||
var REWARD_MIN_PANEL_HEIGHT = 320;
|
||||
var PLAZA_VISIBLE_ROWS = 4;
|
||||
var PLAZA_ROW_HEIGHT = 199;
|
||||
var PLAZA_ROW_GAP = 24;
|
||||
var PLAZA_SECONDS_PER_ROW = 3.2;
|
||||
var PLAZA_FEED_LIMIT = 20;
|
||||
var STORAGE_KEY = 'hy_cp_activity_end_at';
|
||||
var stageHeights = {
|
||||
plaza: 4283,
|
||||
@ -210,10 +215,14 @@
|
||||
renderAvatar('avatar-left', row.leftAvatar),
|
||||
renderAvatar('avatar-right', row.rightAvatar),
|
||||
'<span class="name name-left">',
|
||||
'<bdi>',
|
||||
escapeHTML(row.leftName),
|
||||
'</bdi>',
|
||||
'</span>',
|
||||
'<span class="name name-right">',
|
||||
'<bdi>',
|
||||
escapeHTML(row.rightName),
|
||||
'</bdi>',
|
||||
'</span>',
|
||||
'<img class="deco-line deco-left" src="./assets/deco-line.png" alt="" aria-hidden="true" />',
|
||||
'<img class="deco-line deco-right" src="./assets/deco-line.png" alt="" aria-hidden="true" />',
|
||||
@ -222,6 +231,40 @@
|
||||
].join('');
|
||||
}
|
||||
|
||||
function renderPlazaCarousel(rows) {
|
||||
var sourceRows = Array.isArray(rows) ? rows : [];
|
||||
var shouldLoop = sourceRows.length > PLAZA_VISIBLE_ROWS;
|
||||
var rowHTML = sourceRows.map(renderCPRow).join('');
|
||||
var loopDistance =
|
||||
sourceRows.length * (PLAZA_ROW_HEIGHT + PLAZA_ROW_GAP);
|
||||
var loopDuration = Math.max(
|
||||
sourceRows.length * PLAZA_SECONDS_PER_ROW,
|
||||
PLAZA_VISIBLE_ROWS * PLAZA_SECONDS_PER_ROW
|
||||
);
|
||||
|
||||
// 一组数据末尾保留一个 row-gap,再紧接完全相同的第二组;轨道移动一整组高度后,第二组首行与初始首行位置一致,循环重置时不会闪白或跳帧。
|
||||
return [
|
||||
'<div class="plaza-carousel-viewport">',
|
||||
'<div class="plaza-carousel-track',
|
||||
shouldLoop ? ' is-looping' : '',
|
||||
'" style="--plaza-loop-distance:',
|
||||
loopDistance,
|
||||
'px;--plaza-loop-duration:',
|
||||
loopDuration,
|
||||
's">',
|
||||
'<div class="plaza-carousel-set">',
|
||||
rowHTML,
|
||||
'</div>',
|
||||
shouldLoop
|
||||
? '<div class="plaza-carousel-set" aria-hidden="true">' +
|
||||
rowHTML +
|
||||
'</div>'
|
||||
: '',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('');
|
||||
}
|
||||
|
||||
function renderPlaza() {
|
||||
var plazaRows = activityData.plazaRows || [];
|
||||
var previousRows = activityData.previousRows || [];
|
||||
@ -229,12 +272,10 @@
|
||||
'<h2 class="panel-title">',
|
||||
t(
|
||||
'cp.plazaGiftTitle',
|
||||
'CP pairs with intimacy ≥ 5000 are shown here'
|
||||
'CP formation gifts worth more than 5,000 coins are shown here'
|
||||
),
|
||||
'</h2>',
|
||||
'<div class="cp-list">',
|
||||
plazaRows.map(renderCPRow).join(''),
|
||||
'</div>',
|
||||
renderPlazaCarousel(plazaRows),
|
||||
].join('');
|
||||
var panels = [renderPanel('plaza-panel-a', 1816, 1152, firstBody)];
|
||||
if (previousRows.length) {
|
||||
@ -463,21 +504,37 @@
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePlazaEntry(entry) {
|
||||
var intimacyValue = Number(
|
||||
entry.intimacy_value || entry.intimacyValue || 0
|
||||
function normalizeFormationGiftEntry(entry) {
|
||||
var giftCoinValue = Number(
|
||||
(entry &&
|
||||
(entry.gift_coin_value ||
|
||||
entry.giftCoinValue ||
|
||||
entry.coin_spent ||
|
||||
entry.coinSpent)) ||
|
||||
0
|
||||
);
|
||||
var userA = normalizePairUser(entry.user_a);
|
||||
var userB = normalizePairUser(entry.user_b);
|
||||
if (intimacyValue < 5000 || !userA || !userB) return null;
|
||||
var requester = normalizePairUser(
|
||||
entry && (entry.requester || entry.user_a || entry.userA)
|
||||
);
|
||||
var target = normalizePairUser(
|
||||
entry && (entry.target || entry.user_b || entry.userB)
|
||||
);
|
||||
// 业务定义是“超过 5000 金币”,不是大于等于;即使旧网关误返回 5000 或更低的记录,H5 也不能把它展示出来。
|
||||
if (
|
||||
!Number.isFinite(giftCoinValue) ||
|
||||
giftCoinValue <= 5000 ||
|
||||
!requester ||
|
||||
!target
|
||||
)
|
||||
return null;
|
||||
return {
|
||||
type: 'score',
|
||||
rawScore: intimacyValue,
|
||||
score: formatScore(intimacyValue),
|
||||
leftName: userA.name,
|
||||
rightName: userB.name,
|
||||
leftAvatar: userA.avatar,
|
||||
rightAvatar: userB.avatar,
|
||||
rawGiftCoinValue: giftCoinValue,
|
||||
score: formatScore(giftCoinValue),
|
||||
leftName: requester.name,
|
||||
rightName: target.name,
|
||||
leftAvatar: requester.avatar,
|
||||
rightAvatar: target.avatar,
|
||||
};
|
||||
}
|
||||
|
||||
@ -549,18 +606,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
function applyPlazaLeaderboard(data) {
|
||||
function applyPlazaFormationGiftFeed(data) {
|
||||
var items = data && Array.isArray(data.items) ? data.items : [];
|
||||
// CP 广场只展示真实接口里亲密值达到门槛的 CP;接口为空或低于门槛时保持空列表,不再用 mock 用户兜底。
|
||||
// feed 由后端按 CP 成立时间倒序返回;H5 只做口径校验并保留返回顺序,不再按金币额排成另一个榜单。
|
||||
activityData.plazaRows = items
|
||||
.map(normalizePlazaEntry)
|
||||
.map(normalizeFormationGiftEntry)
|
||||
.filter(function (item) {
|
||||
return Boolean(item);
|
||||
})
|
||||
.sort(function (left, right) {
|
||||
return right.rawScore - left.rawScore;
|
||||
})
|
||||
.slice(0, 4);
|
||||
});
|
||||
}
|
||||
|
||||
function loadActivityStatus() {
|
||||
@ -575,23 +628,19 @@
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function loadPlazaLeaderboard() {
|
||||
function loadPlazaFormationGiftFeed() {
|
||||
if (
|
||||
!window.HyAppAPI ||
|
||||
!window.HyAppAPI.cpSpace ||
|
||||
!window.HyAppAPI.cpSpace.intimacyLeaderboard
|
||||
!window.HyAppAPI.cpSpace.formationGiftFeed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// 后端亲密榜已按亲密值降序聚合;H5 仍二次过滤 5000 门槛并限制 4 个,防止旧数据或异常分页把低亲密 CP 展示出来。
|
||||
// 20 条可让四行视窗持续轮播,同时限制头像 DOM 和图片解码数量;gateway/user-service 还会再次夹紧上限,避免参数被篡改后无界拉取。
|
||||
window.HyAppAPI.cpSpace
|
||||
.intimacyLeaderboard({
|
||||
relation_type: 'cp',
|
||||
page: 1,
|
||||
page_size: 4,
|
||||
})
|
||||
.formationGiftFeed({ limit: PLAZA_FEED_LIMIT })
|
||||
.then(function (data) {
|
||||
applyPlazaLeaderboard(data);
|
||||
applyPlazaFormationGiftFeed(data);
|
||||
render();
|
||||
})
|
||||
.catch(function () {});
|
||||
@ -668,7 +717,7 @@
|
||||
countdownEndAt = resolveFallbackEndAt();
|
||||
bindTabs();
|
||||
render();
|
||||
loadPlazaLeaderboard();
|
||||
loadPlazaFormationGiftFeed();
|
||||
loadActivityStatus();
|
||||
countdownTimer = window.setInterval(updateCountdown, 1000);
|
||||
window.addEventListener('resize', updateStageHeight);
|
||||
|
||||
@ -372,6 +372,38 @@ button {
|
||||
top: 170px;
|
||||
}
|
||||
|
||||
.plaza-carousel-viewport {
|
||||
position: absolute;
|
||||
left: 60px;
|
||||
top: 170px;
|
||||
width: 840px;
|
||||
height: 868px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.plaza-carousel-track {
|
||||
width: 840px;
|
||||
will-change: auto;
|
||||
}
|
||||
|
||||
.plaza-carousel-track.is-looping {
|
||||
animation: plaza-carousel-scroll var(--plaza-loop-duration) linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.plaza-carousel-set {
|
||||
display: grid;
|
||||
row-gap: 24px;
|
||||
width: 840px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
@keyframes plaza-carousel-scroll {
|
||||
to {
|
||||
transform: translateY(calc(-1 * var(--plaza-loop-distance)));
|
||||
}
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
position: absolute;
|
||||
left: 55px;
|
||||
@ -454,6 +486,7 @@ button {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.cp-row .name-left {
|
||||
@ -492,15 +525,17 @@ button {
|
||||
|
||||
.score-value {
|
||||
position: absolute;
|
||||
left: 359px;
|
||||
left: 308px;
|
||||
top: 71px;
|
||||
width: 120px;
|
||||
width: 222px;
|
||||
height: 36px;
|
||||
color: #fff7f7;
|
||||
font-size: 30px;
|
||||
font-weight: 900;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-shadow:
|
||||
0 2px 0 #a51f32,
|
||||
0 0 8px rgba(255, 255, 255, 0.32);
|
||||
@ -729,3 +764,11 @@ html[dir='rtl'] .reward-note {
|
||||
html[dir='rtl'] .language-switcher {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.plaza-carousel-track.is-looping {
|
||||
animation: none;
|
||||
transform: none;
|
||||
will-change: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1892,6 +1892,12 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
query: params || {},
|
||||
});
|
||||
},
|
||||
formationGiftFeed: function (params) {
|
||||
return request('/api/v1/cp/formation-gift-feed', {
|
||||
method: 'GET',
|
||||
query: params || {},
|
||||
});
|
||||
},
|
||||
intimacyLeaderboard: function (params) {
|
||||
return request('/api/v1/cp/intimacy-leaderboard', {
|
||||
method: 'GET',
|
||||
|
||||
@ -520,8 +520,8 @@
|
||||
"cp.tabPlaza": "ساحة CP",
|
||||
"cp.tabRank": "ترتيب CP",
|
||||
"cp.tabRewards": "المكافآت",
|
||||
"cp.plazaGiftTitle": "سيتم عرض أزواج CP التي لديها قيمة ألفة >= 5000 هنا",
|
||||
"cp.plazaGiftSubtitle": "(عرض آخر 10 سجلات مرتبة تصاعديا.)",
|
||||
"cp.plazaGiftTitle": "تظهر هنا هدايا تكوين CP التي تزيد قيمتها عن 5,000 عملة",
|
||||
"cp.plazaGiftSubtitle": "تُعرض أحدث أزواج CP المؤهلة هنا باستمرار.",
|
||||
"cp.previousNo1Title": "أفضل 3 في الفترة السابقة",
|
||||
"cp.rewardMedal7": "وسام*7 أيام",
|
||||
"cp.rewardMedalNote": "(وسام دائم بعد الحصول عليه 3 مرات)",
|
||||
|
||||
@ -526,8 +526,8 @@
|
||||
"cp.tabPlaza": "CP Plaza",
|
||||
"cp.tabRank": "CP Rank",
|
||||
"cp.tabRewards": "Rewards",
|
||||
"cp.plazaGiftTitle": "CP pairs with intimacy >= 5000 are shown here",
|
||||
"cp.plazaGiftSubtitle": "(Display the last 10 records, sorted in ascending order.)",
|
||||
"cp.plazaGiftTitle": "CP formation gifts worth more than 5,000 coins are shown here",
|
||||
"cp.plazaGiftSubtitle": "The latest qualifying CP pairs scroll here continuously.",
|
||||
"cp.previousNo1Title": "Previous Top 3",
|
||||
"cp.rewardMedal7": "Medal*7 days",
|
||||
"cp.rewardMedalNote": "(Permanent medal after getting 3 times)",
|
||||
|
||||
@ -520,8 +520,8 @@
|
||||
"cp.tabPlaza": "Plaza CP",
|
||||
"cp.tabRank": "Ranking CP",
|
||||
"cp.tabRewards": "Recompensas",
|
||||
"cp.plazaGiftTitle": "Los CP con intimidad >= 5000 se mostrarán aquí",
|
||||
"cp.plazaGiftSubtitle": "(Muestra los últimos 10 registros en orden ascendente.)",
|
||||
"cp.plazaGiftTitle": "Aquí se muestran los regalos para formar CP que valen más de 5.000 monedas",
|
||||
"cp.plazaGiftSubtitle": "Las parejas CP elegibles más recientes se desplazan aquí continuamente.",
|
||||
"cp.previousNo1Title": "Top 3 anterior",
|
||||
"cp.rewardMedal7": "Medalla*7 días",
|
||||
"cp.rewardMedalNote": "(Medalla permanente tras obtenerla 3 veces)",
|
||||
|
||||
@ -487,8 +487,8 @@
|
||||
"cp.tabPlaza": "CP Plaza",
|
||||
"cp.tabRank": "Peringkat CP",
|
||||
"cp.tabRewards": "Hadiah",
|
||||
"cp.plazaGiftTitle": "CP dengan intimacy >= 5000 akan ditampilkan di sini",
|
||||
"cp.plazaGiftSubtitle": "(Menampilkan 10 catatan terbaru, diurutkan naik.)",
|
||||
"cp.plazaGiftTitle": "Hadiah pembentukan CP bernilai lebih dari 5.000 koin ditampilkan di sini",
|
||||
"cp.plazaGiftSubtitle": "Pasangan CP terbaru yang memenuhi syarat bergulir terus di sini.",
|
||||
"cp.previousNo1Title": "Top 3 periode sebelumnya",
|
||||
"cp.rewardMedal7": "Medali*7 hari",
|
||||
"cp.rewardMedalNote": "(Medali permanen setelah mendapatkannya 3 kali)",
|
||||
|
||||
@ -487,8 +487,8 @@
|
||||
"cp.tabPlaza": "CP Plaza",
|
||||
"cp.tabRank": "CP Sıralaması",
|
||||
"cp.tabRewards": "Ödüller",
|
||||
"cp.plazaGiftTitle": "Samimiyet değeri >= 5000 olan CP çiftleri burada görünür",
|
||||
"cp.plazaGiftSubtitle": "(Son 10 kayıt artan sırayla gösterilir.)",
|
||||
"cp.plazaGiftTitle": "5.000 coinden daha değerli CP kurma hediyeleri burada gösterilir",
|
||||
"cp.plazaGiftSubtitle": "Koşulları karşılayan en yeni CP çiftleri burada sürekli kayar.",
|
||||
"cp.previousNo1Title": "Önceki Top 3",
|
||||
"cp.rewardMedal7": "Madalya*7 gün",
|
||||
"cp.rewardMedalNote": "(3 kez alındıktan sonra kalıcı madalya)",
|
||||
|
||||
@ -493,8 +493,8 @@
|
||||
"cp.tabPlaza": "CP 广场",
|
||||
"cp.tabRank": "CP 排行",
|
||||
"cp.tabRewards": "奖励",
|
||||
"cp.plazaGiftTitle": "CP 之间亲密值 >= 5000 的 CP 会展示在这里",
|
||||
"cp.plazaGiftSubtitle": "(展示最近 10 条记录,按时间升序排列。)",
|
||||
"cp.plazaGiftTitle": "组 CP 时赠送价值超过 5000 金币的礼物会展示在这里",
|
||||
"cp.plazaGiftSubtitle": "最近符合条件的 CP 组合会在这里持续轮播。",
|
||||
"cp.previousNo1Title": "上期前三名",
|
||||
"cp.rewardMedal7": "勋章*7天",
|
||||
"cp.rewardMedalNote": "(获得 3 次后永久)",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user