修改功能,现已测试注册登录忘记密码

This commit is contained in:
rain
2026-06-12 11:42:49 +08:00
parent 0bf2f573ed
commit cfc64c69e5
26 changed files with 2238 additions and 898 deletions
+59
View File
@@ -228,7 +228,66 @@
colorLight: "#ffffff",
});
var DEFAULT_DOWNLOAD_INFO = {
appName: "彩先知",
version: "1.0.0",
intro: "随时随地查看预测分析,不错过任何精彩推荐",
downloadUrl: downloadUrl,
};
function normalizeDownloadInfo(response) {
var data = response && (response.data || response.result || response);
if (!data || typeof data !== "object") return DEFAULT_DOWNLOAD_INFO;
return {
appName: data.appName || data.name || DEFAULT_DOWNLOAD_INFO.appName,
version: data.version || data.versionName || DEFAULT_DOWNLOAD_INFO.version,
intro:
data.intro ||
data.description ||
data.remark ||
DEFAULT_DOWNLOAD_INFO.intro,
downloadUrl:
data.downloadUrl ||
data.apkUrl ||
data.androidUrl ||
data.url ||
DEFAULT_DOWNLOAD_INFO.downloadUrl,
iosUrl: data.iosUrl || data.iphoneUrl || data.appStoreUrl || "",
};
}
function applyDownloadInfo(info) {
var nextInfo = $.extend({}, DEFAULT_DOWNLOAD_INFO, info || {});
if (nextInfo.appName) {
$(".hero-text h1").html("下载" + CommonUtil.escapeHtml(nextInfo.appName) + "<span>APP</span>");
}
if (nextInfo.intro) {
$(".hero-text p").first().text(nextInfo.intro);
}
if (nextInfo.downloadUrl) {
$("#androidBtn").attr("href", nextInfo.downloadUrl);
CommonUtil.generateQRCode(nextInfo.downloadUrl, "downloadQrImg", {
width: 180,
height: 180,
colorDark: "#102b6a",
colorLight: "#ffffff",
});
}
if (nextInfo.iosUrl) $("#iosBtn").attr("href", nextInfo.iosUrl);
}
function loadDownloadInfo() {
return ApiClient.post(ApiClient.API.appDownloadInfo, {}, { publicRequest: true })
.then(function (response) {
if (ApiClient.isSuccess(response) || response.data || response.result) {
applyDownloadInfo(normalizeDownloadInfo(response));
}
})
.catch(function () {});
}
// Load download links from page config
loadDownloadInfo();
ApiClient.post("/api/web/index", {})
.then(function (result) {
if (result.data && result.data.webConfigs) {
+81 -366
View File
@@ -13,6 +13,7 @@
<link rel="stylesheet" href="../public/css/public.css" />
<link rel="stylesheet" href="../public/css/publish.css" />
<link rel="stylesheet" href="../public/css/finance.css" />
<link rel="stylesheet" href="../public/css/chongzhi.css" />
</head>
<body>
<!-- Header -->
@@ -33,7 +34,7 @@
>免费注册</a
>
</div>
<div id="loggedInBox" class="topbar__logged" style="display: none">
<div id="loggedInBox" class="topbar__logged cz-hidden">
<a href="usercenter.html" class="topbar__profile">
<img
id="userAvatar"
@@ -66,8 +67,7 @@
<div class="cz-balance-bar">
<div class="cz-balance-bar__item">
<div
class="cz-balance-bar__icon"
style="background: rgba(16, 43, 106, 0.08); color: var(--primary)"
class="cz-balance-bar__icon account"
>
<i class="layui-icon layui-icon-rmb"></i>
</div>
@@ -103,7 +103,7 @@
</div>
<!-- QR Code Payment Section -->
<div class="cxz-form-card" id="qrcodeCard" style="display: none">
<div class="cxz-form-card cz-hidden" id="qrcodeCard">
<div class="cz-qr-section" id="qrSection">
<div class="cz-qr-header">
<div class="cz-qr-icon">
@@ -127,7 +127,7 @@
</button>
</div>
<div class="cz-pay-result" id="paymentSuccess" style="display: none">
<div class="cz-pay-result cz-hidden" id="paymentSuccess">
<div class="cz-pay-result__icon success">
<i class="layui-icon layui-icon-ok-circle"></i>
</div>
@@ -136,7 +136,7 @@
<a href="usercenter.html" class="cz-pay-result__btn">返回个人中心</a>
</div>
<div class="cz-pay-result" id="paymentTimeout" style="display: none">
<div class="cz-pay-result cz-hidden" id="paymentTimeout">
<div class="cz-pay-result__icon timeout">
<i class="layui-icon layui-icon-close-fill"></i>
</div>
@@ -176,7 +176,7 @@
id="beian"
href="https://beian.miit.gov.cn/"
target="_blank"
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
class="cz-footer-link"
>工信部备案号</a
>
<span id="additional-info">本站仅供数据分析参考</span>
@@ -193,359 +193,6 @@
</button>
<script src="../public/js/qrcode.min.js"></script>
<style>
/* Balance Bar */
.cz-balance-bar {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-bottom: 24px;
}
.cz-balance-bar__item {
background: var(--white);
border-radius: var(--radius-lg);
padding: 20px 24px;
box-shadow: var(--shadow-sm);
display: flex;
align-items: center;
gap: 16px;
border: 1px solid var(--border-light);
transition: all 0.3s;
}
.cz-balance-bar__item:hover {
border-color: transparent;
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.cz-balance-bar__icon {
width: 48px;
height: 48px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
flex-shrink: 0;
}
.cz-balance-bar__label {
font-size: 13px;
color: var(--text-muted);
}
.cz-balance-bar__value {
font-size: 24px;
font-weight: 800;
color: var(--text-dark);
line-height: 1.2;
}
.cz-balance-bar__value .unit {
font-size: 14px;
font-weight: 400;
color: var(--text-muted);
margin-left: 2px;
}
/* Package Grid */
.cz-package-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px;
margin-bottom: 24px;
}
.cz-package-loading {
grid-column: 1/-1;
text-align: center;
padding: 40px;
color: var(--text-muted);
}
.cz-package-loading i {
font-size: 28px;
display: block;
margin-bottom: 8px;
color: var(--primary);
}
.cz-pkg {
position: relative;
background: var(--bg-light);
border: 2px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 20px 16px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
user-select: none;
overflow: hidden;
}
.cz-pkg:hover {
border-color: var(--primary);
transform: translateY(-2px);
box-shadow: var(--shadow-sm);
}
.cz-pkg.selected {
border-color: var(--primary);
background: rgba(16, 43, 106, 0.04);
box-shadow: 0 0 0 3px rgba(16, 43, 106, 0.12);
}
.cz-pkg.selected::after {
content: "\2713";
position: absolute;
top: 0;
right: 0;
width: 24px;
height: 24px;
background: var(--primary);
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0 var(--radius-lg) 0 var(--radius-lg);
}
.cz-pkg__price {
font-size: 28px;
font-weight: 800;
color: var(--primary);
line-height: 1.2;
}
.cz-pkg__price span {
font-size: 14px;
font-weight: 600;
}
.cz-pkg__credit {
display: inline-block;
margin-top: 8px;
padding: 3px 10px;
border-radius: 999px;
font-size: 12px;
font-weight: 700;
background: rgba(253, 185, 51, 0.12);
color: var(--gold);
}
.cz-pkg__bonus {
display: inline-block;
margin-top: 4px;
padding: 2px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(241, 90, 34, 0.1);
color: var(--orange);
}
.cz-pkg.selected .cz-pkg__price {
color: var(--primary);
}
/* Hot / Recommend tag */
.cz-pkg__tag {
position: absolute;
top: 8px;
left: 8px;
padding: 2px 8px;
border-radius: 999px;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.5px;
color: #fff;
}
.cz-pkg__tag.hot {
background: linear-gradient(135deg, #ff6b35, #f15a22);
}
.cz-pkg__tag.rec {
background: linear-gradient(135deg, var(--primary), #1a3f8f);
}
/* QR Code Section */
.cz-qr-section {
text-align: center;
padding: 24px 0;
}
.cz-qr-header {
margin-bottom: 16px;
}
.cz-qr-icon {
width: 48px;
height: 48px;
border-radius: 50%;
background: rgba(7, 193, 96, 0.1);
color: #07c160;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 24px;
margin-bottom: 8px;
}
.cz-qr-title {
font-size: 18px;
font-weight: 700;
color: var(--text-dark);
}
.cz-qr-subtitle {
font-size: 13px;
color: var(--text-muted);
margin-top: 4px;
}
.cz-qr-amount {
font-size: 32px;
font-weight: 800;
color: var(--orange);
margin: 16px 0;
}
.cz-qr-amount span {
font-size: 16px;
font-weight: 600;
color: var(--text-muted);
}
.cz-qr-wrap {
display: inline-block;
padding: 16px;
background: #fff;
border: 2px solid var(--border-light);
border-radius: var(--radius-lg);
margin-bottom: 12px;
}
.cz-qr-wrap img,
.cz-qr-wrap canvas {
display: block;
width: 200px;
height: 200px;
}
.cz-qr-hint {
font-size: 13px;
color: var(--text-muted);
margin-top: 8px;
}
.cz-qr-timer {
font-size: 14px;
color: var(--orange);
margin-top: 8px;
font-weight: 700;
}
.cz-qr-cancel {
margin-top: 16px;
padding: 8px 24px;
border: 1px solid var(--border-light);
border-radius: 999px;
background: transparent;
color: var(--text-muted);
font-size: 13px;
cursor: pointer;
transition: all 0.25s;
}
.cz-qr-cancel:hover {
border-color: var(--primary);
color: var(--primary);
}
/* Payment Result */
.cz-pay-result {
text-align: center;
padding: 40px 0;
}
.cz-pay-result__icon {
width: 72px;
height: 72px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 36px;
margin-bottom: 16px;
}
.cz-pay-result__icon.success {
background: rgba(40, 167, 69, 0.12);
color: var(--green);
}
.cz-pay-result__icon.timeout {
background: rgba(255, 193, 7, 0.15);
color: #ffc107;
}
.cz-pay-result__title {
font-size: 20px;
font-weight: 700;
color: var(--text-dark);
margin-bottom: 8px;
}
.cz-pay-result__desc {
font-size: 13px;
color: var(--text-muted);
margin-bottom: 20px;
}
.cz-pay-result__btn {
display: inline-block;
padding: 10px 32px;
border-radius: 999px;
font-size: 14px;
font-weight: 700;
background: linear-gradient(135deg, var(--primary), #1a3f8f);
color: #fff;
text-decoration: none;
cursor: pointer;
border: none;
transition: all 0.3s;
}
.cz-pay-result__btn:hover {
box-shadow: 0 6px 20px rgba(16, 43, 106, 0.4);
transform: translateY(-2px);
}
/* Tips Card */
.cz-tips-card {
background: var(--white);
border-radius: var(--radius-lg);
padding: 20px 24px;
border: 1px solid var(--border-light);
margin-top: 24px;
}
.cz-tips-title {
font-size: 14px;
font-weight: 700;
color: var(--text-dark);
margin-bottom: 12px;
}
.cz-tips-title i {
color: var(--primary);
margin-right: 4px;
}
.cz-tips-list {
margin: 0;
padding-left: 18px;
}
.cz-tips-list li {
font-size: 12px;
color: var(--text-muted);
line-height: 2;
position: relative;
}
/* Responsive */
@media (max-width: 768px) {
.cz-balance-bar {
grid-template-columns: 1fr;
}
.cz-package-grid {
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.cz-pkg {
padding: 16px 12px;
}
.cz-pkg__price {
font-size: 22px;
}
}
@media (max-width: 480px) {
.cz-package-grid {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.cz-pkg__price {
font-size: 20px;
}
.cz-pkg__credit {
font-size: 11px;
}
}
</style>
<script>
const $ = layui.$;
var configList = [];
@@ -556,6 +203,9 @@
var countdownSeconds = 300;
var pollingStartTime = 0;
var MAX_POLLING_DURATION = 300000;
var POLLING_INTERVAL = 3000;
var currentRechargeOutTradeNo = "";
var currentRechargeExpireTime = 0;
function escapeHtml(value) {
return String(value == null ? "" : value)
@@ -643,7 +293,7 @@
}
})
.catch(function () {
renderEmptyPackages("加载失败,请刷新重试");
renderEmptyPackages("加载失败,请刷新重试");
});
}
@@ -751,12 +401,18 @@
var data = ApiClient.pickData ? ApiClient.pickData(res) : res.data;
if (ApiClient.isSuccess(res) && data) {
var payUrl = getRechargePaymentUrl(data);
var outTradeNo = getRechargeOutTradeNo(data);
var expireTime = getRechargeExpireTime(data);
var amount = data.amount || data.paidAmount || selectedConfigAmount;
if (!payUrl) {
layui.layer.msg("\u8ba2\u5355\u672a\u8fd4\u56de\u652f\u4ed8\u4e8c\u7ef4\u7801\u5185\u5bb9", { icon: 2 });
return;
}
showQRCode(payUrl, amount);
if (!outTradeNo) {
layui.layer.msg("充值订单未返回订单号,无法查询支付状态", { icon: 2 });
return;
}
showQRCode(payUrl, amount, outTradeNo, expireTime);
} else {
layui.layer.msg(res.msg || "创建订单失败", { icon: 2 });
}
@@ -772,9 +428,11 @@
if (!data || typeof data !== "object") return "";
return (
data.qrCode ||
data.qrcode ||
data.payUrl ||
data.paymentUrl ||
data.codeUrl ||
data.code_url ||
data.qrCodeUrl ||
data.nativeUrl ||
data.url ||
@@ -782,8 +440,22 @@
);
}
function getRechargeOutTradeNo(data) {
if (!data || typeof data !== "object") return "";
return data.outTradeNo || data.out_trade_no || data.orderNo || data.order_no || data.tradeNo || data.trade_no || "";
}
function getRechargeExpireTime(data) {
if (!data || typeof data !== "object") return 0;
var value = data.expireTime || data.expire_time || data.expiredAt || data.expired_at || data.expiresAt || data.expires_at;
if (!value) return Date.now() + MAX_POLLING_DURATION;
var parsed = typeof value === "number" ? value : Date.parse(value);
if (!parsed || Number.isNaN(parsed)) return Date.now() + MAX_POLLING_DURATION;
return parsed < 10000000000 ? parsed * 1000 : parsed;
}
// Show QR code
function showQRCode(url, amount) {
function showQRCode(url, amount, outTradeNo, expireTime) {
$("#qrcodeCard").show();
$("#qrSection").show();
$("#paymentSuccess").hide();
@@ -803,7 +475,10 @@
countdownSeconds = 300;
pollingStartTime = Date.now();
currentRechargeOutTradeNo = outTradeNo || "";
currentRechargeExpireTime = expireTime || Date.now() + MAX_POLLING_DURATION;
startCountdown();
startPolling();
$("html,body").animate(
{ scrollTop: $("#qrcodeCard").offset().top - 20 },
@@ -839,7 +514,7 @@
function doPoll() {
var elapsed = Date.now() - pollingStartTime;
if (elapsed >= MAX_POLLING_DURATION) {
if (elapsed >= MAX_POLLING_DURATION || Date.now() >= currentRechargeExpireTime) {
stopPolling();
clearInterval(countdownTimer);
$("#qrSection").hide();
@@ -847,14 +522,54 @@
return;
}
scheduleNextPoll();
if (!currentRechargeOutTradeNo) {
scheduleNextPoll();
return;
}
queryRechargeOrderStatus(currentRechargeOutTradeNo)
.then(function (paid) {
if (paid) {
stopPolling();
if (countdownTimer) clearInterval(countdownTimer);
$("#qrSection").hide();
$("#paymentTimeout").hide();
$("#paymentSuccess").show();
layui.layer.msg("充值成功", { icon: 1 });
return;
}
scheduleNextPoll();
})
.catch(function () {
scheduleNextPoll();
});
}
function scheduleNextPoll() {
var delay = 1000 + Math.floor(Math.random() * 4000);
var delay = POLLING_INTERVAL + Math.floor(Math.random() * 1200);
pollingTimer = setTimeout(doPoll, delay);
}
function queryRechargeOrderStatus(outTradeNo) {
return ApiClient.get(ApiClient.API.walletRechargeOrderStatus(outTradeNo))
.then(function (res) {
if (!ApiClient.isSuccess(res)) return false;
var data = ApiClient.pickData ? ApiClient.pickData(res, {}) : res.data || {};
var status = String(data.status || data.payStatus || data.walletStatus || data.orderStatus || data.tradeStatus || "").toLowerCase();
return (
data.paid === true ||
data.success === true ||
data.paySuccess === true ||
status === "success" ||
status === "paid" ||
status === "2" ||
status === "1" ||
Number(data.status) === 2 ||
Number(data.payStatus) === 2
);
});
}
function stopPolling() {
if (pollingTimer) {
clearTimeout(pollingTimer);
+93 -40
View File
@@ -81,7 +81,7 @@
提示:实习期为三天,连续每天发布2篇以上的优质免费文章审核通过后,自动升级为正式专家。
</div>
<div class="publish-tip-item">
免费文章标准:标题20字以上(含期号、彩种、专家名称、标题),正文500字以上,需原创。
免费文章标准:标题15-30字(含期号、彩种、专家名称、标题),正文500字以上,需原创。
</div>
</div>
@@ -105,11 +105,11 @@
class="form-input"
id="articleTitle"
placeholder="请输入文章标题(含期号、彩种、标题)"
maxlength="100"
maxlength="30"
oninput="updateTitleCount()"
/>
<span class="form-input-count"
><span id="titleCount">0</span>/100</span
><span id="titleCount">0</span>/30</span
>
</div>
</div>
@@ -175,6 +175,13 @@
var layer;
var editor;
var pageReady = false;
var publishPermission = {
canFree: false,
canPaid: false,
};
var REQUIRED_DAILY_FREE_ARTICLES = 2;
var FREE_TITLE_MIN_LENGTH = 15;
var FREE_TITLE_MAX_LENGTH = 30;
function autoFormatEditorContent() {
if (!editor) return;
@@ -227,8 +234,9 @@
renderLoginState();
renderNav();
CommonUtil.requireAuth(function () {
loadPublishIdentity().then(function (allowed) {
if (!allowed) {
loadPublishPermission().then(function (permission) {
publishPermission = permission;
if (!permission.canFree) {
layer.alert(
"您还不是实习或正式专家,暂不能发布文章。",
{ title: "暂无权限" },
@@ -381,48 +389,89 @@
});
}
function checkPaidPublishPermission() {
function parsePublishPermission(userData) {
var status = String(
userData.expertStatus || userData.expert_status || "",
).toLowerCase();
var isIntern = /实习|intern|trial/.test(status);
var isRegularByStatus = /正式|regular|formal/.test(status);
var hasExpertIdentity =
isTruthy(userData.is_expert) ||
isTruthy(userData.isExpert) ||
isTruthy(userData.expert) ||
isTruthy(userData.is_regular_expert) ||
isTruthy(userData.isRegularExpert) ||
isTruthy(userData.regularExpert) ||
isIntern ||
isRegularByStatus;
var isRegularExpert =
isTruthy(userData.is_regular_expert) ||
isTruthy(userData.isRegularExpert) ||
isTruthy(userData.regularExpert) ||
isRegularByStatus;
return {
hasExpertIdentity: hasExpertIdentity,
isRegularExpert: hasExpertIdentity && isRegularExpert,
canFree: hasExpertIdentity,
canPaid: false,
todayFreeArticleCount: 0,
paidReason: isRegularExpert
? "今天需先发布2篇审核通过的免费文章后,才能发布付费文章"
: "正式专家才能发布付费文章",
};
}
function loadPublishPermission() {
return ApiClient.get(ApiClient.API.mineSummary)
.then(function (res) {
if (!ApiClient.isSuccess(res) || !res.data) {
return { canPaid: false, reason: "暂时无法获取发布权限。" };
return {
hasExpertIdentity: false,
isRegularExpert: false,
canFree: false,
canPaid: false,
todayFreeArticleCount: 0,
paidReason: "暂时无法获取发布权限。",
};
}
var status = String(
res.data.expertStatus || res.data.expert_status || "",
).toLowerCase();
var hasExpertIdentity =
isTruthy(res.data.is_expert) ||
isTruthy(res.data.isExpert) ||
isTruthy(res.data.expert) ||
isTruthy(res.data.is_regular_expert) ||
isTruthy(res.data.isRegularExpert) ||
isTruthy(res.data.regularExpert) ||
isTruthy(res.data.internExpert) ||
isTruthy(res.data.isInternExpert) ||
/实习|intern|trial|正式|regular|formal/.test(status);
if (!hasExpertIdentity) {
return { canPaid: false, reason: "专家才能发布付费文章。" };
}
var permission = parsePublishPermission(res.data);
if (!permission.canFree || !permission.isRegularExpert) return permission;
return loadTodayPublishedFreeCount().then(function (count) {
return {
canPaid: count >= 2,
reason:
count >= 2
? ""
: "今天需先发布2篇审核通过的免费文章后,才能发布付费文章(当前" +
count +
"篇)。",
};
permission.todayFreeArticleCount = count;
permission.canPaid = count >= REQUIRED_DAILY_FREE_ARTICLES;
permission.paidReason = permission.canPaid
? ""
: "今天需先发布2篇审核通过的免费文章后,才能发布付费文章(当前" +
count +
"篇)。";
return permission;
});
})
.catch(function () {
return { canPaid: false, reason: "暂时无法获取发布权限。" };
return {
hasExpertIdentity: false,
isRegularExpert: false,
canFree: false,
canPaid: false,
todayFreeArticleCount: 0,
paidReason: "暂时无法获取发布权限。",
};
});
}
function checkPaidPublishPermission() {
return loadPublishPermission().then(function (permission) {
publishPermission = permission;
return {
canPaid: permission.canPaid,
reason: permission.paidReason,
};
});
}
function isExpertUser(data) {
if (!data) return false;
var levelText = CommonUtil.getUserLevelText
@@ -504,10 +553,11 @@
item.name || item.menuName || item.title || "",
).trim();
var code = String(item.suoxie || item.code || "").trim();
var type = String(item.type || "").toLowerCase();
if (["首页", "专家推荐"].indexOf(name) > -1) return false;
if (/^(home|index|zhuanjia|expert|expertRecommend)$/i.test(code))
return false;
return !!(item.id || item.menuId) && !!name;
return type === "lottery" && !!(item.id || item.menuId) && !!name;
}
function loadMenuList() {
@@ -577,12 +627,12 @@
layer.msg("请选择彩种", { icon: 2 });
return;
}
if (title.length < 20) {
layer.msg("标题不能少于20字", { icon: 2 });
if (title.length < FREE_TITLE_MIN_LENGTH) {
layer.msg("免费文章标题需控制在15-30个字之间", { icon: 2 });
return;
}
if (title.length > 100) {
layer.msg("标题不能超过100字", { icon: 2 });
if (title.length > FREE_TITLE_MAX_LENGTH) {
layer.msg("免费文章标题需控制在15-30个字之间", { icon: 2 });
return;
}
if (!content || text.length < 500) {
@@ -597,6 +647,9 @@
menuId: menuId,
title: title,
content: content,
accountType: 1,
}, {
headers: CommonUtil.authHeaders(),
})
.then(function (res) {
if (isApiSuccess(res)) {
@@ -604,7 +657,7 @@
"发布成功,请等待审核",
{ icon: 1, time: 1600 },
function () {
window.location.href = "usercenter.html";
window.location.href = "index.html";
},
);
} else {
+105
View File
@@ -6,6 +6,7 @@
<title id="page-title">彩先知 - 分销中心</title>
<script src="../public/css/layui/layui.js"></script>
<script src="../config.js"></script>
<script src="../public/js/qrcode.min.js"></script>
<script src="../utils/ApiClient.js"></script>
<script src="../utils/DateUtil.js"></script>
<script src="../utils/CommonUtil.js"></script>
@@ -102,6 +103,16 @@
<!-- Action Section -->
<div class="action-section">
<div class="action-card">
<div class="action-card-title">
<i class="layui-icon layui-icon-share"></i> 推广分享
</div>
<div class="action-card-desc">
复制分销链接,邀请好友注册获得佣金;也可以生成推广二维码进行分享。
</div>
<button class="action-card-btn btn-apply-dist" id="fzlj" type="button">复制链接</button>
<button class="action-card-btn btn-apply-expert" id="tgewm" type="button">推广二维码</button>
</div>
<div class="action-card">
<div class="action-card-title">
<i class="layui-icon layui-icon-group"></i> 申请分销
@@ -210,6 +221,7 @@
// Check login state for topbar
checkLogin();
renderNav();
initShareFunctions();
// Check auth and load user detail
CommonUtil.requireAuth(function () {
@@ -264,6 +276,99 @@
: $("#backTop").removeClass("is-visible");
});
function getApiBaseUrl() {
return (ApiClient.baseUrl || (window.CONFIG && CONFIG.API_BASE_URL) || window.location.origin || "").replace(/\/$/, "");
}
function normalizeShareLink(data) {
var affUrl = (data && (data.affUrl || data.shareUrl || data.inviteUrl || data.url)) || "";
if (!affUrl) return "";
if (/^https?:\/\//i.test(affUrl)) return affUrl;
return getApiBaseUrl() + "/html/reg.html?affUrl=" + String(affUrl).replace(/^\//, "");
}
function getAffInfo() {
return ApiClient.post("/api/web/rebate/getAffInfo", {}, { headers: CommonUtil.authHeaders() });
}
function copyText(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text);
}
var $input = $("<textarea>").val(text).css({ position: "fixed", left: "-9999px", top: "-9999px" });
$("body").append($input);
$input[0].select();
document.execCommand("copy");
$input.remove();
return Promise.resolve();
}
function initShareFunctions() {
$("#fzlj").on("click", copyShareLink);
$("#tgewm").on("click", showQrCodeModal);
}
function copyShareLink() {
CommonUtil.requireAuth(function () {
getAffInfo()
.then(function (res) {
if (res.code !== 0 || !res.data) throw new Error(res.msg || "获取分享链接失败");
var shareLink = normalizeShareLink(res.data);
if (!shareLink) throw new Error("接口未返回分享链接");
return copyText(shareLink);
})
.then(function () {
layer.msg("链接已复制到剪贴板", { icon: 1, time: 1500 });
})
.catch(function (err) {
layer.msg(err.message || "复制失败,请手动复制", { icon: 2 });
});
});
}
function showQrCodeModal() {
CommonUtil.requireAuth(function () {
getAffInfo()
.then(function (res) {
if (res.code !== 0 || !res.data) throw new Error(res.msg || "获取推广信息失败");
var shareLink = normalizeShareLink(res.data);
if (res.data.affCodeUrl && res.data.affUrl) {
shareLink = String(res.data.affCodeUrl).replace(/\/$/, "") + "/" + String(res.data.affUrl).replace(/^\//, "");
}
if (!shareLink) throw new Error("接口未返回推广二维码链接");
createCustomModal(shareLink);
})
.catch(function (err) {
layer.msg(err.message || "生成二维码失败", { icon: 2 });
});
});
}
function createCustomModal(shareLink) {
var $mask = $('<div class="custom-modal-mask"></div>');
var $modal = $('<div class="custom-modal-content"></div>');
var $qrContainer = $('<div class="custom-qr-container"></div>');
$modal.append('<h3 class="custom-modal-title">推广二维码</h3>');
$modal.append($qrContainer);
$modal.append('<button class="custom-modal-close" type="button">关闭</button>');
$mask.append($modal);
$("body").append($mask);
new QRCode($qrContainer[0], {
text: shareLink,
width: 200,
height: 200,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H,
});
$mask.on("click", function (event) {
if (event.target === $mask[0]) $mask.remove();
});
$modal.find(".custom-modal-close").on("click", function () {
$mask.remove();
});
}
function loadUserDetail() {
CommonUtil.getCurrentUserDetail(
function (data) {
+1 -1
View File
@@ -162,7 +162,7 @@
});
function loadNotice() {
ApiClient.post("/api/web/notice/getDetail?id=" + noticeId).then(
ApiClient.get(ApiClient.API.noticeDetail(noticeId)).then(
function (res) {
if (res.code === 0 && res.data) {
renderNotice(res.data);
+8 -3
View File
@@ -159,13 +159,18 @@
// Load notice list
function loadNotices() {
ApiClient.post("/api/web/notice/getPageList", {
ApiClient.get(ApiClient.API.noticeList, {
pageNum: currentPage,
pageSize: pageSize,
count: pageSize,
}).then(function (res) {
if (res.code === 0 && res.data) {
renderNotices(res.data.records || []);
renderPagination(res.data.totalRow || 0);
var data = res.data || {};
var records = Array.isArray(data)
? data
: data.records || data.rows || data.list || [];
renderNotices(records);
renderPagination(data.totalRow || data.total || records.length || 0);
} else {
$("#noticeList").html(
'<div class="cxz-notice-item"><span style="color:var(--text-muted);">暂无公告</span></div>',
+8 -2
View File
@@ -282,14 +282,20 @@
);
return;
}
ApiClient.get("/api/web/lottery/result/list", {
ApiClient.get(ApiClient.API.lotteryResultList, {
menuId: currentMenuId,
pageNum: 1,
pageSize: 50,
}).catch(function () {
return ApiClient.get(ApiClient.API.latestLotteryResult);
}).then(function (res) {
if (ApiClient.isSuccess(res) && ApiClient.pickData(res, null)) {
const data = ApiClient.pickData(res, {}) || {};
const list = data.records || data.rows || data.list || ApiClient.asArray(data);
let list = data.records || data.rows || data.list || ApiClient.asArray(data);
list = ApiClient.asArray(list).filter(function (item) {
const code = item && (item.code || item.suoxie || item.lotteryCode);
return !code || !currentSuoxie || String(code).toLowerCase() === String(currentSuoxie).toLowerCase();
});
renderResults(list);
} else {
$("#resultBody").html(
+12 -17
View File
@@ -119,7 +119,6 @@
let layerInstance = null;
let currentCaptchaId = "";
let currentVerifyType = "captcha";
let currentSlideToken = "";
let currentSlideUuid = "";
let currentSlideX = 0;
@@ -149,7 +148,6 @@
function refreshCaptcha() {
currentCaptchaId = "";
currentSlideToken = "";
currentSlideUuid = "";
currentSlideX = 0;
$("#captchaId").val("");
@@ -193,9 +191,6 @@
function completeSlideCaptcha(result) {
const data = result || {};
const nested = data.data || {};
currentSlideToken =
data.slideToken || data.token || data.verifyToken ||
nested.slideToken || nested.token || nested.verifyToken || "";
currentSlideUuid =
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
currentSlideX =
@@ -222,7 +217,6 @@
onSuccess: completeSlideCaptcha,
onCancel: function () {
currentSlideUuid = "";
currentSlideToken = "";
currentSlideX = 0;
},
onError: function (error) {
@@ -288,7 +282,6 @@
}
return {
verifyType: "slide",
slideToken: currentSlideToken,
slideUuid: currentSlideUuid,
slideX: currentSlideX,
};
@@ -316,10 +309,8 @@
const payload = Object.assign(
{
grantType: "password",
clientId: ApiClient.clientId,
client_id: ApiClient.clientId,
phoneNumber: $("#phoneInput").val().trim(),
password: hex_md5($("#passwordInput").val()),
password: hex_md5($("#passwordInput").val().trim()),
deviceType: "WEB",
},
getVerifyParams(false) || {},
@@ -332,17 +323,21 @@
})
.then(function (res) {
if (ApiClient.isSuccess(res) && res.data) {
localStorage.setItem(
"token",
JSON.stringify(
res.data.token || res.data.access_token || res.data,
),
);
const data = res.data || {};
localStorage.setItem("token", data.access_token || data.token || "");
localStorage.setItem("userInfo", JSON.stringify(data));
sessionStorage.removeItem("authExpiredRedirecting");
sessionStorage.removeItem("authExpiredMessage");
layerInstance.msg(
"登录成功,即将跳转到首页",
{ icon: 1, time: 1200 },
function () {
window.location.href = "index.html";
const redirect = new URLSearchParams(window.location.search).get("redirect");
window.location.href =
redirect ||
(typeof CommonUtil !== "undefined"
? CommonUtil.siteHref("/index.html")
: "index.html");
},
);
return;
+50
View File
@@ -101,6 +101,17 @@
</a>
</div>
<div class="cxz-recommend-section">
<div class="cxz-recommend-card">
<div class="cxz-recommend-title">相关推荐</div>
<ul class="cxz-recommend-list" id="freeRelatedList"></ul>
</div>
<div class="cxz-recommend-card">
<div class="cxz-recommend-title">最新文章</div>
<ul class="cxz-recommend-list" id="freeLatestList"></ul>
</div>
</div>
<!-- Comment Section -->
<div class="cxz-comment-section">
<div class="cxz-comment-header">
@@ -356,8 +367,47 @@
if (!prev && rows[0]) prev = rows[0];
if (!next && rows[1]) next = rows[1];
if (prev || next) renderArticleNav(prev, next);
renderFreeArticleList("#freeRelatedList", rows.filter(function (item) {
var id = item && (item.id || item.articleId || item.freeArticleId);
return id && String(id) !== String(articleId);
}).slice(0, 8));
})
.catch(function () {});
loadFreeArticleLatest();
}
function loadFreeArticleLatest() {
ApiClient.get(ApiClient.API.freeArticleLatest, { articleCount: 8 })
.then(function (res) {
if (!ApiClient.isSuccess(res)) return;
renderFreeArticleList("#freeLatestList", ApiClient.asArray(ApiClient.pickData(res, [])));
})
.catch(function () {
renderFreeArticleList("#freeLatestList", []);
});
}
function renderFreeArticleList(selector, list) {
var $list = $(selector).empty();
if (!list || !list.length) {
$list.html('<li class="cxz-recommend-empty">暂无文章</li>');
return;
}
$.each(list, function (_, item) {
var id = item.id || item.articleId || item.freeArticleId;
if (!id) return;
var title = item.title || item.articleTitle || item.name || "无标题";
var time = DateUtil.formatDateToYMD(item.updateTime || item.createTime || item.publishTime) || "";
$list.append(
'<li><a href="' +
escapeHtml(articleLinkOf(item)) +
'">' +
escapeHtml(title) +
'</a><span>' +
escapeHtml(time) +
"</span></li>",
);
});
}
function updateLikeButton(data) {
+57 -9
View File
@@ -114,6 +114,7 @@
let currentPage = 1;
const pageSize = 15;
let lotteryMenus = [];
let freeArticleGroups = [];
function logout() {
localStorage.removeItem("token");
@@ -155,7 +156,7 @@
if (
menuId &&
lotteryMenus.some(function (item) {
return String(item.id) === String(menuId);
return sameLotteryKey(item, menuId);
})
) {
return;
@@ -165,14 +166,24 @@
}
function renderLotteryTabs() {
return ApiClient.get(ApiClient.API.homeNav)
.then(function (res) {
return Promise.all([
ApiClient.get(ApiClient.API.homeNav).catch(function () {
return { data: [] };
}),
ApiClient.get(ApiClient.API.freeArticleRecommend, { articleCount: pageSize }).catch(function () {
return { data: [] };
}),
])
.then(function (results) {
const res = results[0];
const recommendRes = results[1];
lotteryMenus = normalizeLotteryMenus(ApiClient.pickData(res, []));
freeArticleGroups = ApiClient.asArray(ApiClient.pickData(recommendRes, []));
resolveCurrentMenuId();
const $tabs = $("#lotteryTabs");
$tabs.empty();
$.each(lotteryMenus, function (_, item) {
const id = item.id || "";
const id = item.id || item.menuId || item.code || item.suoxie || "";
$tabs.append(
'<a href="mianfeilist.html?id=' +
encodeURIComponent(id) +
@@ -198,13 +209,41 @@
$(".cxz-lottery-tab").removeClass("active");
$('.cxz-lottery-tab[data-id="' + menuId + '"]').addClass("active");
const currentMenu = lotteryMenus.find(function (item) {
return String(item.id) === String(menuId);
return sameLotteryKey(item, menuId);
});
const name = (currentMenu && currentMenu.name) || "免费推荐";
$("#listTitle").text(name + " - 免费推荐");
document.title = "彩先知 - " + name + "免费推荐";
}
function sameLotteryKey(item, value) {
const key = String(value || "").toLowerCase();
if (!key || !item) return false;
return (
String(item.id || "").toLowerCase() === key ||
String(item.menuId || "").toLowerCase() === key ||
String(item.code || "").toLowerCase() === key ||
String(item.suoxie || "").toLowerCase() === key ||
String(item.lotteryCode || "").toLowerCase() === key ||
String(item.name || "").toLowerCase() === key
);
}
function currentMenuInfo() {
return lotteryMenus.find(function (item) {
return sameLotteryKey(item, menuId);
});
}
function currentFallbackGroup() {
const menu = currentMenuInfo();
return (
freeArticleGroups.find(function (group) {
return sameLotteryKey(group, menuId) || sameLotteryKey(group, menu && (menu.code || menu.suoxie || menu.id));
}) || null
);
}
// Load articles
function loadArticles() {
if (!menuId) {
@@ -214,7 +253,7 @@
renderPagination(0);
return;
}
ApiClient.get("/api/web/free-article/list", {
ApiClient.get(ApiClient.API.freeArticleList, {
menuId: menuId,
pageNum: currentPage,
pageSize: pageSize,
@@ -225,13 +264,22 @@
renderArticles(list);
renderPagination(data.totalRow || data.total || data.count || list.length || 0);
} else {
$("#articleList").html(
'<div class="cxz-article-item"><span style="color:var(--text-muted);">暂无数据</span></div>',
);
renderFallbackArticles();
}
}).catch(function () {
renderFallbackArticles();
});
}
function renderFallbackArticles() {
const group = currentFallbackGroup();
const allArticles = ApiClient.asArray(group && group.articles);
const startIndex = (currentPage - 1) * pageSize;
const records = allArticles.slice(startIndex, startIndex + pageSize);
renderArticles(records);
renderPagination(allArticles.length);
}
function renderArticles(list) {
const $container = $("#articleList");
$container.empty();
+298 -72
View File
@@ -25,16 +25,16 @@
</div>
<div class="auth-body">
<form id="registerForm" autocomplete="off">
<div class="form-group" id="nicknameContainer">
<label for="nickname">昵称</label>
<div class="form-group" id="nickNameContainer">
<label for="nickName">昵称</label>
<input
type="text"
id="nickname"
id="nickName"
class="form-input"
placeholder="请输入昵称(2-20个字符"
maxlength="20"
placeholder="请输入昵称(2-6个汉字或2-12个英文"
maxlength="12"
/>
<div class="error-message" id="nicknameError"></div>
<div class="error-message" id="nickNameError"></div>
</div>
<div class="form-group" id="phoneContainer">
@@ -146,10 +146,10 @@
let layerInstance = null;
let currentCaptchaId = "";
let currentVerifyType = "captcha";
let currentSlideToken = "";
let currentSlideUuid = "";
let currentSlideX = 0;
let pendingSmsAfterVerify = false;
let smsCodeIssuedPhone = "";
let referralPreviewData = null;
function showError(field, message) {
@@ -172,19 +172,27 @@
function loadVerifyConfig() {
return AuthPageUtil.loadVerifyType().then(function (type) {
currentVerifyType = type;
currentVerifyType = type === "none" ? "captcha" : type;
});
}
function refreshCaptcha() {
if (currentVerifyType === "none") {
currentCaptchaId = "";
currentSlideUuid = "";
currentSlideX = 0;
$("#captchaGroup").hide();
$("#captchaRefreshLink").hide();
return;
}
$("#captchaGroup").show();
currentCaptchaId = "";
currentSlideToken = "";
currentSlideUuid = "";
currentSlideX = 0;
$("#captchaId").val("");
$("#captchaInput").val("");
$("#captchaGroup").removeClass("is-slide-mode");
$("#sendSmsBtn").prop("disabled", currentVerifyType === "slide");
if (currentVerifyType === "slide") {
renderSlideCaptchaEntry();
return;
@@ -220,9 +228,6 @@
function completeSlideCaptcha(result) {
const data = result || {};
const nested = data.data || {};
currentSlideToken =
data.slideToken || data.token || data.verifyToken ||
nested.slideToken || nested.token || nested.verifyToken || "";
currentSlideUuid =
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
currentSlideX =
@@ -235,7 +240,7 @@
$("#captchaContainer").html(
'<div class="slide-verify-card is-success"><div class="slide-verify-mark">✓</div><div class="slide-verify-main"><div class="slide-verify-title">验证已通过</div><div class="slide-verify-desc">可以获取短信或注册</div></div><div class="slide-verify-action">完成</div></div>',
);
$("#sendSmsBtn").prop("disabled", false);
checkSmsWaitAfterVerify();
if (pendingSmsAfterVerify) {
pendingSmsAfterVerify = false;
sendSmsCode();
@@ -254,7 +259,6 @@
onSuccess: completeSlideCaptcha,
onCancel: function () {
currentSlideUuid = "";
currentSlideToken = "";
currentSlideX = 0;
},
onError: function (error) {
@@ -277,7 +281,6 @@
$("#captchaInput").hide();
$("#captchaRefreshLink").hide();
$("#captchaGroup").addClass("is-slide-mode");
$("#sendSmsBtn").prop("disabled", true);
$("#captchaContainer")
.removeAttr("onclick")
.html(
@@ -295,12 +298,19 @@
}
function validateNickname(show) {
const value = $("#nickname").val().trim();
if (value.length < 2 || value.length > 20) {
if (show) showError("nickname", "昵称长度应为2-20个字符");
const value = $("#nickName").val().trim();
if (!value) {
if (show) showError("nickName", "请输入昵称");
return false;
}
clearError("nickname");
const nicknameWidth = Array.from(value).reduce(function (total, char) {
return total + (/[\u4e00-\u9fa5\uff00-\uffef]/.test(char) ? 2 : 1);
}, 0);
if (value.length < 2 || nicknameWidth > 12) {
if (show) showError("nickName", "昵称长度应为2-6个汉字或2-12个英文");
return false;
}
clearError("nickName");
return true;
}
@@ -342,72 +352,276 @@
return true;
}
function getVerifyParams(show) {
function hasIssuedSmsCodeForCurrentPhone() {
const phone = $("#phone").val().trim();
return !!phone && smsCodeIssuedPhone === phone;
}
function handlePhoneInput() {
const phone = $("#phone").val().trim();
if (smsCodeIssuedPhone && smsCodeIssuedPhone !== phone) {
$("#smsCode").val("");
clearError("smsCode");
}
}
function validateSmsCodePhone(show) {
const phone = $("#phone").val().trim();
if (smsCodeIssuedPhone && smsCodeIssuedPhone !== phone) {
if (show) showError("smsCode", "手机号已修改,请重新获取短信验证码");
return false;
}
return true;
}
function getOptionalGraphVerifyParams() {
if (hasIssuedSmsCodeForCurrentPhone()) return {};
if (currentVerifyType === "slide" && currentSlideUuid) {
return {
verifyType: "slide",
slideUuid: currentSlideUuid,
slideX: currentSlideX,
};
}
if (currentVerifyType === "captcha") {
const code = $("#captchaInput").val().trim();
if (code && currentCaptchaId) {
return { verifyType: "captcha", code: code, uuid: currentCaptchaId };
}
}
return {};
}
function getGraphVerifyParams(show) {
if (currentVerifyType === "slide") {
if (!currentSlideUuid) {
if (show) layerInstance.msg("请先完成滑动验证", { icon: 2 });
if (show) {
layerInstance.msg("请先完成滑动验证后获取短信验证码", {
icon: 2,
});
}
return null;
}
return {
verifyType: "slide",
slideToken: currentSlideToken,
slideUuid: currentSlideUuid,
slideX: currentSlideX,
};
}
const code = $("#captchaInput").val().trim();
if (!code || !currentCaptchaId) {
if (show) showError("captcha", "请填写有效验证码");
if (!code) {
if (show) {
layerInstance.msg("请先完成图片验证码后获取短信验证码", {
icon: 2,
});
}
return null;
}
if (!currentCaptchaId) {
if (show) {
layerInstance.msg("验证码已失效,请换一张", { icon: 2 });
refreshCaptcha();
}
return null;
}
clearError("captcha");
return { verifyType: "captcha", code, uuid: currentCaptchaId };
}
function sendSmsCode() {
if (!validatePhone(true)) return;
if (currentVerifyType === "slide" && !currentSlideUuid) {
layerInstance.msg("请先完成滑动验证后获取短信验证码", { icon: 2 });
return;
}
const verifyParams = getVerifyParams(true);
if (!verifyParams) return;
$("#sendSmsBtn").prop("disabled", true);
AuthPageUtil.sendSmsCode(
Object.assign(
{ phoneNumber: $("#phone").val().trim() },
verifyParams,
),
function getSmsWaitSeconds() {
const smsCountdownApi = ApiClient.API["authSmsCountdown"];
if (!smsCountdownApi) return Promise.resolve(0);
return ApiClient.get(
smsCountdownApi,
{ phoneNumber: $("#phone").val().trim(), scene: "auth" },
{ publicRequest: true },
)
.then(function (res) {
if (ApiClient.isSuccess(res)) {
layerInstance.msg("短信验证码已发送", { icon: 1 });
AuthPageUtil.startSmsCountdown("#sendSmsBtn");
return;
}
$("#sendSmsBtn").prop("disabled", false);
layerInstance.msg((res && res.msg) || "短信验证码发送失败", {
icon: 2,
});
refreshCaptcha();
if (!ApiClient.isSuccess(res)) return 0;
const data = res.data || {};
return (
Number(
data.seconds ||
data.waitSeconds ||
data.remainingSeconds ||
data.countdown ||
0,
) || 0
);
})
.catch(function () {
$("#sendSmsBtn").prop("disabled", false);
layerInstance.msg("网络异常,短信发送失败", { icon: 2 });
refreshCaptcha();
return 0;
});
}
function checkSmsWaitAfterVerify() {
if (!validatePhone(false)) return;
getSmsWaitSeconds().then(function (waitSeconds) {
if (waitSeconds > 0) {
layerInstance.msg("请 " + waitSeconds + " 秒后再获取短信验证码", {
icon: 0,
});
AuthPageUtil.startSmsCountdown("#sendSmsBtn", waitSeconds);
}
});
}
function refreshDialogCaptcha() {
currentCaptchaId = "";
$("#captchaInput").val("");
$("#captchaId").val("");
$("#captchaDialogInput").val("");
$("#captchaDialogImage").attr("src", "");
return ApiClient.get(
ApiClient.API.authCode,
{},
{ publicRequest: true },
)
.then(function (res) {
if (ApiClient.isSuccess(res) && res.data) {
currentCaptchaId = res.data.uuid || res.data.id || "";
$("#captchaId").val(currentCaptchaId);
$("#captchaDialogImage").attr(
"src",
res.data.img || res.data.image || "",
);
return;
}
layerInstance.msg("获取验证码失败,请重试", { icon: 2 });
})
.catch(function () {
layerInstance.msg("网络错误,无法获取验证码", { icon: 2 });
});
}
function openImageCaptchaDialog() {
const dialogHtml = `
<div class="captcha-dialog">
<div class="captcha-dialog-title">完成图片验证码</div>
<div class="captcha-dialog-desc">请输入右侧图片中的验证码,通过后将自动发送短信验证码。</div>
<div class="captcha-dialog-row">
<input type="text" class="captcha-dialog-input" id="captchaDialogInput" maxlength="6" placeholder="请输入验证码" />
<div class="captcha-dialog-img-box" id="captchaDialogRefresh">
<img class="captcha-dialog-img" id="captchaDialogImage" src="" alt="验证码" />
</div>
</div>
<div class="captcha-dialog-tip">看不清?<span id="captchaDialogRefreshText">换一张</span></div>
<div class="captcha-dialog-actions">
<button type="button" class="captcha-dialog-btn" id="captchaDialogCancel">取消</button>
<button type="button" class="captcha-dialog-btn primary" id="captchaDialogConfirm">确认发送</button>
</div>
</div>
`;
const dialogIndex = layerInstance.open({
type: 1,
title: false,
area: ["420px", "auto"],
shadeClose: true,
closeBtn: 1,
content: dialogHtml,
success: function () {
refreshDialogCaptcha();
$("#captchaDialogRefresh, #captchaDialogRefreshText").on(
"click",
refreshDialogCaptcha,
);
$("#captchaDialogCancel").on("click", function () {
layerInstance.close(dialogIndex);
});
$("#captchaDialogInput").on("keydown", function (event) {
if (event.key === "Enter") {
event.preventDefault();
$("#captchaDialogConfirm").trigger("click");
}
});
$("#captchaDialogConfirm").on("click", function () {
const code = $("#captchaDialogInput").val().trim();
if (!code) {
layerInstance.msg("请输入验证码", { icon: 2 });
return;
}
$("#captchaInput").val(code);
layerInstance.close(dialogIndex);
sendSmsCode();
});
setTimeout(function () {
$("#captchaDialogInput").focus();
}, 80);
},
end: function () {
$("#sendSmsBtn").prop("disabled", false);
},
});
}
function sendSmsCode() {
if (!validatePhone(true)) return;
if (currentVerifyType === "slide" && !currentSlideUuid) {
pendingSmsAfterVerify = true;
openSlideCaptcha();
return;
}
if (
currentVerifyType === "captcha" &&
!$("#captchaInput").val().trim()
) {
$("#sendSmsBtn").prop("disabled", true);
openImageCaptchaDialog();
return;
}
const verifyParams = getGraphVerifyParams(true);
if (!verifyParams) return;
$("#sendSmsBtn").prop("disabled", true);
getSmsWaitSeconds().then(function (waitSeconds) {
if (waitSeconds > 0) {
layerInstance.msg("请 " + waitSeconds + " 秒后再获取短信验证码", {
icon: 0,
});
AuthPageUtil.startSmsCountdown("#sendSmsBtn", waitSeconds);
return;
}
AuthPageUtil.sendSmsCode(
Object.assign(
{ phoneNumber: $("#phone").val().trim() },
verifyParams,
),
)
.then(function (res) {
if (ApiClient.isSuccess(res)) {
smsCodeIssuedPhone = $("#phone").val().trim();
layerInstance.msg("短信验证码已发送", { icon: 1 });
AuthPageUtil.startSmsCountdown("#sendSmsBtn");
return;
}
$("#sendSmsBtn").prop("disabled", false);
layerInstance.msg((res && res.msg) || "短信验证码发送失败", {
icon: 2,
});
refreshCaptcha();
})
.catch(function () {
$("#sendSmsBtn").prop("disabled", false);
layerInstance.msg("网络异常,短信发送失败", { icon: 2 });
refreshCaptcha();
});
});
}
function validateForm() {
if (
!validateNickname(true) ||
!validatePhone(true) ||
!validateSmsCode(true) ||
!validateSmsCodePhone(true) ||
!validatePassword(true) ||
!validateConfirmPassword(true)
)
return false;
if (!getVerifyParams(true)) return false;
if (!$("#agreementCheckbox").prop("checked")) {
layerInstance.msg("请阅读并同意用户协议和隐私政策", { icon: 2 });
return false;
@@ -417,8 +631,6 @@
function buildRegisterData() {
const params = new URLSearchParams(window.location.search);
const inviteCode =
params.get("inviteCode") || params.get("referralCode") || "";
const referrerId =
(referralPreviewData &&
(referralPreviewData.referrerId ||
@@ -427,46 +639,58 @@
params.get("referrerId") ||
params.get("pid") ||
0;
const invitePayload = inviteCode ? { inviteCode: inviteCode } : {};
return Object.assign(
{
phoneNumber: $("#phone").val().trim(),
password: hex_md5($("#password").val()),
smsCode: $("#smsCode").val().trim(),
nickname: $("#nickname").val().trim(),
nickName: $("#nickName").val().trim(),
referrerId: referrerId,
},
invitePayload,
getVerifyParams(false) || {},
getOptionalGraphVerifyParams(),
);
}
function loadReferralBindPreview() {
function getInviteCodeFromQuery() {
const params = new URLSearchParams(window.location.search);
const inviteCode =
params.get("inviteCode") || params.get("referralCode") || "";
if (!inviteCode) return;
ApiClient.get(
return params.get("inviteCode") || params.get("referralCode") || "";
}
function loadReferralBindPreview() {
const inviteCode = getInviteCodeFromQuery();
if (!inviteCode) return Promise.resolve();
return ApiClient.get(
ApiClient.API.referralBindPreview,
{ inviteCode: inviteCode },
{ publicRequest: true },
)
.then(function (res) {
if (!ApiClient.isSuccess(res)) return;
if (!ApiClient.isSuccess(res)) {
throw new Error((res && res.msg) || "推荐人信息无效");
}
referralPreviewData = ApiClient.pickData(res, {}) || {};
const name =
referralPreviewData.nickname ||
referralPreviewData.nickName ||
referralPreviewData.nickname ||
referralPreviewData.userName ||
referralPreviewData.phoneNumber ||
"";
if (name)
if (name) {
layerInstance.msg("已识别推荐人:" + name, {
icon: 1,
time: 1500,
});
}
})
.catch(function () {
.catch(function (error) {
referralPreviewData = null;
layerInstance.msg(
(error && error.message) || "推荐人信息无效",
{ icon: 2 },
);
});
}
@@ -509,12 +733,14 @@
event.preventDefault();
if (validateForm()) register();
});
$("#nickname").on("blur", function () {
$("#nickName").on("blur", function () {
validateNickname(true);
});
$("#phone").on("blur", function () {
validatePhone(true);
});
$("#phone")
.on("input", handlePhoneInput)
.on("blur", function () {
validatePhone(true);
});
$("#smsCode").on("blur", function () {
validateSmsCode(true);
});
+141 -15
View File
@@ -127,10 +127,10 @@
let layerInstance = null;
let currentCaptchaId = "";
let currentVerifyType = "captcha";
let currentSlideToken = "";
let currentSlideUuid = "";
let currentSlideX = 0;
let pendingSmsAfterVerify = false;
let smsCodeIssuedPhone = "";
function showError(field, message) {
const containerId =
@@ -158,13 +158,12 @@
function refreshCaptcha() {
currentCaptchaId = "";
currentSlideToken = "";
currentSlideUuid = "";
currentSlideX = 0;
$("#captchaId").val("");
$("#captchaInput").val("");
$("#captchaGroup").removeClass("is-slide-mode");
$("#sendSmsBtn").prop("disabled", currentVerifyType === "slide");
$("#sendSmsBtn").prop("disabled", false);
if (currentVerifyType === "slide") {
renderSlideCaptchaEntry();
return;
@@ -200,9 +199,6 @@
function completeSlideCaptcha(result) {
const data = result || {};
const nested = data.data || {};
currentSlideToken =
data.slideToken || data.token || data.verifyToken ||
nested.slideToken || nested.token || nested.verifyToken || "";
currentSlideUuid =
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
currentSlideX =
@@ -234,7 +230,6 @@
onSuccess: completeSlideCaptcha,
onCancel: function () {
currentSlideUuid = "";
currentSlideToken = "";
currentSlideX = 0;
},
onError: function (error) {
@@ -257,7 +252,7 @@
$("#captchaInput").hide();
$("#captchaRefreshLink").hide();
$("#captchaGroup").addClass("is-slide-mode");
$("#sendSmsBtn").prop("disabled", true);
$("#sendSmsBtn").prop("disabled", false);
$("#captchaContainer")
.removeAttr("onclick")
.html(
@@ -294,6 +289,29 @@
return true;
}
function hasIssuedSmsCodeForCurrentPhone() {
const phone = $("#phone").val().trim();
return !!phone && smsCodeIssuedPhone === phone;
}
function handlePhoneInput() {
const phone = $("#phone").val().trim();
if (smsCodeIssuedPhone && smsCodeIssuedPhone !== phone) {
smsCodeIssuedPhone = "";
$("#smsCode").val("");
}
}
function validateSmsCodePhone(show) {
if (!validateSmsCode(show)) return false;
if (!hasIssuedSmsCodeForCurrentPhone()) {
if (show) showError("smsCode", "请先获取当前手机号的短信验证码");
return false;
}
clearError("smsCode");
return true;
}
function validatePassword(show) {
if (!AuthPageUtil.isPassword($("#password").val())) {
if (show) showError("password", "密码长度应为6-20位");
@@ -320,7 +338,6 @@
}
return {
verifyType: "slide",
slideToken: currentSlideToken,
slideUuid: currentSlideUuid,
slideX: currentSlideX,
};
@@ -334,23 +351,131 @@
return { verifyType: "captcha", code, uuid: currentCaptchaId };
}
function getSmsWaitSeconds() {
const smsCountdownApi = ApiClient.API["authSmsCountdown"];
if (!smsCountdownApi) return Promise.resolve(0);
return ApiClient.get(
smsCountdownApi,
{ phoneNumber: $("#phone").val().trim(), scene: "auth" },
{ publicRequest: true },
)
.then(function (res) {
if (!ApiClient.isSuccess(res)) return 0;
const data = res.data || {};
return Number(data.seconds || data.waitSeconds || data.remainingSeconds || data.countdown || 0) || 0;
})
.catch(function () {
return 0;
});
}
function refreshDialogCaptcha() {
currentCaptchaId = "";
$("#captchaInput").val("");
$("#captchaId").val("");
$("#captchaDialogInput").val("");
$("#captchaDialogImage").attr("src", "");
return ApiClient.get(ApiClient.API.authCode, {}, { publicRequest: true })
.then(function (res) {
if (ApiClient.isSuccess(res) && res.data) {
currentCaptchaId = res.data.uuid || res.data.id || "";
$("#captchaId").val(currentCaptchaId);
$("#captchaDialogImage").attr("src", res.data.img || res.data.image || "");
return;
}
layerInstance.msg("获取验证码失败,请重试", { icon: 2 });
})
.catch(function () {
layerInstance.msg("网络错误,无法获取验证码", { icon: 2 });
});
}
function openImageCaptchaDialog() {
const dialogHtml =
'<div class="captcha-dialog">' +
'<div class="captcha-dialog-title">完成图片验证码</div>' +
'<div class="captcha-dialog-desc">请输入右侧图片中的验证码,通过后将自动发送短信验证码。</div>' +
'<div class="captcha-dialog-row">' +
'<input type="text" class="captcha-dialog-input" id="captchaDialogInput" maxlength="6" placeholder="请输入验证码" />' +
'<div class="captcha-dialog-img-box" id="captchaDialogRefresh">' +
'<img class="captcha-dialog-img" id="captchaDialogImage" src="" alt="验证码" />' +
'</div></div>' +
'<div class="captcha-dialog-tip">看不清?<span id="captchaDialogRefreshText">换一张</span></div>' +
'<div class="captcha-dialog-actions">' +
'<button type="button" class="captcha-dialog-btn" id="captchaDialogCancel">取消</button>' +
'<button type="button" class="captcha-dialog-btn primary" id="captchaDialogConfirm">确认发送</button>' +
'</div></div>';
const dialogIndex = layerInstance.open({
type: 1,
title: false,
area: ["420px", "auto"],
shadeClose: true,
closeBtn: 1,
content: dialogHtml,
success: function () {
refreshDialogCaptcha();
$("#captchaDialogRefresh, #captchaDialogRefreshText").on("click", refreshDialogCaptcha);
$("#captchaDialogCancel").on("click", function () {
layerInstance.close(dialogIndex);
});
$("#captchaDialogInput").on("keydown", function (event) {
if (event.key === "Enter") {
event.preventDefault();
$("#captchaDialogConfirm").trigger("click");
}
});
$("#captchaDialogConfirm").on("click", function () {
const code = $("#captchaDialogInput").val().trim();
if (!code) {
layerInstance.msg("请输入验证码", { icon: 2 });
return;
}
$("#captchaInput").val(code);
layerInstance.close(dialogIndex);
sendSmsCode();
});
setTimeout(function () {
$("#captchaDialogInput").focus();
}, 80);
},
end: function () {
$("#sendSmsBtn").prop("disabled", false);
},
});
}
function sendSmsCode() {
if (!validatePhone(true)) return;
if (currentVerifyType === "slide" && !currentSlideUuid) {
layerInstance.msg("请先完成滑动验证后获取短信验证码", { icon: 2 });
pendingSmsAfterVerify = true;
openSlideCaptcha();
return;
}
if (currentVerifyType === "captcha" && !$("#captchaInput").val().trim()) {
$("#sendSmsBtn").prop("disabled", true);
openImageCaptchaDialog();
return;
}
const verifyParams = getVerifyParams(true);
if (!verifyParams) return;
$("#sendSmsBtn").prop("disabled", true);
AuthPageUtil.sendForgotPasswordSmsCode(
getSmsWaitSeconds().then(function (waitSeconds) {
if (waitSeconds > 0) {
layerInstance.msg("请 " + waitSeconds + " 秒后再获取短信验证码", { icon: 0 });
AuthPageUtil.startSmsCountdown("#sendSmsBtn", waitSeconds);
throw new Error("__SMS_WAIT__");
}
return AuthPageUtil.sendForgotPasswordSmsCode(
Object.assign(
{ phoneNumber: $("#phone").val().trim() },
verifyParams,
),
)
);
})
.then(function (res) {
if (ApiClient.isSuccess(res)) {
smsCodeIssuedPhone = $("#phone").val().trim();
layerInstance.msg("短信验证码已发送", { icon: 1 });
AuthPageUtil.startSmsCountdown("#sendSmsBtn");
return;
@@ -361,7 +486,8 @@
});
refreshCaptcha();
})
.catch(function () {
.catch(function (error) {
if (error && error.message === "__SMS_WAIT__") return;
$("#sendSmsBtn").prop("disabled", false);
layerInstance.msg("网络异常,短信发送失败", { icon: 2 });
refreshCaptcha();
@@ -371,7 +497,7 @@
function validateForm() {
if (
!validatePhone(true) ||
!validateSmsCode(true) ||
!validateSmsCodePhone(true) ||
!validatePassword(true) ||
!validateConfirmPassword(true)
)
@@ -433,7 +559,7 @@
event.preventDefault();
if (validateForm()) submitResetPassword();
});
$("#phone").on("blur", function () {
$("#phone").on("input", handlePhoneInput).on("blur", function () {
validatePhone(true);
});
$("#smsCode").on("blur", function () {
+3 -222
View File
@@ -3,235 +3,16 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3D研究室 - 微信登录</title>
<title>彩先知 - 微信登录</title>
<script src="../config.js"></script>
<script src="../utils/ApiClient.js"></script>
<script src="../utils/AuthPageUtil.js"></script>
<style>
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
color: #1f2933;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei",
sans-serif;
background:
radial-gradient(circle at 72% 18%, rgba(255, 190, 98, 0.45), rgba(255, 190, 98, 0) 32%),
linear-gradient(135deg, #ff7a1a 0%, #ff6f12 54%, #ff8a23 100%);
}
.page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 16px;
}
.card {
width: 420px;
max-width: 100%;
padding: 28px 30px 30px;
border-radius: 10px;
background: #ffffff;
box-shadow: 0 18px 48px rgba(124, 38, 4, 0.18);
}
.brand {
margin-bottom: 20px;
color: #de2103;
font-size: 28px;
font-weight: 800;
text-align: center;
}
.title {
margin-bottom: 8px;
font-size: 18px;
font-weight: 700;
text-align: center;
}
.desc {
min-height: 22px;
margin-bottom: 18px;
color: #667085;
font-size: 13px;
line-height: 22px;
text-align: center;
}
.status {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin: 14px 0 20px;
color: #de2103;
font-size: 14px;
}
.spinner {
width: 18px;
height: 18px;
border: 2px solid #f5c7bd;
border-top-color: #de2103;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.bind-form {
display: none;
}
.form-row {
margin-top: 14px;
}
.form-row label {
display: block;
margin-bottom: 6px;
color: #344054;
font-size: 13px;
font-weight: 600;
}
.input,
.sms-input {
width: 100%;
height: 42px;
padding: 0 12px;
border: 1px solid #d9dee7;
border-radius: 5px;
color: #1f2933;
font-size: 14px;
outline: none;
}
.input:focus,
.sms-input:focus {
border-color: #de2103;
box-shadow: 0 0 0 3px rgba(222, 33, 3, 0.08);
}
.sms-row {
display: flex;
gap: 10px;
}
.captcha-row {
display: none;
}
.captcha-box {
display: flex;
gap: 10px;
}
.captcha-box .input {
flex: 1;
min-width: 0;
}
.captcha-image {
flex: 0 0 108px;
height: 42px;
border: 1px solid #d9dee7;
border-radius: 5px;
background: #f8fafc;
cursor: pointer;
object-fit: cover;
}
.sms-input {
flex: 1;
min-width: 0;
}
.sms-button {
flex: 0 0 108px;
height: 42px;
border: 1px solid #de2103;
border-radius: 5px;
background: #fff8f6;
color: #de2103;
cursor: pointer;
}
.sms-button:disabled,
.submit:disabled {
cursor: not-allowed;
opacity: 0.65;
}
.submit {
width: 100%;
height: 42px;
margin-top: 20px;
border: 0;
border-radius: 5px;
background: linear-gradient(180deg, #ff4a22 0%, #de2103 100%);
color: #ffffff;
font-size: 14px;
font-weight: 700;
cursor: pointer;
}
.tips {
margin-top: 12px;
padding: 10px 12px;
border: 1px solid #f2d2ca;
border-radius: 5px;
background: #fff8f6;
color: #8a4b42;
font-size: 12px;
line-height: 20px;
}
.error {
display: none;
margin-top: 14px;
padding: 10px 12px;
border: 1px solid #f4c7c7;
border-radius: 5px;
background: #fff5f5;
color: #b42318;
font-size: 13px;
line-height: 20px;
}
.actions {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 16px;
}
.actions a,
.actions button {
border: 0;
background: transparent;
color: #de2103;
font-size: 13px;
text-decoration: none;
cursor: pointer;
}
</style>
<link rel="stylesheet" href="../public/css/social-callback.css" />
</head>
<body>
<div class="page">
<div class="card">
<div class="brand">3D研究室</div>
<div class="brand">彩先知</div>
<div class="title" id="title">微信登录</div>
<div class="desc" id="desc">正在处理微信授权,请稍候...</div>
<div class="status" id="status">
+128 -22
View File
@@ -59,6 +59,7 @@
</div>
<div class="tl-filter-bar">
<div class="tl-flow-tabs" id="walletFlowTabs"></div>
<div class="tl-filter-group">
<span>状态</span>
<div class="tl-segment" id="statusFilters"></div>
@@ -137,6 +138,17 @@
{ value: "sales", label: "销售余额" },
{ value: "expert", label: "专家余额" },
];
const flowTypeOptions = [
{ value: "withdraw", label: "\u63d0\u73b0\u7533\u8bf7", desc: "\u63d0\u73b0\u5230\u6536\u6b3e\u8d26\u6237" },
{ value: "recharge", label: "\u8d26\u6237\u5145\u503c", desc: "\u8d26\u6237\u4f59\u989d\u5145\u503c" },
{ value: "purchase", label: "\u6587\u7ae0\u8d2d\u4e70", desc: "\u8d2d\u4e70\u6587\u7ae0\u652f\u51fa" },
{ value: "sales", label: "\u9080\u8bf7\u8fd4\u5229", desc: "\u5206\u9500\u8fd4\u5229\u6536\u5165" },
{ value: "expert", label: "\u4e13\u5bb6\u4f63\u91d1", desc: "\u4e13\u5bb6\u6536\u76ca\u6536\u5165" },
];
const flowTypeMap = flowTypeOptions.reduce(function (map, item) {
map[item.value] = item;
return map;
}, {});
const statusTextMap = {
0: "审核中",
1: "成功",
@@ -160,6 +172,8 @@
const sourceTextMap = {
sales: "销售余额",
expert: "专家余额",
account: "\u8d26\u6237\u4f59\u989d",
balance: "\u8d26\u6237\u4f59\u989d",
};
const methodTextMap = {
alipay: "支付宝",
@@ -168,12 +182,15 @@
bank: "银行卡",
bank_card: "银行卡",
};
const incomeFlowTypes = new Set(["recharge", "sales", "expert"]);
const outcomeFlowTypes = new Set(["withdraw", "purchase"]);
let currentPage = 1;
let pageSize = 10;
let totalRow = 0;
let currentStatus = "";
let currentSource = "";
let currentFlowType = "withdraw";
function logout() {
localStorage.removeItem("token");
@@ -249,19 +266,40 @@
}
function renderFilters() {
renderFlowTabs();
$(".tl-filter-group").toggle(currentFlowType === "withdraw");
renderSegment("#statusFilters", statusOptions, currentStatus, function (value) {
currentStatus = value;
currentPage = 1;
loadWithdrawList();
loadWalletFlowList();
});
renderSegment("#sourceFilters", sourceOptions, currentSource, function (value) {
currentSource = value;
currentPage = 1;
loadWithdrawList();
loadWalletFlowList();
});
updateFilterSummary();
}
function renderFlowTabs() {
const $wrap = $("#walletFlowTabs").empty();
$.each(flowTypeOptions, function (_, item) {
const $button = $('<button class="tl-flow-tab" type="button"></button>');
$button.attr("data-type", item.value);
$button.html("<span>" + escapeHtml(item.label) + "</span><em>" + escapeHtml(item.desc) + "</em>");
$button.toggleClass("active", item.value === currentFlowType);
$button.on("click", function () {
currentFlowType = item.value;
currentPage = 1;
currentStatus = "";
currentSource = "";
renderFilters();
loadWalletFlowList();
});
$wrap.append($button);
});
}
function renderSegment(selector, options, selectedValue, onChange) {
const $wrap = $(selector).empty();
$.each(options, function (_, item) {
@@ -277,6 +315,10 @@
}
function updateFilterSummary() {
if (currentFlowType !== "withdraw") {
$("#filterSummary").text((flowTypeMap[currentFlowType] && flowTypeMap[currentFlowType].label) || "\u8d44\u91d1\u6d41\u6c34");
return;
}
const statusLabel = statusOptions.find((item) => item.value === currentStatus)?.label || "全部";
const sourceLabel = sourceOptions.find((item) => item.value === currentSource)?.label || "全部";
$("#filterSummary").text(statusLabel + "状态 / " + sourceLabel + "来源");
@@ -299,7 +341,7 @@
}
function getStatus(item) {
return fieldValue(item, ["status", "withdrawStatus", "auditStatus"]);
return item.status ?? item.withdrawStatus ?? item.auditStatus ?? item.flowStatus ?? item.payStatus ?? "";
}
function getStatusText(item) {
@@ -314,7 +356,7 @@
function getSourceText(item) {
const source = fieldValue(item, ["sourceWallet", "walletType"]);
return fieldValue(item, ["sourceWalletText", "walletTypeText"]) || sourceTextMap[source] || source || "--";
return fieldValue(item, ["sourceWalletText", "walletTypeText", "flowTypeText", "typeText"]) || sourceTextMap[source] || source || getFlowTypeText(item);
}
function getMethodText(item) {
@@ -334,22 +376,69 @@
}
function getCreateTime(item) {
const time = fieldValue(item, ["createTime", "createdTime", "applyTime", "submitTime", "updateTime"]);
const time = fieldValue(item, ["createTime", "createdTime", "applyTime", "submitTime", "payTime", "updateTime"]);
return DateUtil.formatDateTimeToYMDHM(time) || time || "--";
}
function loadWithdrawList() {
function getFlowTypeText(item) {
const flowType = fieldValue(item, ["flowType", "type"]) || currentFlowType;
return fieldValue(item, ["flowTypeText", "typeText"]) || (flowTypeMap[flowType] && flowTypeMap[flowType].label) || flowType || "\u8d44\u91d1\u6d41\u6c34";
}
function getRecordSourceText(item) {
const source = fieldValue(item, ["withdrawType", "receiveType", "walletType", "paymentType", "sourceWallet"]);
return (
fieldValue(item, ["withdrawTypeText", "receiveTypeText", "walletTypeText", "paymentTypeText", "sourceWalletText", "remark", "description"]) ||
methodTextMap[source] ||
sourceTextMap[source] ||
source ||
"--"
);
}
function getDisplayAmount(item) {
const amount = getAmount(item);
const flowType = fieldValue(item, ["flowType", "type"]) || currentFlowType;
const isIncome = amount > 0 || (amount === Math.abs(amount) && incomeFlowTypes.has(flowType));
const isOutcome = amount < 0 || outcomeFlowTypes.has(flowType);
const sign = isIncome && !isOutcome ? "+" : isOutcome ? "-" : "";
return {
text: sign + money(Math.abs(amount)) + " \u5143",
className: isIncome && !isOutcome ? "income" : isOutcome ? "outcome" : "neutral",
};
}
function renderTableHeader() {
const $header = $("#withdrawTable thead tr").empty();
const columns =
currentFlowType === "withdraw"
? ["\u7533\u8bf7\u5355\u53f7", "\u63d0\u73b0\u6765\u6e90", "\u63d0\u73b0\u65b9\u5f0f", "\u91d1\u989d", "\u6536\u6b3e\u8d26\u6237", "\u72b6\u6001", "\u7533\u8bf7\u65f6\u95f4"]
: ["\u6d41\u6c34\u53f7", "\u7c7b\u578b", "\u91d1\u989d", "\u65b9\u5f0f/\u6765\u6e90", "\u72b6\u6001", "\u65f6\u95f4"];
$.each(columns, function (_, title) {
$header.append("<th>" + escapeHtml(title) + "</th>");
});
}
function isWithdrawRecordType() {
return currentFlowType === "withdraw";
}
function loadWalletFlowList() {
const params = {
pageNum: currentPage,
pageSize: pageSize,
};
if (currentStatus) params.status = currentStatus;
if (currentSource) params.sourceWallet = currentSource;
if (isWithdrawRecordType()) {
if (currentStatus) params.status = currentStatus;
if (currentSource) params.sourceWallet = currentSource;
} else {
params.flowType = currentFlowType;
}
$("#withdrawTable").addClass("loading");
ApiClient.get(ApiClient.API.walletWithdrawList, params)
ApiClient.get(isWithdrawRecordType() ? ApiClient.API.walletWithdrawList : ApiClient.API.walletFlowList, params)
.then(function (res) {
if (!isSuccess(res)) throw new Error(res.msg || "获取提现记录失败");
if (!isSuccess(res)) throw new Error(res.msg || "获取记录失败");
const data = pickData(res) || res || {};
const records = getRecords(data, res);
totalRow = getTotal(data, records, res);
@@ -357,7 +446,7 @@
renderPagination();
})
.catch(function (err) {
layui.layer.msg(err.message || "获取提现记录失败", { icon: 2 });
layui.layer.msg(err.message || "获取记录失败", { icon: 2 });
totalRow = 0;
renderTable([]);
renderPagination();
@@ -370,9 +459,12 @@
function renderTable(records) {
const $tbody = $("#withdrawTable tbody").empty();
let pageAmount = 0;
renderTableHeader();
if (!records.length) {
$("#withdrawTable").addClass("tl-table-hidden");
$("#emptyState").addClass("show");
$("#emptyState .tl-empty-title").text("\u6682\u65e0\u8bb0\u5f55");
$("#emptyState .tl-empty-desc").text(((flowTypeMap[currentFlowType] && flowTypeMap[currentFlowType].label) || "\u5f53\u524d\u7c7b\u578b") + "\u6682\u65e0\u8d44\u91d1\u6d41\u6c34");
$(".tl-summary").addClass("is-hidden");
} else {
$("#withdrawTable").removeClass("tl-table-hidden");
@@ -384,15 +476,27 @@
const amount = getAmount(item);
pageAmount += Math.abs(amount);
const $row = $("<tr></tr>");
$row.html(
"<td>" + escapeHtml(getRecordNo(item)) + "</td>" +
"<td>" + escapeHtml(getSourceText(item)) + "</td>" +
"<td>" + escapeHtml(getMethodText(item)) + "</td>" +
'<td class="tl-amount">-' + escapeHtml(money(Math.abs(amount))) + "</td>" +
"<td>" + escapeHtml(getReceiveAccountText(item)) + "</td>" +
'<td><span class="tl-status ' + getStatusClass(item) + '">' + escapeHtml(getStatusText(item)) + "</span></td>" +
"<td>" + escapeHtml(getCreateTime(item)) + "</td>",
);
if (isWithdrawRecordType()) {
$row.html(
"<td>" + escapeHtml(getRecordNo(item)) + "</td>" +
"<td>" + escapeHtml(getSourceText(item)) + "</td>" +
"<td>" + escapeHtml(getMethodText(item)) + "</td>" +
'<td class="tl-amount outcome">-' + escapeHtml(money(Math.abs(amount))) + " \u5143</td>" +
"<td>" + escapeHtml(getReceiveAccountText(item)) + "</td>" +
'<td><span class="tl-status ' + getStatusClass(item) + '">' + escapeHtml(getStatusText(item)) + "</span></td>" +
"<td>" + escapeHtml(getCreateTime(item)) + "</td>",
);
} else {
const amountInfo = getDisplayAmount(item);
$row.html(
"<td>" + escapeHtml(getRecordNo(item)) + "</td>" +
"<td>" + escapeHtml(getFlowTypeText(item)) + "</td>" +
'<td class="tl-amount ' + amountInfo.className + '">' + escapeHtml(amountInfo.text) + "</td>" +
"<td>" + escapeHtml(getRecordSourceText(item)) + "</td>" +
'<td><span class="tl-status ' + getStatusClass(item) + '">' + escapeHtml(getStatusText(item)) + "</span></td>" +
"<td>" + escapeHtml(getCreateTime(item)) + "</td>",
);
}
$tbody.append($row);
});
@@ -417,7 +521,7 @@
jump: function (obj, first) {
if (first) return;
currentPage = obj.curr;
loadWithdrawList();
loadWalletFlowList();
},
});
});
@@ -427,6 +531,8 @@
const query = new URLSearchParams(window.location.search);
const status = query.get("status") || "";
const sourceWallet = query.get("sourceWallet") || "";
const flowType = query.get("flowType") || "";
if (flowTypeMap[flowType]) currentFlowType = flowType;
if (statusOptions.some((item) => item.value === status)) currentStatus = status;
if (sourceOptions.some((item) => item.value === sourceWallet)) currentSource = sourceWallet;
}
@@ -442,7 +548,7 @@
renderFilters();
CommonUtil.loadPageConfig({ ads: false, links: false });
CommonUtil.requireAuth(function () {
loadWithdrawList();
loadWalletFlowList();
});
});
</script>
+2 -2
View File
@@ -185,7 +185,7 @@
function loadAgreementDetail() {
var $contentEl = $("#articleContent");
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">加载中...</p>');
ApiClient.post("/api/web/agreement/getByType?type=2").then(function (res) {
ApiClient.get(ApiClient.API.agreement(2)).then(function (res) {
if (res.code === 0 && res.data) {
var article = res.data;
if (article.title) {
@@ -254,4 +254,4 @@
});
</script>
</body>
</html>
</html>
+2 -2
View File
@@ -229,7 +229,7 @@
function loadAgreementDetail() {
var $contentEl = $("#articleContent");
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">加载中...</p>');
ApiClient.post("/api/web/agreement/getByType?type=1").then(function (res) {
ApiClient.get(ApiClient.API.agreement(1)).then(function (res) {
if (res.code === 0 && res.data) {
var article = res.data;
if (article.title) {
@@ -298,4 +298,4 @@
});
</script>
</body>
</html>
</html>