修改功能,现已测试注册登录忘记密码
This commit is contained in:
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user