Files
shencaisuan/html/tuiguang.html
T
2026-06-04 11:43:41 +08:00

874 lines
29 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title id="page-title">彩先知 - 推广赚钱</title>
<script src="../public/css/layui/layui.js"></script>
<script src="../config.js"></script>
<script src="../utils/ApiClient.js"></script>
<script src="../utils/DateUtil.js"></script>
<script src="../utils/CommonUtil.js"></script>
<script src="../public/js/qrcode.min.js"></script>
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
<link rel="stylesheet" href="../public/css/public.css" />
<link rel="stylesheet" href="../public/css/distribution.css" />
</head>
<body>
<!-- Header -->
<nav class="topbar" id="navbar">
<div class="topbar__inner">
<a href="index.html" class="topbar__brand">
<img
src="../images/home-logo.png"
alt="彩先知"
class="topbar__logo"
/>
</a>
<div class="topbar__nav" id="navLotteryItems"></div>
<div class="topbar__user">
<div id="notLoggedInBox" class="topbar__guest">
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
<a href="reg.html" class="topbar__btn topbar__btn--primary"
>免费注册</a
>
</div>
<div id="loggedInBox" class="topbar__logged" style="display: none">
<a href="usercenter.html" class="topbar__profile">
<img
id="userAvatar"
src="../public/img/userimg.png"
alt=""
class="topbar__avatar"
/>
<div class="topbar__meta">
<span id="userName" class="topbar__uname">用户</span>
<span id="userLevel" class="topbar__ubadge">会员</span>
</div>
</a>
<button class="topbar__btn topbar__btn--logout" onclick="logout()">
退出登录
</button>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="cxz-main">
<div class="cxz-breadcrumb">
<a href="index.html">首页</a><span class="sep">></span>
<a href="usercenter.html">个人中心</a><span class="sep">></span>
<span>推广赚钱</span>
</div>
<!-- Banner -->
<div class="promo-banner">
<h2>推广赚<span>佣金</span></h2>
<p>
复制分享链接,邀请好友注册即可获得分销收益。一级分销返佣更高,多级返佣轻松赚钱!
</p>
</div>
<!-- Stats -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-label">分销余额</div>
<div class="stat-value">
<span id="salesBalance">0.00</span><span class="unit"></span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">累计返利</div>
<div class="stat-value">
<span id="distIncome">0.00</span><span class="unit"></span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">邀请人数</div>
<div class="stat-value">
<span id="totalSubordinates">0</span><span class="unit"></span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">待结算</div>
<div class="stat-value">
<span id="pendingRebate">0.00</span><span class="unit"></span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">返利比例</div>
<div class="stat-value">
<span id="rebateRate">--</span>
</div>
</div>
</div>
<!-- QR Code & Link -->
<div class="promo-content">
<div class="qr-card">
<div class="qr-card-title">推广二维码</div>
<div class="qr-code-box">
<img id="promoQrImg" src="" alt="推广二维码" />
</div>
<div class="qr-card-tip">扫描二维码即可注册</div>
</div>
<div class="link-card">
<div class="link-card-title">推广链接</div>
<div class="link-input-wrap">
<input
type="text"
class="link-input"
id="promoLink"
readonly
value=""
/>
<button class="copy-btn" id="copyLinkBtn" onclick="copyPromoLink()">
复制链接
</button>
</div>
<div class="share-tips">
<h4>推广说明</h4>
<ul>
<li>
通过您的推广链接注册的用户将成为您的<strong>一级下级</strong>
</li>
<li>一级下级消费您可获得<strong>高比例</strong>返佣</li>
<li>
一级下级的下级为您的<strong>二级下级</strong>,也可获得返佣
</li>
<li>推广收益可随时申请<strong>提现</strong></li>
</ul>
</div>
</div>
</div>
<!-- Invite List Table -->
<div class="team-section">
<div class="team-section-title team-section-title--filter">
<span><i class="layui-icon layui-icon-group"></i> 邀请用户</span>
<div class="promo-filter" id="inviteFilter">
<button class="active" type="button" data-filter="all">全部</button>
<button type="button" data-filter="active">已消费</button>
<button type="button" data-filter="new">未消费</button>
</div>
</div>
<table class="team-table">
<thead>
<tr>
<th>头像</th>
<th>用户名称</th>
<th>注册时间</th>
<th>消费金额</th>
<th>贡献返利</th>
<th>状态</th>
</tr>
</thead>
<tbody id="inviteTableBody">
<tr>
<td
colspan="6"
style="
text-align: center;
color: var(--text-muted);
padding: 40px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="cxz-pagination" id="invitePager"></div>
</div>
<!-- Rebate Flow Table -->
<div class="team-section">
<div class="team-section-title team-section-title--filter">
<span><i class="layui-icon layui-icon-rmb"></i> 返利流水</span>
<div class="promo-filter" id="rebateFilter">
<button class="active" type="button" data-filter="all">全部</button>
<button type="button" data-filter="pending">待结算</button>
<button type="button" data-filter="success">已结算</button>
</div>
</div>
<table class="team-table">
<thead>
<tr>
<th>流水号</th>
<th>来源用户</th>
<th>返利金额</th>
<th>比例</th>
<th>状态</th>
<th>时间</th>
</tr>
</thead>
<tbody id="rebateTableBody">
<tr>
<td
colspan="6"
style="
text-align: center;
color: var(--text-muted);
padding: 40px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="cxz-pagination" id="rebatePager"></div>
</div>
<div class="promo-info-grid">
<div class="team-section promo-info-card">
<div class="team-section-title">
<i class="layui-icon layui-icon-about"></i> 绑定规则
</div>
<div class="promo-rule-list">
<div class="promo-rule-item">
<span>1</span>
<p>好友通过您的推广链接注册后,会自动绑定为邀请用户。</p>
</div>
<div class="promo-rule-item">
<span>2</span>
<p>好友购买付费内容后,会生成返利记录并等待结算。</p>
</div>
<div class="promo-rule-item">
<span>3</span>
<p>返利比例以当前平台配置为准,页面会展示接口返回的比例。</p>
</div>
<div class="promo-rule-item">
<span>4</span>
<p>已结算返利可进入提现页面处理,具体以钱包余额为准。</p>
</div>
</div>
</div>
<div class="team-section promo-info-card">
<div class="team-section-title">
<i class="layui-icon layui-icon-chart-screen"></i> 返利流程
</div>
<div class="promo-flow-list">
<div class="promo-flow-step"><strong>01</strong><span>分享链接</span></div>
<div class="promo-flow-step"><strong>02</strong><span>好友注册</span></div>
<div class="promo-flow-step"><strong>03</strong><span>购买付费文章</span></div>
<div class="promo-flow-step"><strong>04</strong><span>返利结算</span></div>
</div>
</div>
</div>
</main>
<!-- QR Code Modal -->
<div class="cxz-dialog-overlay" id="qrDialog" style="display: none">
<div class="cxz-dialog-box">
<div class="cxz-dialog-header">
<div class="cxz-dialog-title">推广二维码</div>
<button class="cxz-dialog-close" onclick="closeQrDialog()">
&times;
</button>
</div>
<div class="cxz-dialog-body" style="text-align: center; padding: 24px">
<div
id="qrCodeContainer"
style="
display: inline-block;
padding: 16px;
border: 2px dashed var(--border-light);
border-radius: var(--radius-lg);
"
></div>
<p
style="margin-top: 12px; font-size: 13px; color: var(--text-muted)"
>
长按或截图分享给好友
</p>
</div>
</div>
</div>
<!-- Footer -->
<footer class="site-footer">
<div class="site-footer__inner">
<img
src="../images/home-logo.png"
alt="彩先知"
class="site-footer__logo"
/>
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
<div class="site-footer__meta">
<a
id="beian"
href="https://beian.miit.gov.cn/"
target="_blank"
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
>工信部备案号</a
>
<span id="additional-info">本站仅供数据分析参考</span>
</div>
</div>
</footer>
<button
class="gotop"
id="backTop"
type="button"
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
>
</button>
<script>
const $ = layui.$;
let invitePage = 1;
let rebatePage = 1;
let inviteFilter = "all";
let rebateFilter = "all";
const pageSize = 10;
let promoSummary = {
salesBalance: 0,
totalSubordinates: 0,
distributionIncome: 0,
pendingRebate: 0,
rebateRate: "",
};
function logout() {
localStorage.removeItem("token");
window.location.reload();
}
function checkLogin() {
const token = localStorage.getItem("token");
if (token) {
$("#notLoggedInBox").hide();
$("#loggedInBox").css("display", "flex");
CommonUtil.getCurrentUserDetail(
function (data) {
$("#userName").text(data.nickName || "用户");
$("#userLevel").text(data.isExpert === "1" ? "专家" : "会员");
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
},
function () {
$("#notLoggedInBox").show();
$("#loggedInBox").hide();
},
);
} else {
window.location.href = "login.html";
}
}
function renderNav() {
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
if (res.code !== 0 || !res.data) return;
var $nav = $("#navLotteryItems");
$nav.find(".topbar__nav-link").not(":first").remove();
$.each(res.data, function (i, item) {
$nav.append(
'<a href="cai.html?id=' +
item.suoxie +
'" class="topbar__nav-link">' +
item.name +
"</a>",
);
});
});
}
$(window).on("scroll", function () {
$(window).scrollTop() > 320
? $("#backTop").addClass("is-visible")
: $("#backTop").removeClass("is-visible");
});
function isSuccess(res) {
return ApiClient.isSuccess
? ApiClient.isSuccess(res)
: res && (res.code === 0 || res.code === 200);
}
function pickData(res, fallback) {
if (ApiClient.pickData) return ApiClient.pickData(res, fallback);
return res && res.data !== undefined && res.data !== null
? res.data
: fallback;
}
function asRows(data) {
if (ApiClient.asArray) return ApiClient.asArray(data);
if (Array.isArray(data)) return data;
if (!data || typeof data !== "object") return [];
return data.records || data.rows || data.list || data.items || [];
}
function firstDefined() {
for (var i = 0; i < arguments.length; i++) {
var value = arguments[i];
if (value !== undefined && value !== null && value !== "") return value;
}
return "";
}
function numberValue(value, fallback) {
var n = Number(value);
return isNaN(n) ? fallback || 0 : n;
}
function updateStats(data) {
data = data || {};
promoSummary.salesBalance = numberValue(
firstDefined(
data.salesBalance,
data.rebateBalance,
data.availableRebate,
data.availableAmount,
data.canWithdrawAmount,
promoSummary.salesBalance,
),
);
promoSummary.totalSubordinates = numberValue(
firstDefined(
data.totalSubordinates,
data.inviteTotal,
data.inviteCount,
data.totalInvite,
promoSummary.totalSubordinates,
),
);
promoSummary.distributionIncome = numberValue(
firstDefined(
data.distributionIncome,
data.rebateTotal,
data.totalRebate,
data.totalAmount,
promoSummary.distributionIncome,
),
);
promoSummary.pendingRebate = numberValue(
firstDefined(
data.pendingRebate,
data.pendingAmount,
data.waitAmount,
data.unsettledAmount,
promoSummary.pendingRebate,
),
);
promoSummary.rebateRate = firstDefined(
data.rebateRate,
data.rate,
data.rebateRatio,
promoSummary.rebateRate,
);
$("#salesBalance").text((promoSummary.salesBalance || 0).toFixed(2));
$("#totalSubordinates").text(promoSummary.totalSubordinates || 0);
$("#distIncome").text(
(promoSummary.distributionIncome || 0).toFixed(2),
);
$("#pendingRebate").text((promoSummary.pendingRebate || 0).toFixed(2));
$("#rebateRate").text(rateText(promoSummary.rebateRate));
}
function rateText(value) {
if (value === undefined || value === null || value === "") return "--";
var n = Number(value);
if (isNaN(n)) return String(value);
return n > 0 && n < 1 ? Math.round(n * 100) + "%" : n + "%";
}
function totalOf(data, rows) {
return (
numberValue(
firstDefined(data.totalRow, data.total, data.totalCount, data.count),
0,
) || (rows ? rows.length : 0)
);
}
function fullShareLink(url, code) {
if (url && /^https?:\/\//.test(url)) return url;
if (url) {
if (url.indexOf("/html/reg.html") >= 0) {
return ApiClient.baseUrl.replace(/\/$/, "") + "/" + url.replace(/^\//, "");
}
return (
ApiClient.baseUrl.replace(/\/$/, "") +
"/html/reg.html?affUrl=" +
encodeURIComponent(url.replace(/^\//, ""))
);
}
return (
location.origin +
"/html/reg.html" +
(code ? "?inviteCode=" + encodeURIComponent(code) : "")
);
}
// Load promotion info (link + QR code)
function loadPromoInfo() {
ApiClient.get(ApiClient.API.referralShareInfo)
.then(function (res) {
if (isSuccess(res)) {
var data = pickData(res, {}) || {};
// Build share link
var shareLink = fullShareLink(
firstDefined(
data.affUrl,
data.shareUrl,
data.shareLink,
data.inviteUrl,
data.promoteUrl,
data.referralUrl,
data.url,
),
firstDefined(
data.inviteCode,
data.referralCode,
data.affCode,
data.code,
),
);
$("#promoLink").val(shareLink);
// Generate QR code
if (shareLink) {
CommonUtil.generateQRCode(shareLink, "promoQrImg", {
width: 200,
height: 200,
colorDark: "#102b6a",
colorLight: "#ffffff",
});
}
updateStats(data);
}
})
.catch(function (err) {
console.error("获取推广信息失败:", err);
});
}
function loadPromoSummary() {
if (!ApiClient.API.referralSummary) return;
ApiClient.get(ApiClient.API.referralSummary)
.then(function (res) {
if (isSuccess(res)) updateStats(pickData(res, {}) || {});
})
.catch(function (err) {
console.error("获取推广统计失败:", err);
});
}
// Copy promo link
function copyPromoLink() {
var link = $("#promoLink").val();
if (!link) {
layui.layer.msg("推广链接为空", { icon: 2 });
return;
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard
.writeText(link)
.then(function () {
layui.layer.msg("链接已复制到剪贴板!", { icon: 1, time: 1500 });
var $btn = $("#copyLinkBtn");
$btn
.text("已复制")
.css(
"background",
"linear-gradient(135deg, var(--green), #2ecc71)",
);
setTimeout(function () {
$btn.text("复制链接").css("background", "");
}, 2000);
})
.catch(function () {
fallbackCopy(link);
});
} else {
fallbackCopy(link);
}
}
function fallbackCopy(text) {
var input = document.createElement("input");
input.value = text;
document.body.appendChild(input);
input.select();
try {
document.execCommand("copy");
layui.layer.msg("链接已复制到剪贴板!", { icon: 1, time: 1500 });
} catch (e) {
layui.layer.msg("复制失败,请手动复制", { icon: 2 });
}
document.body.removeChild(input);
}
function closeQrDialog() {
$("#qrDialog").hide();
}
function avatarCell(item, fallbackName) {
var avatar = firstDefined(item.avatar, item.avatarUrl, item.headImg);
if (avatar) {
return (
'<img src="' +
escapeHtml(avatar) +
'" style="width:32px;height:32px;border-radius:50%;object-fit:cover;border:2px solid rgba(253,185,51,0.4);" />'
);
}
return (
'<div style="width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,var(--primary),var(--primary-light));color:#fff;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;">' +
escapeHtml((fallbackName || "用").charAt(0)) +
"</div>"
);
}
function statusLabel(label, type) {
return (
'<span class="promo-status ' +
type +
'">' +
escapeHtml(label) +
"</span>"
);
}
function loadInviteList() {
var params = { pageNum: invitePage, pageSize: pageSize };
if (inviteFilter === "active") params.consumed = true;
if (inviteFilter === "new") params.consumed = false;
ApiClient.get(ApiClient.API.referralInviteList, params)
.then(function (res) {
if (isSuccess(res)) {
var data = pickData(res, {}) || {};
var list = asRows(data);
renderInviteList(list);
renderPager("invitePager", totalOf(data, list), invitePage, function (page) {
invitePage = page;
loadInviteList();
});
} else {
renderInviteList([]);
renderPager("invitePager", 0, 1, function () {});
}
})
.catch(function (err) {
console.error("请求邀请用户失败:", err);
$("#inviteTableBody").html(
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">加载失败,请重试</td></tr>',
);
});
}
function renderInviteList(list) {
var $tbody = $("#inviteTableBody");
$tbody.empty();
if (!list || !list.length) {
$tbody.html(
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">暂无邀请用户</td></tr>',
);
return;
}
$.each(list, function (i, item) {
var nickName = firstDefined(
item.nickName,
item.nickname,
item.userName,
item.username,
item.mobile,
item.phone,
"未知用户",
);
var registerTime = firstDefined(
item.registerTime,
item.regTime,
item.createTime,
item.createdAt,
);
var consumeAmount = numberValue(
firstDefined(item.consumeAmount, item.amount, item.totalAmount),
).toFixed(2);
var rebateAmount = numberValue(
firstDefined(
item.rebateMoney,
item.rebateAmount,
item.commissionAmount,
item.rewardAmount,
),
).toFixed(2);
var consumed =
item.hasConsume === true ||
item.isConsumed === true ||
item.consumeFlag === 1 ||
item.consumeFlag === "1" ||
Number(consumeAmount) > 0;
$tbody.append(
"<tr>" +
"<td>" +
avatarCell(item, nickName) +
"</td>" +
"<td>" +
escapeHtml(nickName) +
"</td>" +
"<td>" +
escapeHtml(registerTime ? String(registerTime).substring(0, 10) : "--") +
"</td>" +
"<td>" +
consumeAmount +
"元</td>" +
'<td style="color:var(--orange);font-weight:600;">' +
rebateAmount +
"元</td>" +
"<td>" +
(consumed
? statusLabel("已消费", "success")
: statusLabel("未消费", "pending")) +
"</td>" +
"</tr>",
);
});
}
function loadRebateList() {
var params = { pageNum: rebatePage, pageSize: pageSize };
if (rebateFilter === "pending") params.status = 0;
if (rebateFilter === "success") params.status = 1;
ApiClient.get(ApiClient.API.referralRebateList, params)
.then(function (res) {
if (isSuccess(res)) {
var data = pickData(res, {}) || {};
var list = asRows(data);
renderRebateList(list);
renderPager("rebatePager", totalOf(data, list), rebatePage, function (page) {
rebatePage = page;
loadRebateList();
});
} else {
renderRebateList([]);
renderPager("rebatePager", 0, 1, function () {});
}
})
.catch(function (err) {
console.error("请求返利流水失败:", err);
$("#rebateTableBody").html(
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">加载失败,请重试</td></tr>',
);
});
}
function renderRebateList(list) {
var $tbody = $("#rebateTableBody");
$tbody.empty();
if (!list || !list.length) {
$tbody.html(
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">暂无返利流水</td></tr>',
);
return;
}
$.each(list, function (i, item) {
var flowNo = firstDefined(item.flowNo, item.orderNo, item.id, item.rebateNo, "--");
var sourceUser = firstDefined(
item.sourceUserName,
item.inviteUserName,
item.nickName,
item.nickname,
item.mobile,
"未知用户",
);
var amount = numberValue(
firstDefined(
item.rebateMoney,
item.rebateAmount,
item.commissionAmount,
item.rewardAmount,
item.amount,
),
).toFixed(2);
var rate = rateText(firstDefined(item.rebateRate, item.rate, item.ratio));
var status = firstDefined(item.status, item.state, item.settleStatus, 0);
var statusHtml =
status === 1 ||
status === "1" ||
status === "success" ||
status === "settled"
? statusLabel("已结算", "success")
: statusLabel("待结算", "pending");
var time = firstDefined(item.createTime, item.settleTime, item.time, item.createdAt);
$tbody.append(
"<tr>" +
"<td>" +
escapeHtml(flowNo) +
"</td>" +
"<td>" +
escapeHtml(sourceUser) +
"</td>" +
'<td style="color:var(--orange);font-weight:600;">' +
amount +
"元</td>" +
"<td>" +
escapeHtml(rate) +
"</td>" +
"<td>" +
statusHtml +
"</td>" +
"<td>" +
escapeHtml(time ? String(time).substring(0, 19).replace("T", " ") : "--") +
"</td>" +
"</tr>",
);
});
}
function renderPager(elem, total, curr, onJump) {
layui.laypage.render({
elem: elem,
count: total,
limit: pageSize,
curr: curr,
layout: ["prev", "page", "next"],
jump: function (obj, first) {
if (!first && obj.curr !== curr) onJump(obj.curr);
},
});
}
function escapeHtml(str) {
if (str === undefined || str === null) return "";
return String(str)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
// Init
$(function () {
checkLogin();
renderNav();
CommonUtil.loadPageConfig({ ads: false, links: false });
$("#inviteFilter button").on("click", function () {
$("#inviteFilter button").removeClass("active");
$(this).addClass("active");
inviteFilter = $(this).data("filter");
invitePage = 1;
loadInviteList();
});
$("#rebateFilter button").on("click", function () {
$("#rebateFilter button").removeClass("active");
$(this).addClass("active");
rebateFilter = $(this).data("filter");
rebatePage = 1;
loadRebateList();
});
CommonUtil.requireAuth(function () {
loadPromoInfo();
loadPromoSummary();
loadInviteList();
loadRebateList();
});
});
</script>
</body>
</html>