220 lines
9.5 KiB
HTML
220 lines
9.5 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}推荐好友 · AlphaX Agent | Crypto{% endblock %}
|
||
|
||
{% block nav_links %}
|
||
<a class="sidebar-link" href="/app"><svg class="link-icon"><use href="#svg-dashboard"/></svg>看板</a>
|
||
<a class="sidebar-link" href="/sentiment"><svg class="link-icon"><use href="#svg-sentiment"/></svg>舆情</a>
|
||
<a class="sidebar-link" href="/subscription"><svg class="link-icon"><use href="#svg-subscribe"/></svg>订阅</a>
|
||
<a class="sidebar-link active" href="/referral"><svg class="link-icon"><use href="#svg-referral"/></svg>推荐</a>
|
||
<div class="sidebar-section-label admin-link" style="display:none">研发</div>
|
||
<a class="sidebar-link admin-link" href="/pipeline" style="display:none"><svg class="link-icon"><use href="#svg-pipeline"/></svg>链路日志</a>
|
||
<a class="sidebar-link admin-link" href="/cron" style="display:none"><svg class="link-icon"><use href="#svg-cron"/></svg>调度中心</a>
|
||
<a class="sidebar-link admin-link" href="/llm-insights" style="display:none"><svg class="link-icon"><use href="#svg-ai"/></svg>AI 记录</a>
|
||
<a class="sidebar-link admin-link" href="/strategy" style="display:none"><svg class="link-icon"><use href="#svg-target"/></svg>策略</a>
|
||
<a class="sidebar-link admin-link" href="/iteration" style="display:none"><svg class="link-icon"><use href="#svg-iterate"/></svg>迭代</a>
|
||
<a class="sidebar-link admin-link" href="/admin.html" style="display:none"><svg class="link-icon"><use href="#svg-admin"/></svg>管理</a>
|
||
{% endblock %}
|
||
|
||
{% block extra_head_css %}
|
||
<style>
|
||
main { max-width: 680px; margin: 0 auto; width: 100%; padding: 32px 20px; display: flex; flex-direction: column; gap: 28px; }
|
||
|
||
.page-header { text-align: center; }
|
||
.page-header h1 { font-size: 28px; font-weight: 700; letter-spacing: -.5px; margin-bottom: 6px; }
|
||
.page-header .sub { font-size: 14px; color: var(--stone); }
|
||
|
||
/* Invite card */
|
||
.invite-card {
|
||
background: var(--canvas); border: 1px solid var(--hairline-soft);
|
||
border-radius: var(--radius-xl); padding: 28px 24px;
|
||
display: flex; flex-direction: column; gap: 16px;
|
||
}
|
||
.invite-label { font-size: 12px; color: var(--stone); font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
|
||
.invite-link-box {
|
||
display: flex; align-items: center; gap: 8px;
|
||
background: var(--surface); border: 1px solid var(--hairline);
|
||
border-radius: var(--radius-lg); padding: 10px 14px;
|
||
font-size: 14px; color: var(--ink); font-family: monospace;
|
||
word-break: break-all; user-select: all;
|
||
}
|
||
.invite-link-box .link-text { flex: 1; min-width: 0; }
|
||
.copy-btn {
|
||
flex-shrink: 0; padding: 7px 18px; border: 0; border-radius: var(--radius-full);
|
||
background: var(--primary); color: var(--on-primary);
|
||
font-size: 13px; font-weight: 600; cursor: pointer; transition: .15s;
|
||
}
|
||
.copy-btn:hover { opacity: .85; }
|
||
.copy-btn.copied { background: var(--green); }
|
||
.copy-msg { font-size: 12px; color: var(--green); min-height: 18px; text-align: center; }
|
||
|
||
/* Stats */
|
||
.stats-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||
.stat-box {
|
||
background: var(--canvas); border: 1px solid var(--hairline-soft);
|
||
border-radius: var(--radius-xl); padding: 20px;
|
||
text-align: center; display: flex; flex-direction: column; gap: 4px;
|
||
}
|
||
.stat-box .num { font-size: 36px; font-weight: 700; letter-spacing: -1px; line-height: 1; }
|
||
.stat-box .lbl { font-size: 12px; color: var(--stone); }
|
||
|
||
/* Referred list */
|
||
.ref-list { display: flex; flex-direction: column; gap: 8px; }
|
||
.ref-card {
|
||
background: var(--canvas); border: 1px solid var(--hairline-soft);
|
||
border-radius: var(--radius-lg); padding: 16px 18px;
|
||
display: flex; align-items: center; gap: 12px;
|
||
}
|
||
.ref-avatar {
|
||
width: 36px; height: 36px; border-radius: 50%;
|
||
background: var(--yellow); color: var(--primary);
|
||
display: grid; place-items: center; font-weight: 700; font-size: 14px; flex-shrink: 0;
|
||
}
|
||
.ref-info { flex: 1; min-width: 0; }
|
||
.ref-email { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.ref-date { font-size: 11px; color: var(--stone); margin-top: 2px; }
|
||
.ref-badge { flex-shrink: 0; font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: var(--radius-full); }
|
||
.ref-badge.verified { background: var(--green-light); color: var(--green); }
|
||
.ref-badge.pending { background: var(--yellow-light); color: var(--yellow-dark); }
|
||
|
||
.empty-state { text-align: center; padding: 48px 20px; color: var(--stone); }
|
||
.empty-state p { font-size: 14px; margin-bottom: 8px; }
|
||
.empty-state .empty-icon { font-size: 48px; margin-bottom: 16px; opacity: .3; }
|
||
|
||
/* Share section */
|
||
.share-section { text-align: center; }
|
||
.share-section h3 { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
|
||
.share-section p { font-size: 13px; color: var(--stone); margin-bottom: 12px; }
|
||
.share-tips { display: flex; flex-direction: column; gap: 6px; text-align: left; font-size: 13px; color: var(--slate); line-height: 1.6; padding: 16px 20px; background: var(--surface); border-radius: var(--radius-lg); }
|
||
|
||
@media(max-width:480px){
|
||
main { padding: 20px 14px; gap: 20px; }
|
||
.invite-card { padding: 20px 16px; }
|
||
.invite-link-box { flex-direction: column; }
|
||
.copy-btn { width: 100%; }
|
||
.stats-row { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<main>
|
||
<div class="page-header">
|
||
<h1>🎁 推荐好友</h1>
|
||
<p class="sub">邀请朋友加入 AlphaX Agent | Crypto,一起跟踪市场信号</p>
|
||
</div>
|
||
|
||
<div class="invite-card">
|
||
<div class="invite-label">你的专属邀请链接</div>
|
||
<div class="invite-link-box">
|
||
<span class="link-text" id="inviteLink">加载中...</span>
|
||
<button class="copy-btn" id="copyBtn" onclick="copyLink()">复制链接</button>
|
||
</div>
|
||
<div class="copy-msg" id="copyMsg"></div>
|
||
</div>
|
||
|
||
<div class="stats-row" id="statsRow">
|
||
<div class="stat-box"><div class="num">--</div><div class="lbl">已邀请</div></div>
|
||
<div class="stat-box"><div class="num">--</div><div class="lbl">已注册</div></div>
|
||
</div>
|
||
|
||
<div id="refSection">
|
||
<h3 style="font-size:16px;font-weight:600;margin-bottom:12px">已邀请好友</h3>
|
||
<div class="ref-list" id="refList">
|
||
<div class="empty-state"><p>加载中...</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="share-section">
|
||
<h3>如何推荐</h3>
|
||
<p>复制邀请链接发送给朋友,他们注册时将自动绑定你的邀请码</p>
|
||
<div class="share-tips">
|
||
<div>📋 复制邀请链接,通过微信 / Telegram / 邮件分享</div>
|
||
<div>🔗 好友点击链接注册,系统自动记录邀请关系</div>
|
||
<div>📊 你可以在本页查看邀请进度</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
{% endblock %}
|
||
|
||
{% block extra_script %}
|
||
<script>
|
||
var inviteCode = '';
|
||
var baseUrl = window.location.origin;
|
||
|
||
async function init() {
|
||
try {
|
||
var r = await fetch('/api/auth/me');
|
||
if (!r.ok) { window.location.href = '/auth'; return; }
|
||
var data = await r.json();
|
||
inviteCode = data.user.invite_code || '';
|
||
if (!inviteCode) {
|
||
document.getElementById('inviteLink').textContent = '暂无邀请码';
|
||
return;
|
||
}
|
||
var link = baseUrl + '/auth?invite=' + inviteCode;
|
||
document.getElementById('inviteLink').textContent = link;
|
||
loadReferralStats();
|
||
} catch(e) {
|
||
document.getElementById('inviteLink').textContent = '加载失败,请刷新重试';
|
||
}
|
||
}
|
||
|
||
async function loadReferralStats() {
|
||
try {
|
||
var r = await fetch('/api/referral/stats');
|
||
if (!r.ok) return;
|
||
var d = await r.json();
|
||
document.getElementById('statsRow').innerHTML =
|
||
'<div class="stat-box"><div class="num">' + (d.total_invited || 0) + '</div><div class="lbl">已邀请</div></div>' +
|
||
'<div class="stat-box"><div class="num">' + (d.total_registered || 0) + '</div><div class="lbl">已注册</div></div>';
|
||
renderRefList(d.invited_users || []);
|
||
} catch(e) {}
|
||
}
|
||
|
||
function renderRefList(users) {
|
||
var list = document.getElementById('refList');
|
||
if (!users.length) {
|
||
list.innerHTML = '<div class="empty-state"><div class="empty-icon">📭</div><p>还没有好友通过你的链接注册</p><p style="font-size:12px;color:var(--muted)">分享邀请链接,开始推荐吧</p></div>';
|
||
return;
|
||
}
|
||
list.innerHTML = users.map(function(u) {
|
||
var initial = (u.email || '?').charAt(0).toUpperCase();
|
||
var badge = u.email_verified
|
||
? '<span class="ref-badge verified">已验证</span>'
|
||
: '<span class="ref-badge pending">未验证</span>';
|
||
var date = u.created_at ? u.created_at.slice(0, 10) : '--';
|
||
return '<div class="ref-card">' +
|
||
'<div class="ref-avatar">' + initial + '</div>' +
|
||
'<div class="ref-info"><div class="ref-email">' + esc(u.email) + '</div><div class="ref-date">' + date + '</div></div>' +
|
||
badge +
|
||
'</div>';
|
||
}).join('');
|
||
}
|
||
|
||
function copyLink() {
|
||
var link = document.getElementById('inviteLink').textContent;
|
||
if (!link || link === '加载中...' || link === '暂无邀请码') return;
|
||
navigator.clipboard.writeText(link).then(function() {
|
||
var btn = document.getElementById('copyBtn');
|
||
var msg = document.getElementById('copyMsg');
|
||
btn.textContent = '已复制 ✓';
|
||
btn.classList.add('copied');
|
||
msg.textContent = '邀请链接已复制到剪贴板';
|
||
setTimeout(function() {
|
||
btn.textContent = '复制链接';
|
||
btn.classList.remove('copied');
|
||
msg.textContent = '';
|
||
}, 2000);
|
||
}).catch(function() {
|
||
var msg = document.getElementById('copyMsg');
|
||
msg.textContent = '复制失败,请手动选择链接复制';
|
||
msg.style.color = 'var(--red)';
|
||
});
|
||
}
|
||
|
||
function esc(s) { return String(s||'').replace(/[&<>"]/g, function(c){ return {'&':'&','<':'<','>':'>','"':'"'}[c] }); }
|
||
|
||
init();
|
||
</script>
|
||
{% endblock %}
|