Files
shaguabijia-app-server/h5/welfare/index.html
T

430 lines
32 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../shared/fonts.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>赚钱中心 · 傻瓜比价</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; overflow: hidden; }
body { font-family: 'PuHuiTi', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; background: #F5F5F5; color: #1A1A1A; }
:root {
--orange: #FF5722; --bg: #F5F5F5; --card: #FFFFFF; --aux: #999999; --text: #1A1A1A;
--cta-grad: linear-gradient(180deg, #FFE066 0%, #FFC400 100%);
--cta-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 2px 6px rgba(255,179,0,.35);
}
.num { font-family: "DIN Alternate", "Helvetica Neue", sans-serif; font-variant-numeric: tabular-nums; }
.device { position: relative; width: 100%; height: 100%; background: var(--bg); overflow: hidden; }
.screen { position: absolute; inset: 0; display: flex; flex-direction: column; }
/* 底部留出原生底部 tab 栏高度(内容区铺满、tab 栏盖其上)+ 手势条安全区 */
.scroll { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0 12px calc(80px + env(safe-area-inset-bottom, 0px)); }
.scroll::-webkit-scrollbar { display: none; }
.page-header { height: 50px; display: flex; align-items: center; justify-content: center; padding: 4px 4px 8px; }
.page-title { font-size: 20px; font-weight: 700; color: var(--text); line-height: 1; }
/* ===== 资产卡(与收益明细汇总卡同一套 UI:黄渐变) ===== */
.asset-card { position: relative; border-radius: 18px; padding: 16px; margin: 0 4px; overflow: hidden;
background: linear-gradient(180deg, #FFE86A 0%, #FFD600 100%); box-shadow: 0 6px 18px rgba(255,179,0,.22); }
.asset-cols { display: flex; gap: 22px; }
.asset-col { flex: 1; min-width: 0; cursor: pointer; }
.asset-label { display: inline-flex; align-items: center; gap: 2px; font-size: 15px; font-weight: 600; color: #1A1A1A; line-height: 20px; }
.asset-arrow { width: 13px; height: 13px; flex-shrink: 0; }
.asset-valrow { display: flex; align-items: center; gap: 8px; min-height: 31px; margin-top: 8px; }
.asset-val { font-size: 28px; font-weight: 700; color: #FF5A1F; line-height: 30px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chip { flex-shrink: 0; display: inline-flex; align-items: center; gap: 2px; height: 26px; padding: 0 10px; border-radius: 999px; background: #FFFFFF; border: none; box-shadow: 0 2px 6px rgba(139,94,0,.13); font-size: 12px; font-weight: 700; color: #1A1A1A; white-space: nowrap; cursor: pointer; }
.chip:active { transform: translateY(1px) scale(.98); }
.chip svg, .chip img { width: 16px; height: 16px; display: block; border-radius: 50%; }
.asset-note { font-size: 11px; font-weight: 400; color: rgba(26,26,26,.58); line-height: 15.4px; margin-top: 8px; }
/* 未登录卡:暖白 + 钱包插画 */
.asset-card.unlogged { background: radial-gradient(120% 90% at 100% 0%, rgba(255,214,0,.28) 0%, rgba(255,214,0,0) 55%), #FFFDF5; box-shadow: 0 4px 14px rgba(204,153,0,.08); min-height: 132px; display: flex; align-items: center; padding: 0 16px; }
.asset-illustration { position: absolute; right: 6px; bottom: 17px; width: 96px; z-index: 2; pointer-events: none; }
.asset-unlogged-body { display: flex; flex-direction: column; gap: 16px; padding-right: 112px; position: relative; z-index: 3; }
.asset-unlogged-title { font-size: 17px; font-weight: 700; color: var(--text); }
.login-btn { align-self: flex-start; height: 40px; padding: 0 28px; border-radius: 20px; border: none; background: var(--cta-grad); box-shadow: var(--cta-shadow); color: var(--text); font-size: 14px; font-weight: 700; letter-spacing: .04em; cursor: pointer; }
.login-btn:active { transform: translateY(1px) scale(.99); }
/* ===== 任务卡 ===== */
.task-card { background: var(--card); border-radius: 14px; padding: 20px 16px 16px; box-shadow: 0 4px 12px rgba(0,0,0,.04); margin-top: 16px; }
.section-title { font-size: 16px; font-weight: 600; color: var(--text); margin: 0 0 14px; }
/* 通用黄色 CTA + 红点 */
.cta { flex-shrink: 0; position: relative; border: none; border-radius: 32px; background: var(--cta-grad); box-shadow: var(--cta-shadow); color: var(--text); font-size: 12px; font-weight: 600; line-height: 29px; height: 29px; cursor: pointer; white-space: nowrap; }
.cta:active { transform: translateY(1px) scale(.98); }
.cta.gray { background: #F5F5F5; border: 1px solid #E5E5E5; box-shadow: none; color: var(--aux); }
.dot { position: absolute; top: -1px; right: -1px; width: 11px; height: 11px; border-radius: 50%; background: #FF3B30; box-shadow: 0 1px 4px rgba(255,59,48,.35); pointer-events: none; }
/* 签到行 + 时间线 */
.checkin-row { padding: 2px 0 24px; border-bottom: 1px solid #F0F0F0; }
.checkin-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.checkin-copy { min-width: 0; }
.checkin-title { font-size: 15px; font-weight: 500; color: var(--text); white-space: nowrap; }
.checkin-sub { font-size: 11px; font-weight: 400; color: var(--aux); margin-top: 6px; white-space: nowrap; }
.checkin-cta { width: 60px; min-width: 60px; padding: 0 12px; }
.timeline { position: relative; display: grid; grid-template-columns: repeat(5, minmax(0,1fr)); column-gap: 2px; margin-top: 20px; }
.step { position: relative; display: grid; grid-template-rows: 18px 22px 15px; row-gap: 2px; justify-items: center; }
.step-label { font-size: 11px; font-weight: 650; color: var(--aux); line-height: 18px; white-space: nowrap; }
.step-badge { padding: 0 8px; border-radius: 999px; background: #fff; color: #FFA000; font-size: 11px; line-height: 18px; font-weight: 900; box-shadow: 0 2px 8px rgba(0,0,0,.08); white-space: nowrap; }
.step-icon { box-sizing: border-box; width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.step-icon img { display: block; width: 22px; height: 22px; object-fit: contain; }
.step.done .step-icon { background: #FFF3E0; border: 1px solid #FFE066; box-shadow: inset 0 1px 0 rgba(255,255,255,.72); }
.step.done .step-icon::before { content: '✓'; color: #FFA000; font-size: 13px; line-height: 1; font-weight: 900; }
.step-amt { color: var(--aux); font-size: 11px; line-height: 1; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; }
.step.current .step-amt { color: #FF6A00; font-weight: 800; }
/* 连线:节点内容 z-index:1 盖住线,线 z-index:0(勿用 -1,会沉到卡片背景下看不见) */
.step > * { position: relative; z-index: 1; }
.step:not(:last-child)::after { content: ''; position: absolute; top: 30px; left: 50%; width: calc(100% + 2px); height: 2px; border-radius: 32px; background: #E5E5E5; z-index: 0; }
.step.gap-next::after { border-radius: 0; background: repeating-linear-gradient(90deg,#E5E5E5 0 3px, transparent 3px 8px); background-size: 8px 2px; background-repeat: repeat-x; }
/* 任务行 */
.task-row { display: flex; align-items: center; margin-top: 30px; }
.task-info { flex: 1; min-width: 0; }
.task-titlerow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.task-title { font-size: 15px; font-weight: 500; color: var(--text); line-height: 1.3; }
.task-coin { display: inline-flex; align-items: center; gap: 0; font-size: 12px; font-weight: 600; color: var(--orange); }
.task-coin .ci { width: 18px; height: 18px; flex-shrink: 0; margin-right: -2px; transform: scale(1.12); }
.task-sub { font-size: 11px; color: var(--aux); margin-top: 6px; font-weight: 400; line-height: 1.4; display: flex; align-items: center; gap: 6px; }
.task-tag { padding: 2px 5px 1px; border-radius: 4px; background: #FFF3E0; color: #E65100; font-size: 10px; font-weight: 700; }
.task-cta { min-width: 60px; padding: 0 12px; }
.task-row[hidden] { display: none; }
/* 规则入口(在任务卡外) */
.rule-entry { margin: 16px auto 8px; border: none; background: transparent; color: #999999; font-size: 12px; font-weight: 500; line-height: 18px; display: flex; align-items: center; justify-content: center; gap: 2px; width: 100%; cursor: pointer; }
.rule-entry span { font-size: 13px; }
/* 调试预览(检查签到 1-7 天图案) */
.dbg { margin: 8px auto 0; display: flex; align-items: center; justify-content: center; gap: 8px; flex-wrap: wrap; opacity: .85; }
.dbg button { font-size: 11px; padding: 5px 10px; border-radius: 8px; border: 1px solid #E5E5E5; background: #fff; color: #666; cursor: pointer; }
.dbg .lbl { font-size: 11px; color: #999; }
/* ===== 签到弹窗(1:1 对齐原型 #checkinPopup) ===== */
.ck-layer { position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,.55); -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px); display: none; align-items: center; justify-content: center; padding: 0 16px; }
.ck-layer.show { display: flex; }
.ck-card { position: relative; width: 100%; max-width: 340px; border-radius: 18px; padding: 16px 12px 12px; background: linear-gradient(180deg, #FFE0B2 0%, #FFFDE7 30%, #FFFFFF 72%); box-shadow: 0 20px 40px rgba(0,0,0,.12); }
.ck-close { position: absolute; left: 50%; bottom: -52px; width: 34px; height: 34px; transform: translateX(-50%); border: none; border-radius: 50%; background: rgba(255,255,255,.58); color: rgba(0,0,0,.46); box-shadow: 0 6px 18px rgba(0,0,0,.08); display: flex; align-items: center; justify-content: center; font-size: 22px; line-height: 1; cursor: pointer; }
.ck-banner { width: 206px; height: 16px; margin: -4px auto 8px; border-radius: 999px; background: rgba(255,255,255,.92); box-shadow: 0 4px 14px rgba(255,174,0,.14); border: 1px solid rgba(255,184,0,.24); display: flex; align-items: center; justify-content: center; gap: 4px; color: #7A4F00; font-size: 10px; font-weight: 700; white-space: nowrap; }
.ck-banner .star { width: 9px; height: 9px; background: #FFB300; clip-path: polygon(50% 0%,62% 37%,100% 50%,62% 63%,50% 100%,38% 63%,0% 50%,38% 37%); flex-shrink: 0; }
.ck-title { margin: 0; text-align: center; color: #1A1A1A; font-size: 20px; line-height: 1.1; font-weight: 900; }
.ck-sub { margin-top: 8px; text-align: center; color: #666; font-size: 11px; line-height: 1.2; font-weight: 500; white-space: nowrap; }
.ck-sub b { color: #FF6A00; font-weight: 800; }
.ck-rewards { margin-top: 12px; display: grid; grid-template-columns: repeat(5,1fr); gap: 6px; }
.ck-rcard { position: relative; min-height: 64px; border-radius: 8px; background: rgba(255,255,255,.88); border: 1px solid #F0F0F0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 8px 2px 6px; box-shadow: inset 0 1px 0 rgba(255,255,255,.75); }
.ck-rcard.claimed { background: rgba(247,247,247,.96); border-color: #E5E5E5; box-shadow: none; }
.ck-rcard.current { border-color: #FFB300; box-shadow: 0 8px 15px rgba(255,184,0,.14); background: rgba(255,255,255,.96); }
.ck-ricon { min-height: 26px; display: flex; align-items: center; justify-content: center; color: #999; font-size: 10px; line-height: 1; font-weight: 800; white-space: nowrap; }
.ck-ricon img { width: 29px; height: 29px; object-fit: contain; display: block; }
.ck-ricon img.chest { width: 36px; height: 33px; }
.ck-ramt { color: #1A1A1A; font-size: 12px; line-height: 1; font-weight: 800; }
.ck-rcard.claimed .ck-ramt { color: #999; }
.ck-progress { margin: 12px 0 0; position: relative; display: grid; grid-template-columns: repeat(5,1fr); gap: 6px; align-items: start; }
.ck-lines { position: absolute; top: 4.5px; left: 0; right: 0; height: 3px; pointer-events: none; z-index: 0; }
.ck-seg { position: absolute; top: 0; height: 3px; border-radius: 32px; }
.ck-seg.solid { background: var(--lc,#FFB800); }
.ck-seg.dashed { background: repeating-linear-gradient(90deg,var(--lc,#D9D9D9) 0 3px, transparent 3px 8px); background-size: 8px 3px; background-repeat: repeat-x; }
.ck-node { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 8px; color: #666; font-size: 10px; line-height: 1; white-space: nowrap; }
.ck-dot { box-sizing: border-box; width: 12px; height: 12px; border-radius: 50%; background: #fff; border: 2px solid #DDD; }
.ck-node.done .ck-dot { background: #FFB300; border-color: #FFB300; }
.ck-node.current .ck-dot { background: #fff; border: 2.5px solid #FFB300; }
.ck-cta { position: relative; margin: 12px auto 0; width: fit-content; min-width: 252px; max-width: calc(100% - 24px); height: 40px; padding: 0 22px; border: none; border-radius: 24px; background: linear-gradient(180deg,#FFE066 0%,#FFB300 100%); color: #1A1A1A; font-size: 16px; font-weight: 900; line-height: 1; white-space: nowrap; box-shadow: 0 14px 28px rgba(255,184,0,.22); display: flex; align-items: center; justify-content: center; gap: 4px; cursor: pointer; }
.ck-cta:active { transform: translateY(1px) scale(.99); }
.ck-cta img { width: 18px; height: 18px; object-fit: contain; display: block; }
.ck-cta b { color: #FF6A00; font-size: 22px; line-height: 1; }
/* Toast */
.toast { position: fixed; left: 50%; top: 45%; transform: translate(-50%,-50%); background: rgba(56,56,68,.94); color: #fff; font-size: 14px; padding: 12px 20px; border-radius: 12px; z-index: 60; opacity: 0; transition: opacity .2s; pointer-events: none; max-width: 78vw; text-align: center; }
.toast.show { opacity: 1; }
</style>
</head>
<body>
<div class="device">
<div class="screen">
<div class="scroll">
<div class="page-header"><span class="page-title">赚钱中心</span></div>
<div id="assetSlot"></div>
<div class="task-card">
<div class="section-title">赚金币</div>
<div id="checkinSlot"></div>
<div id="tasksSlot"></div>
</div>
<button class="rule-entry" onclick="onRules()">查看活动规则<span></span></button>
<div class="dbg" id="dbgSlot">
<button onclick="dbgStep(-1)">◀ 天</button>
<span class="lbl" id="dbgLabel">预览签到:关</span>
<button onclick="dbgStep(1)">天 ▶</button>
<button onclick="dbgToggleSigned()">切已签</button>
</div>
</div>
</div>
</div>
<div class="ck-layer" id="ckMask" onclick="if(event.target===this)closeCheckin()">
<div class="ck-card" onclick="event.stopPropagation()">
<button class="ck-close" onclick="closeCheckin()" aria-label="关闭">×</button>
<div class="ck-banner"><span class="star"></span><span id="ckBanner">连续签到7天,必得2500金币</span></div>
<h2 class="ck-title" id="ckTitle">签到领取今日金币</h2>
<div class="ck-sub" id="ckSub"></div>
<div class="ck-rewards" id="ckRewards"></div>
<div class="ck-progress" id="ckProgress"></div>
<button class="ck-cta" id="ckBtn" onclick="doCheckin()"></button>
<button class="ck-cta" id="ckBoostBtn" onclick="onSigninBoost()" style="display:none">看广告最高膨胀至 3000 金币</button>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="../shared/bridge.js"></script>
<script src="../shared/api.js"></script>
<script>
(function () {
'use strict';
var A = 'assets/';
var state = { logged: false, coin: 0, cashCents: 0, signin: null, notif: null, ad: null, couponDone: false };
var dbg = { day: 0, signed: false }; // day 0 = 关(用真实数据)
var SIGN_AMT = [200, 200, 300, 200, 400, 400, 800];
function el(id) { return document.getElementById(id); }
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
function thousands(n) { return Number(n || 0).toLocaleString('zh-CN'); }
function yuan(cents) { return (Number(cents || 0) / 100).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
var toastTimer;
function toast(msg) { var t = el('toast'); t.textContent = msg; t.classList.add('show'); clearTimeout(toastTimer); toastTimer = setTimeout(function () { t.classList.remove('show'); }, 1800); }
function loggedIn() {
try { if (window.SGBridge) { var t = SGBridge.getToken && SGBridge.getToken(); if (t) return true; var a = SGBridge.getAuthState && SGBridge.getAuthState(); return !!(a && (a.loggedIn || a.logged_in)); } } catch (e) {}
return false;
}
function requestLogin() { if (window.SGBridge && SGBridge.requestLogin) SGBridge.requestLogin(); }
function nav(route) { if (window.SGBridge && SGBridge.navigate) SGBridge.navigate(route); else console.log('[nav]', route); }
function guard(fn) { if (!state.logged) { requestLogin(); return; } fn(); }
// ---------- CTA ----------
window.onRules = function () { if (state.logged) nav('welfareRules'); else requestLogin(); };
window.onWithdraw = function () { nav('withdrawal'); };
window.onCoinHistory = function () { nav('coinHistory'); };
window.onCashHistory = function () { nav('cashHistory'); };
window.onLogin = function () { requestLogin(); };
window.onCoupon = function () { guard(function () { nav('welfareTask:coupon'); }); };
window.onCompare = function () { guard(function () { nav('welfareTask:compare'); }); };
window.onNotif = function () { guard(function () { nav('welfareTask:notification'); }); };
window.onReport = function () { guard(function () { nav('reportFlow'); }); };
window.onInvite = function () { guard(function () { nav('invite'); }); };
window.onVideo = function () {
guard(function () {
if (state.ad && state.ad.remaining <= 0) { toast('今日看视频奖励已达上限,明天再来'); return; }
if (cooldownLeft() > 0) return;
nav('welfareTask:rewardVideo');
});
};
// ---------- 资产卡 ----------
function renderAsset() {
var slot = el('assetSlot');
if (!state.logged) {
slot.innerHTML =
'<div class="asset-card unlogged"><img class="asset-illustration" src="' + A + 'asset-illustration.png" alt="">' +
'<div class="asset-unlogged-body"><div class="asset-unlogged-title">登录就能赚金币</div>' +
'<button class="login-btn" onclick="onLogin()">一键登录</button></div></div>';
return;
}
var wx = '<img src="' + A + 'wechat-pay-check-icon.png" alt="">';
var arw = '<svg class="asset-arrow" viewBox="0 0 24 24" fill="none"><path d="M9 6L15 12L9 18" stroke="rgba(26,26,26,.4)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>';
slot.innerHTML =
'<div class="asset-card"><div class="asset-cols">' +
'<div class="asset-col" onclick="onCoinHistory()"><div class="asset-label">我的金币' + arw + '</div>' +
'<div class="asset-valrow"><span class="asset-val num" id="coinVal">' + String(state.coin) + '</span></div></div>' +
'<div class="asset-col" onclick="onCashHistory()"><div class="asset-label">我的现金' + arw + '</div>' +
'<div class="asset-valrow"><span class="asset-val num" id="cashVal">' + yuan(state.cashCents) + '</span>' +
'<button class="chip" onclick="event.stopPropagation();onWithdraw()">' + wx + '去提现</button></div></div>' +
'</div><div class="asset-note">0点自动兑现金(可能存在延迟)</div></div>';
}
function refreshAssetNumbers() { var c = el('coinVal'), k = el('cashVal'); if (c) c.textContent = String(state.coin); if (k) k.textContent = yuan(state.cashCents); }
// ---------- 签到时间线 ----------
function effSignin() {
if (dbg.day > 0) {
return {
steps: SIGN_AMT.map(function (c, i) { return { day: i + 1, coin: c }; }),
today_signed: dbg.signed, today_cycle_day: dbg.day,
consecutive_days: dbg.day, today_coin: SIGN_AMT[dbg.day - 1],
};
}
return state.signin;
}
// 签到视图态(对齐原型 buildCheckin7Steps):5 格滑窗跟随 focus(未签=今天/已签=明天),
// done=已领✓;current=「今天领」(未签在今天)或「明天领」(已签移到明天);已签的今天节点标签变「今天」。
// ⚠️不依赖后端 step.status——签到后后端把今天标 claimed、不再有 today 节点,badge 会整个消失(bug)。
function ckSteps(s, preview) {
var steps = (s && s.steps && s.steps.length) ? s.steps : SIGN_AMT.map(function (c, i) { return { day: i + 1, coin: c }; });
var maxDay = steps.length;
var today = preview ? 0 : Math.min(Math.max((s && s.today_cycle_day) || 1, 1), maxDay);
var signed = !preview && !!(s && s.today_signed);
var focus = preview ? 1 : (signed ? Math.min(today + 1, maxDay) : today);
var start = Math.min(3, Math.max(1, focus - 2));
var days = [start, start + 1, start + 2, start + 3, maxDay];
return days.map(function (d) {
var st = steps[d - 1] || { day: d, coin: 0 };
var isToday = d === today, isTomorrow = d === today + 1;
var isDone = signed ? d <= today : d < today;
var isCurrent = (!signed && isToday) || (signed && isTomorrow);
return {
day: d, coin: st.coin, done: isDone, current: isCurrent, isLastDay: d === maxDay,
badge: isCurrent ? (isTomorrow ? '明天领' : '今天领') : null,
label: (isToday && signed) ? '今天' : ('第' + d + '天'),
};
});
}
function stepIconImg(v) {
var src = (v.isLastDay || v.coin >= 800) ? 'checkin-chest-8888.png' : (v.coin >= 300 ? 'checkin-coins-600.png' : 'checkin-coin-single.png');
return '<img src="' + A + src + '" alt="">';
}
function stepNode(v, gapNext) {
var cls = 'step' + (v.done ? ' done' : '') + (v.current ? ' current' : '') + (gapNext ? ' gap-next' : '');
var top = v.badge ? '<span class="step-badge">' + v.badge + '</span>' : '<span class="step-label">' + v.label + '</span>';
var icon = v.done ? '<span class="step-icon"></span>' : '<span class="step-icon">' + stepIconImg(v) + '</span>';
return '<div class="' + cls + '">' + top + icon + '<span class="step-amt num">' + v.coin + '</span></div>';
}
function renderCheckin() {
var slot = el('checkinSlot'), s = effSignin(), logged = state.logged;
var signed = !!(s && s.today_signed);
var sub = logged ? (s ? '连续签到7天必得2500金币' : '连续签到领金币') : '登录后每日签到,连续7天最高领800金币';
var ctaText = (logged && signed) ? '去查看' : '去签到';
var ctaDot = (!signed) ? '<span class="dot"></span>' : '';
var view = ckSteps(s, !(logged && s));
var html = view.map(function (v, i) {
return stepNode(v, view[i + 1] ? (view[i + 1].day - v.day > 1) : false);
}).join('');
slot.innerHTML =
'<div class="checkin-row"><div class="checkin-head"><div class="checkin-copy">' +
'<div class="checkin-title">新人签到领金币</div><div class="checkin-sub">' + esc(sub) + '</div></div>' +
'<button class="cta checkin-cta" onclick="onCheckinEntry()">' + ctaText + ctaDot + '</button></div>' +
'<div class="timeline">' + html + '</div></div>';
}
window.onCheckinEntry = function () { if (!state.logged) { requestLogin(); return; } openCheckin(); };
// ---------- 任务行 ----------
function cooldownLeft() { if (!state.ad || !state.ad.cooldown_until) return 0; var u = Date.parse(state.ad.cooldown_until); return isNaN(u) ? 0 : Math.max(0, u - Date.now()); }
function videoCta() {
if (!state.logged) return { cls: '', label: '去观看', click: 'onVideo()' };
if (state.ad && state.ad.remaining <= 0) return { cls: 'gray', label: '已领完', click: 'onVideo()' };
var left = cooldownLeft();
if (left > 0) { var s = Math.ceil(left / 1000), mm = Math.floor(s / 60), ss = s % 60; return { cls: 'gray', label: (mm < 10 ? '0' + mm : mm) + ':' + (ss < 10 ? '0' + ss : ss), click: '' }; }
return { cls: '', label: '去赚取', click: 'onVideo()' };
}
function coinTag(t) { return '<span class="task-coin"><img class="ci" src="' + A + 'coin-icon.png" alt="">' + esc(t) + '</span>'; }
function row(o) {
var sub = o.subHtml ? '<div class="task-sub">' + o.subHtml + '</div>' : '';
var coin = o.coin ? coinTag(o.coin) : '';
var dot = o.dot ? '<span class="dot"></span>' : '';
return '<div class="task-row" id="' + o.id + '"><div class="task-info"><div class="task-titlerow"><span class="task-title">' + esc(o.title) + '</span>' + coin + '</div>' + sub +
'</div><button class="cta task-cta ' + (o.cls || '') + '" ' + (o.click ? 'onclick="' + o.click + '"' : '') + '>' + esc(o.cta) + dot + '</button></div>';
}
function renderTasks() {
var logged = state.logged, vs = videoCta(), notifCoin = state.notif ? state.notif.coin : 750;
el('tasksSlot').innerHTML = [
row({ id: 'tCoupon', title: '大额优惠券免费领', coin: '最高500/次', subHtml: '全网神券 AI 帮你一键领齐', cta: '去领券', click: 'onCoupon()', dot: !state.couponDone }),
row({ id: 'tCompare', title: '天天比价赚金币', coin: '最高500/次', subHtml: '同款菜品全网比,自动找底价', cta: '去比价', click: 'onCompare()' }),
row({ id: 'tVideo', title: '看视频赚海量金币', coin: '最高1000000', subHtml: logged ? '单日最高赚 100 万金币' : '登录后立得海量金币', cta: vs.label, cls: vs.cls, click: vs.click }),
row({ id: 'tNotif', title: '打开消息提醒', coin: String(notifCoin), subHtml: '开启推送即得金币', cta: '去开启', click: 'onNotif()' }),
row({ id: 'tReport', title: '上报更低价赚金币', coin: '1000/次', subHtml: '每次审核通过得 1000 金币', cta: '去上报', click: 'onReport()' }),
row({ id: 'tInvite', title: '邀请好友赚现金', subHtml: '<span class="task-tag">限时大额福利</span>每邀1人必得2元现金', cta: '去邀请', click: 'onInvite()' }),
].join('');
}
setInterval(function () { if (cooldownLeft() > 0 || (state.ad && state.ad.remaining > 0)) { var vs = videoCta(); var b = document.querySelector('#tVideo .task-cta'); if (b) { b.innerHTML = esc(vs.label); b.className = 'cta task-cta ' + vs.cls; b.setAttribute('onclick', vs.click); } } }, 1000);
// ---------- 签到弹窗(1:1 对齐原型 #checkinPopup) ----------
function ckRewardImg(st, isLast) {
var src = (isLast || st.coin >= 800) ? 'checkin-chest-8888.png' : (st.coin >= 300 ? 'checkin-coins-600.png' : 'checkin-coin-single.png');
var chest = src.indexOf('chest') >= 0 ? ' class="chest"' : '';
return '<img' + chest + ' src="' + A + src + '" alt="">';
}
function roundTotal(s) {
if (s && s.steps && s.steps.length) { var t = 0; for (var i = 0; i < Math.min(7, s.steps.length); i++) t += (s.steps[i].coin || 0); return t; }
return 2500;
}
function nextReward(s) {
// 明天那档的金币(today_cycle_day 的下一档);第 7 天签完无"明天"档,返回 0(文案走特殊分支)。
var steps = (s && s.steps) || [];
var today = (s && s.today_cycle_day) || 1;
return (steps[today] && steps[today].coin) || 0;
}
function renderCkLines(view) {
var c = el('ckLines'); if (!c) return;
var centers = [10, 30, 50, 70, 90], html = '';
for (var i = 0; i < view.length - 1; i++) {
var jump = (view[i + 1].day - view[i].day) > 1;
var reached = view[i + 1].done || view[i + 1].current; // 连到"已达/当前"节点的线段亮黄
var lc = (reached && !jump) ? '#FFB800' : '#D9D9D9';
html += '<span class="ck-seg ' + (jump ? 'dashed' : 'solid') + '" style="left:' + centers[i] + '%;width:' + (centers[i + 1] - centers[i]) + '%;--lc:' + lc + '"></span>';
}
c.innerHTML = html;
}
function renderCkPopup(s) {
var view = ckSteps(s, false);
var maxDay = (s.steps && s.steps.length) || 7;
var lastDaySigned = s.today_signed && (s.today_cycle_day >= maxDay);
el('ckBanner').textContent = '连续签到7天,必得' + roundTotal(s) + '金币';
el('ckTitle').textContent = s.today_signed ? '今日金币已领取' : '签到领取今日金币';
el('ckSub').innerHTML = lastDaySigned
? '本轮大额奖励已入账,明日领新一轮大奖'
: (s.today_signed
? '已连续签到 <b>' + (s.consecutive_days || 0) + '</b> 天,明天可领 <b>' + nextReward(s) + '</b> 金币'
: '已连续签到 <b>' + (s.consecutive_days || 0) + '</b> 天,今天可领 <b>' + (s.today_coin || 0) + '</b> 金币');
el('ckRewards').innerHTML = view.map(function (v) {
if (v.done) return '<div class="ck-rcard claimed"><div class="ck-ricon">已领取</div><div class="ck-ramt">' + v.coin + '</div></div>';
return '<div class="ck-rcard' + (v.current ? ' current' : '') + '"><div class="ck-ricon">' + ckRewardImg(v, v.isLastDay) + '</div><div class="ck-ramt">' + v.coin + '</div></div>';
}).join('');
el('ckProgress').innerHTML = '<div class="ck-lines" id="ckLines"></div>' + view.map(function (v) {
var cls = (v.done ? ' done' : '') + (v.current ? ' current' : '');
return '<div class="ck-node' + cls + '"><span class="ck-dot"></span><span>' + (v.badge || v.label) + '</span></div>';
}).join('');
renderCkLines(view);
var btn = el('ckBtn'), boost = el('ckBoostBtn');
if (s.today_signed) { btn.style.display = 'none'; boost.style.display = 'flex'; }
else { btn.style.display = 'flex'; boost.style.display = 'none'; btn.innerHTML = '签到领 <img src="' + A + 'checkin-coin-single.png" alt=""><b>' + (s.today_coin || 0) + '</b>'; }
}
window.openCheckin = function () {
var s = effSignin(); if (!s) { toast('签到信息加载中…'); return; }
renderCkPopup(s); el('ckMask').classList.add('show');
};
window.closeCheckin = function () { el('ckMask').classList.remove('show'); };
window.doCheckin = function () {
if (dbg.day > 0) { toast('预览模式不发真金币'); return; }
var s = state.signin; if (!s || s.today_signed) return;
SGApi.post('/signin', {}).then(function (r) {
if (r && r.coin_balance != null) { state.coin = r.coin_balance; refreshAssetNumbers(); }
toast('签到成功 +' + ((r && r.coin_awarded) || s.today_coin || 0) + ' 金币');
// 重拉签到态,弹窗刷成已签(显示膨胀 CTA),不关弹窗(对齐原型)
SGApi.get('/signin/status').then(function (ns) { state.signin = ns; renderCheckin(); if (el('ckMask').classList.contains('show')) renderCkPopup(ns); }).catch(function () {});
}).catch(function (e) {
if (String(e).indexOf('409') >= 0) { toast('今天已签到'); loadSignin(); } else { toast('签到失败,请稍后再试'); }
});
};
window.onSigninBoost = function () { closeCheckin(); guard(function () { nav('welfareTask:signinBoost'); }); };
// ---------- 调试预览 ----------
window.dbgStep = function (d) { dbg.day += d; if (dbg.day > 7) dbg.day = 0; if (dbg.day < 0) dbg.day = 7; el('dbgLabel').textContent = dbg.day ? ('预览签到:第' + dbg.day + '天') : '预览签到:关'; renderCheckin(); };
window.dbgToggleSigned = function () { dbg.signed = !dbg.signed; renderCheckin(); };
// ---------- 数据 ----------
function loadAccount() { return SGApi.get('/wallet/account').then(function (a) { if (!a) return; state.coin = a.coin_balance || 0; state.cashCents = a.cash_balance_cents || 0; refreshAssetNumbers(); }).catch(function () {}); }
function loadSignin() { return SGApi.get('/signin/status').then(function (s) { state.signin = s; if (dbg.day === 0) renderCheckin(); }).catch(function () {}); }
function loadTasks() { return SGApi.get('/tasks').then(function (t) { if (t && t.items) for (var i = 0; i < t.items.length; i++) if (t.items[i].task_key === 'enable_notification') { state.notif = t.items[i]; break; } renderTasks(); }).catch(function () {}); }
function loadAd() { return SGApi.get('/ad/reward-status').then(function (a) { state.ad = a; renderTasks(); }).catch(function () {}); }
function loadAll() { state.logged = loggedIn(); renderAsset(); renderCheckin(); renderTasks(); if (!state.logged) return; loadAccount(); loadSignin(); loadTasks(); loadAd(); }
loadAll();
setInterval(function () { if (state.logged && !document.hidden) { loadAccount(); loadAd(); } }, 12000);
if (window.SGBridge && SGBridge.on) {
SGBridge.on('onResume', function () { var was = state.logged; state.logged = loggedIn(); if (state.logged !== was) loadAll(); else if (state.logged) { loadAccount(); loadSignin(); loadTasks(); loadAd(); } });
SGBridge.on('onAuthChange', function () { loadAll(); });
}
})();
</script>
</body>
</html>