Files
shencaisuan/html/usercenter.html
T
2026-06-12 21:36:58 +08:00

1587 lines
52 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title id="page-title">神彩算 - 用户中心</title>
<script src="../public/css/layui/layui.js"></script>
<script src="../config.js"></script>
<script src="../utils/ApiClient.js"></script>
<script src="../utils/DateUtil.js"></script>
<script src="../utils/CommonUtil.js"></script>
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
<link rel="stylesheet" href="../public/css/public.css" />
<link rel="stylesheet" href="../public/css/usercenter.css" />
<link rel="stylesheet" href="../public/css/usercenter-signin.css" />
</head>
<body>
<!-- Header -->
<nav class="topbar" id="navbar">
<div class="topbar__inner">
<a href="index.html" class="topbar__brand">
<img
src="../images/home-logo.png"
alt="神彩算"
class="topbar__logo"
/>
</a>
<div class="topbar__nav" id="navLotteryItems">
<!-- <a href="index.html" class="topbar__nav-link">首页</a> -->
</div>
<div class="topbar__user">
<div id="notLoggedInBox" class="topbar__guest">
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
<a href="reg.html" class="topbar__btn topbar__btn--primary"
>免费注册</a
>
</div>
<div id="loggedInBox" class="topbar__logged" style="display: none">
<a href="usercenter.html" class="topbar__profile">
<img
id="headerAvatar"
src="../public/img/userimg.png"
alt=""
class="topbar__avatar"
/>
<div class="topbar__meta">
<span id="headerUserName" class="topbar__uname">用户</span>
<span id="headerUserLevel" class="topbar__ubadge">会员</span>
</div>
</a>
<button
class="topbar__btn topbar__btn--logout"
onclick="handleLogout()"
>
退出登录
</button>
</div>
</div>
</div>
</nav>
<!-- ====== Main Content ====== -->
<div class="uc-container">
<!-- Profile Card -->
<div class="uc-profile-card">
<div class="uc-avatar-wrap">
<img
id="userAvatar"
class="uc-avatar"
src="../public/img/userimg.png"
alt="头像"
onclick="openEditProfile()"
/>
</div>
<div class="uc-info">
<div class="uc-nickname" id="userNickName">未登录</div>
<div class="uc-level" id="userLevel">普通会员</div>
<div class="uc-phone" id="userPhone"></div>
<div class="wechatBindCard" id="wechat-bind-card">
<div class="wechatBindTop">
<div class="wechatBindIconBox">
<img class="wechatBindIcon" src="../public/img/pay-wechat.png" alt="微信" />
</div>
<div class="wechatBindInfo">
<div class="wechatBindTitle">微信账号</div>
<div class="wechatBindDesc" id="wechat-bind-desc">检测中...</div>
</div>
<div class="wechatBindStateDot"></div>
</div>
<button
type="button"
class="wechatBindButton"
id="wechat-bind-button"
onclick="openWeChatBindPopup()"
>
绑定微信
</button>
</div>
</div>
<div class="uc-actions">
<button
class="uc-btn uc-btn-signin"
id="signInBtn"
onclick="handleSignIn()"
>
每日签到
</button>
<button class="uc-btn uc-btn-edit" onclick="openEditProfile()">
编辑资料
</button>
<button
class="uc-btn uc-btn-expert"
id="expertApplyBtn"
onclick="window.location.href = 'apply.html'"
>
专家申请
</button>
<button
class="uc-btn uc-btn-publish"
id="publishArticleBtn"
onclick="window.location.href = 'fabumianfeiwenzhang.html'"
>
发布文章
</button>
<button
class="uc-btn uc-btn-collection"
onclick="window.location.href = 'mianfeishoucang.html?tab=free'"
>
我的收藏
</button>
<button
class="uc-btn uc-btn-tuiguang"
onclick="window.location.href = 'tuiguang.html'"
>
分享推广
</button>
<button class="uc-btn uc-btn-logout2" onclick="handleLogout()">
退出登录
</button>
</div>
</div>
<div class="wechatBindCard" id="wechat-bind-card">
<div class="wechatBindTop">
<div class="wechatBindIconBox">
<img class="wechatBindIcon" src="../public/img/pay-wechat.png" alt="微信" />
</div>
<div class="wechatBindInfo">
<div class="wechatBindTitle">微信账号</div>
<div class="wechatBindDesc" id="wechat-bind-desc">正在检测绑定状态...</div>
</div>
<div class="wechatBindStateDot"></div>
</div>
<div class="wechatBindLine"></div>
<button
type="button"
class="wechatBindButton"
id="wechat-bind-button"
onclick="openWeChatBindPopup()"
>
绑定微信
</button>
</div>
<!-- Balance Cards -->
<div class="uc-balance-grid">
<div class="uc-balance-item">
<div class="uc-balance-label">
<span
class="balance-icon"
style="background: var(--gold); color: var(--primary)"
>P</span
>
积分
</div>
<div class="uc-balance-value" id="userPoints">0<span></span></div>
<div class="uc-balance-links">
<a href="jine.html?type=POINTS">明细</a>
</div>
</div>
<div class="uc-balance-item">
<div class="uc-balance-label">
<span class="balance-icon" style="background: var(--primary)"
>B</span
>
余额
</div>
<div class="uc-balance-value" id="userBalance">0<span></span></div>
<div class="uc-balance-links">
<a href="jine.html?type=BALANCE">明细</a
><a href="chongzhi.html">充值</a><a href="tixian.html">提现</a>
</div>
</div>
<div class="uc-balance-item">
<div class="uc-balance-label">
<span class="balance-icon" style="background: var(--orange)"
>S</span
>
销售余额
</div>
<div class="uc-balance-value" id="userSalesBalance">
0<span></span>
</div>
<div class="uc-balance-links">
<a href="jine.html?type=SALES_BALANCE">明细</a>
</div>
</div>
<div class="uc-balance-item">
<div class="uc-balance-label">
<span class="balance-icon" style="background: var(--purple)"
>E</span
>
专家余额
</div>
<div class="uc-balance-value" id="userExpertBalance">
0<span></span>
</div>
<div class="uc-balance-links">
<a href="jine.html?type=EXPERT_BALANCE">明细</a
><a href="tixian.html">提现</a>
</div>
</div>
</div>
<!-- Sign-in Records -->
<div class="uc-section">
<div class="uc-section-header">
<div class="uc-section-title">签到记录</div>
</div>
<table class="uc-table">
<thead>
<tr>
<th>日期</th>
<th>类型</th>
<th>积分变化</th>
<th>说明</th>
</tr>
</thead>
<tbody id="signInTableBody">
<tr>
<td
colspan="4"
style="
text-align: center;
color: var(--text-muted);
padding: 30px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="uc-pagination" id="signInPager"></div>
</div>
<!-- Free Article Section -->
<div class="uc-section">
<div class="uc-section-header">
<div class="uc-section-title">我的免费文章</div>
</div>
<div class="uc-filter-bar">
<label>彩种:</label>
<select id="filterLottery"></select>
<button class="uc-filter-btn" onclick="loadFreeArticles(1)">
筛选
</button>
</div>
<table class="uc-table">
<thead>
<tr>
<th>标题</th>
<th>彩种</th>
<th>方案</th>
<th>类型</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="articleTableBody">
<tr>
<td
colspan="6"
style="
text-align: center;
color: var(--text-muted);
padding: 30px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="uc-pagination" id="articlePager"></div>
</div>
<!-- Paid Article Section -->
<div class="uc-section">
<div class="uc-section-header">
<div class="uc-section-title">我的付费文章</div>
</div>
<div class="uc-filter-bar">
<label>彩种:</label>
<select
id="paidFilterLottery"
onchange="onPaidLotteryChange()"
></select>
<label>方案:</label>
<select id="paidFilterPlan" onchange="onPaidPlanChange()">
<option value="">请选择方案</option>
</select>
<label>类型:</label>
<select id="paidFilterType">
<option value="">请选择类型</option>
</select>
<button class="uc-filter-btn" onclick="loadPaidArticles(1)">
筛选
</button>
</div>
<table class="uc-table">
<thead>
<tr>
<th>标题</th>
<th>彩种</th>
<th>价格</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="paidArticleTableBody">
<tr>
<td
colspan="5"
style="
text-align: center;
color: var(--text-muted);
padding: 30px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="uc-pagination" id="paidArticlePager"></div>
</div>
<!-- Purchase Records Section -->
<div class="uc-section">
<div class="uc-section-header">
<div class="uc-section-title">我的购买记录</div>
</div>
<table class="uc-table">
<thead>
<tr>
<th>类型</th>
<th>商品名称</th>
<th>期号</th>
<th>专家</th>
<th>购买时间</th>
<th>金额</th>
<th>操作</th>
</tr>
</thead>
<tbody id="purchaseTableBody">
<tr>
<td
colspan="7"
style="
text-align: center;
color: var(--text-muted);
padding: 30px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="uc-pagination" id="purchasePager"></div>
</div>
</div>
<!-- Footer -->
<footer class="site-footer">
<div class="site-footer__inner">
<img
src="../images/home-logo.png"
alt="神彩算"
class="site-footer__logo"
/>
<p id="copyright-info">神彩算以开奖数据、免费文章、资讯推荐为核心</p>
<div class="site-footer__meta">
<a
id="beian"
href="https://beian.miit.gov.cn/"
target="_blank"
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
>工信部备案号</a
>
<span id="additional-info">本站仅供数据分析参考</span>
</div>
</div>
</footer>
<button
class="gotop"
id="backTop"
type="button"
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
>
</button>
<div id="mask-layer"></div>
<div id="wechat-bind-popup">
<div class="wechatBindPopupHeader">
<div>
<div class="wechatBindPopupTitle">绑定微信</div>
<div class="wechatBindPopupSub">绑定后可使用微信快捷登录当前账号</div>
</div>
<div class="popup-close" onclick="closeWeChatBindPopup()">
<i class="layui-icon layui-icon-close"></i>
</div>
</div>
<div class="wechatBindPopupBody">
<div class="wechatBindFormRow">
<label>手机号</label>
<input id="wechatBindPhone" type="text" placeholder="请输入手机号" />
</div>
<div class="wechatBindFormRow">
<label>短信验证码</label>
<div class="wechatBindCodeBox">
<input id="wechatBindSmsCode" type="text" placeholder="请输入验证码" />
<button type="button" onclick="sendWeChatBindSms()">获取验证码</button>
</div>
</div>
<div class="wechatBindFormRow">
<label>登录密码</label>
<input id="wechatBindPassword" type="password" placeholder="请输入登录密码" />
</div>
<div class="wechatBindTip">当前接口需要微信授权参数、手机号、短信验证码和密码。</div>
<button type="button" class="wechatBindSubmit" onclick="submitWeChatBind()">确认绑定</button>
</div>
</div>
<script src="../public/js/md5.js"></script>
<script>
const $ = layui.$;
var currentUserData = null;
var accountInfoData = {};
var menuListData = [];
var signInPageNum = 1;
var articlePageNum = 1;
var pageSize = 10;
var signedToday = false;
function firstValue(source, keys, fallback) {
for (var i = 0; i < keys.length; i += 1) {
var key = keys[i];
if (
source &&
source[key] !== undefined &&
source[key] !== null &&
source[key] !== ""
) {
return source[key];
}
}
return fallback === undefined ? "" : fallback;
}
function pageRows(res) {
return ApiClient.asArray(ApiClient.pickData(res, {}));
}
function pageTotal(res) {
var data = ApiClient.pickData(res, {}) || {};
return Number(data.totalRow || data.total || res.total || 0);
}
function money(value) {
var number = Number(value || 0);
return Number.isFinite(number) ? number.toFixed(2) : "0.00";
}
function safeText(value) {
return CommonUtil.escapeHtml
? CommonUtil.escapeHtml(value)
: String(value || "");
}
function setSignInButtonSigned(signed) {
signedToday = !!signed;
var $btn = $("#signInBtn");
$btn.text(signedToday ? "已签到" : "每日签到");
$btn.prop("disabled", signedToday);
$btn.toggleClass("is-signed", signedToday);
}
function hasSignedTodayValue(data) {
return (
data &&
(data.signedToday !== undefined ||
data.todaySigned !== undefined ||
data.isSignedToday !== undefined)
);
}
function readSignedToday(data) {
var value = firstValue(
data,
["signedToday", "todaySigned", "isSignedToday"],
false,
);
return value === true || value === 1 || value === "1";
}
function isExpertUser(data) {
if (!data) return false;
var levelText = CommonUtil.getUserLevelText
? CommonUtil.getUserLevelText(data)
: "";
return (
data.expert === true ||
data.regularExpert === true ||
data.internExpert === true ||
data.isExpert === true ||
data.isExpert === 1 ||
data.isExpert === "1" ||
/专家/.test(levelText || "") ||
/regular|intern|formal|trial|expert|实习|正式/.test(
String(data.expertStatus || data.expert_status || "")
)
);
}
function updateExpertActions(data) {
var expert = isExpertUser(data);
$("#expertApplyBtn").toggle(!expert);
$("#publishArticleBtn").toggle(expert);
}
function loadAccountInfoForWechat() {
ApiClient.get(ApiClient.API.accountInfo, null, { headers: CommonUtil.authHeaders() })
.then(function (res) {
accountInfoData = ApiClient.isSuccess(res) && res.data ? res.data : {};
updateWechatBindPanel();
})
.catch(function () {
accountInfoData = {};
updateWechatBindPanel();
});
}
function isWechatBound() {
var data = Object.assign({}, currentUserData || {}, accountInfoData || {});
return Boolean(
data.openId ||
data.openid ||
data.wxOpenId ||
data.wechatOpenId ||
data.wechatOpenid ||
data.unionId ||
data.wechatUnionId ||
data.wechatBound ||
data.isWechatBound,
);
}
function updateWechatBindPanel() {
var $desc = $("#wechat-bind-desc");
var $button = $("#wechat-bind-button");
var $card = $("#wechat-bind-card");
if (!$desc.length || !$button.length) return;
$card.removeClass("is-bound is-pending is-ready");
if (isWechatBound()) {
$desc.text("微信已绑定");
$card.addClass("is-bound");
$button
.text("已绑定")
.removeClass("is-pending")
.addClass("is-bound")
.prop("disabled", true);
return;
}
$desc.text("未绑定微信");
$card.addClass("is-ready");
$button
.text("绑定微信")
.removeClass("is-bound is-pending")
.prop("disabled", false);
}
function getWechatAuthParams() {
var params = new URLSearchParams(window.location.search);
return {
socialCode: params.get("socialCode") || params.get("code") || "",
socialState: params.get("socialState") || params.get("state") || "",
};
}
function openWeChatBindPopup() {
var authParams = getWechatAuthParams();
if (isWechatBound()) {
layui.layer.msg("当前账号已绑定微信", { icon: 1 });
return;
}
if (!authParams.socialCode) {
layui.layer.msg("请先通过微信授权入口进入绑定流程", { icon: 0 });
return;
}
$("#wechatBindPhone").val(
(currentUserData && currentUserData.phoneNumber) ||
accountInfoData.phoneNumber ||
"",
);
$("#wechatBindSmsCode").val("");
$("#wechatBindPassword").val("");
$("#mask-layer").show();
$("#wechat-bind-popup").show();
}
function closeWeChatBindPopup() {
$("#wechat-bind-popup").hide();
$("#mask-layer").hide();
}
function sendWeChatBindSms() {
var phoneNumber = $("#wechatBindPhone").val().trim();
if (!phoneNumber) {
layui.layer.msg("请输入手机号", { icon: 2 });
return;
}
ApiClient.get(ApiClient.API.authSocialBindPhoneSmsCode, {
phoneNumber: phoneNumber,
}).then(function (res) {
if (ApiClient.isSuccess(res)) {
layui.layer.msg("验证码已发送", { icon: 1 });
} else {
layui.layer.msg(res.msg || "验证码发送失败", { icon: 2 });
}
});
}
function submitWeChatBind() {
var authParams = getWechatAuthParams();
var phoneNumber = $("#wechatBindPhone").val().trim();
var smsCode = $("#wechatBindSmsCode").val().trim();
var password = $("#wechatBindPassword").val();
if (!authParams.socialCode) {
layui.layer.msg("缺少微信授权参数", { icon: 2 });
return;
}
if (!phoneNumber || !smsCode || !password) {
layui.layer.msg("请完整填写绑定信息", { icon: 2 });
return;
}
ApiClient.post(ApiClient.API.authSocialBind, {
source: "wechat_open",
socialCode: authParams.socialCode,
socialState: authParams.socialState,
phoneNumber: phoneNumber,
smsCode: smsCode,
password: hex_md5(password),
}).then(function (res) {
if (ApiClient.isSuccess(res)) {
layui.layer.msg("微信绑定成功", { icon: 1 });
try {
sessionStorage.setItem("wechatAccountBindSuccess", "1");
} catch (e) {}
closeWeChatBindPopup();
loadUserDetail();
} else {
layui.layer.msg(res.msg || "微信绑定失败", { icon: 2 });
}
});
}
function isTodayTime(value) {
if (!value) return false;
var dateText = String(value).slice(0, 10);
var today = new Date();
var month = String(today.getMonth() + 1).padStart(2, "0");
var day = String(today.getDate()).padStart(2, "0");
return dateText === today.getFullYear() + "-" + month + "-" + day;
}
// ====== Auth Check ======
function checkAuth() {
var token = localStorage.getItem("token");
if (!token) {
layui.use("layer", function () {
layui.layer.confirm(
"请先登录",
{ btn: ["去登录", "取消"] },
function (index) {
layui.layer.close(index);
window.location.href = "login.html";
},
);
});
return false;
}
return true;
}
// ====== Header Login State ======
function updateHeaderState() {
var token = localStorage.getItem("token");
if (token) {
$("#notLoggedInBox").hide();
$("#loggedInBox").show();
} else {
$("#notLoggedInBox").show();
$("#loggedInBox").hide();
}
}
// ====== Load User Detail ======
function loadUserDetail() {
CommonUtil.getCurrentUserDetail(
function (data) {
currentUserData = data;
$("#userNickName").text(data.nickName || "用户");
$("#userAvatar").attr(
"src",
data.avatar || "../public/img/userimg.png",
);
$("#headerAvatar").attr(
"src",
data.avatar || "../public/img/userimg.png",
);
$("#headerUserName").text(data.nickName || "用户");
$("#userPhone").text(
data.phoneNumber
? data.phoneNumber.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")
: "",
);
$("#userLevel").text(
CommonUtil.getUserLevelText
? CommonUtil.getUserLevelText(data)
: data.isExpert === "1"
? "专家"
: "普通会员",
);
updateExpertActions(data);
loadAccountInfoForWechat();
$("#userPoints").html((data.points || 0) + "<span>点</span>");
if (hasSignedTodayValue(data)) {
setSignInButtonSigned(readSignedToday(data));
}
loadWalletOverview();
},
function () {
layui.use("layer", function () {
layui.layer.msg("登录已过期,请重新登录", { icon: 2 });
});
localStorage.removeItem("token");
setTimeout(function () {
window.location.href = "login.html";
}, 1500);
},
);
}
function loadWalletOverview() {
ApiClient.get(
ApiClient.API.walletOverview,
null,
{ headers: CommonUtil.authHeaders() },
)
.then(function (res) {
if (!ApiClient.isSuccess(res)) return;
var data = ApiClient.pickData(res, {}) || {};
$("#userBalance").html(
money(
firstValue(data, ["accountBalance", "balance", "walletBalance"], 0),
) + "<span>元</span>",
);
$("#userSalesBalance").html(
money(
firstValue(
data,
["salesBalance", "distributionBalance", "referralBalance", "rebateBalance"],
0,
),
) + "<span>元</span>",
);
$("#userExpertBalance").html(
money(
firstValue(data, ["expertBalance", "expertCommission", "expertWallet"], 0),
) + "<span>元</span>",
);
})
.catch(function () {});
}
// ====== Sign In ======
function handleSignIn() {
if (signedToday || $("#signInBtn").prop("disabled")) return;
CommonUtil.signIn(function (res) {
if (ApiClient.isSuccess ? ApiClient.isSuccess(res) : res.code === 0) {
setSignInButtonSigned(true);
loadUserDetail();
loadSignInRecords(1);
}
});
}
// ====== Logout ======
function handleLogout() {
ApiClient.post(
"/api/web/user/logout",
{},
{ headers: CommonUtil.authHeaders() },
)
.then(function (res) {
localStorage.removeItem("token");
window.location.href = "login.html";
})
.catch(function () {
localStorage.removeItem("token");
window.location.href = "login.html";
});
}
// ====== Sign-in Records ======
function loadSignInRecords(pageNum) {
signInPageNum = pageNum || 1;
ApiClient.post(
"/api/web/user/signIn/getPageList",
{
delFlag: "0",
pageNum: signInPageNum,
pageSize: 5,
pointsType: 1,
},
{ headers: CommonUtil.authHeaders() },
).then(function (res) {
if (res.code === 0 && res.data) {
renderSignInTable(res.data.records || []);
renderSignInPager(res.data.totalRow);
}
});
}
function renderSignInTable(records) {
var $tbody = $("#signInTableBody");
$tbody.empty();
if (!records || records.length === 0) {
$tbody.html(
'<tr><td colspan="4" style="text-align:center;color:var(--text-muted);padding:30px;">暂无签到记录</td></tr>',
);
return;
}
$.each(records, function (i, item) {
if (isTodayTime(item.createTime || item.signTime || item.signDate)) {
setSignInButtonSigned(true);
}
$tbody.append(
"<tr>" +
"<td>" +
(item.createTime || "") +
"</td>" +
"<td>" +
(item.pointsType == 1 ? "签到" : item.pointsType || "") +
"</td>" +
'<td style="color:var(--orange);font-weight:600;">+' +
(item.pointsAwarded || 0) +
"</td>" +
"<td>" +
(item.remark || "每日签到") +
"</td>" +
"</tr>",
);
});
}
function renderSignInPager(total) {
var laypage = layui.laypage;
laypage.render({
elem: "signInPager",
count: total,
limit: 5,
curr: signInPageNum,
theme: "#102b6a",
jump: function (obj, first) {
if (!first) loadSignInRecords(obj.curr);
},
});
}
// ====== Load Menu for Filter ======
function loadMenuList() {
ApiClient.post(
"/api/web/menu/getFormatList",
{},
{ headers: CommonUtil.authHeaders() },
).then(function (res) {
if (res.code === 0 && res.data) {
menuListData = res.data;
// 免费文章 - 只需彩种
var $lottery = $("#filterLottery");
$lottery.empty();
$.each(res.data, function (i, lottery) {
$lottery.append(
'<option value="' +
lottery.id +
'">' +
lottery.name +
"</option>",
);
});
// 付费文章 - 三级联动,默认选第一个
var $paidLottery = $("#paidFilterLottery");
$paidLottery.empty();
$.each(res.data, function (i, lottery) {
$paidLottery.append(
'<option value="' +
lottery.id +
'">' +
lottery.name +
"</option>",
);
});
// 触发联动:加载第一个彩种的方案和类型
if (res.data.length > 0) {
onPaidLotteryChange();
var firstPlan = $("#paidFilterPlan option:not(:first)").val();
if (firstPlan) {
$("#paidFilterPlan").val(firstPlan);
onPaidPlanChange();
var firstType = $("#paidFilterType option:not(:first)").val();
if (firstType) {
$("#paidFilterType").val(firstType);
}
}
}
loadFreeArticles(1);
loadPaidArticles(1);
}
});
}
// ====== Free Articles ======
function loadFreeArticles(pageNum) {
articlePageNum = pageNum || 1;
var menuId = $("#filterLottery").val() || "";
ApiClient.get(
"/api/web/mine/free-article/list",
{
menuId: menuId,
pageNum: articlePageNum,
pageSize: pageSize,
},
{ headers: CommonUtil.authHeaders() },
).then(function (res) {
if (ApiClient.isSuccess(res)) {
renderArticleTable(pageRows(res));
renderArticlePager(pageTotal(res));
} else {
renderArticleTable([]);
}
});
}
function renderArticleTable(records) {
var $tbody = $("#articleTableBody");
$tbody.empty();
if (!records || records.length === 0) {
$tbody.html(
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:30px;">暂无文章</td></tr>',
);
return;
}
$.each(records, function (i, item) {
$tbody.append(
"<tr>" +
'<td><a href="' +
CommonUtil.freeArticleHref(item.id || "") +
'" target="_blank">' +
(item.title || item.articleTitle || item.name || "") +
"</a></td>" +
"<td>" +
(item.lotteryName || item.menuName || item.codeName || "") +
"</td>" +
"<td>" +
(item.planName || item.schemeName || item.groupName || item.playName || "") +
"</td>" +
"<td>" +
(item.typeName || item.categoryName || item.menuTypeName || "") +
"</td>" +
"<td>" +
(item.createTime || "") +
"</td>" +
'<td><a href="' +
CommonUtil.freeArticleHref(item.id || "") +
'" target="_blank">查看</a></td>' +
"</tr>",
);
});
}
function renderArticlePager(total) {
layui.laypage.render({
elem: "articlePager",
count: total,
limit: pageSize,
curr: articlePageNum,
theme: "#102b6a",
jump: function (obj, first) {
if (!first) loadFreeArticles(obj.curr);
},
});
}
// ====== Paid Articles ======
var paidArticlePageNum = 1;
function onPaidLotteryChange() {
var lotteryId = $("#paidFilterLottery").val();
var $plan = $("#paidFilterPlan");
var $type = $("#paidFilterType");
$plan.html('<option value="">请选择方案</option>');
$type.html('<option value="">请选择类型</option>');
if (lotteryId) {
var selected = menuListData.find(function (item) {
return item.id == lotteryId;
});
if (selected && selected.children) {
var plans = CommonUtil.filterDuanzu(
selected.children,
selected.name || selected.lotteryName || "",
);
$.each(plans, function (i, plan) {
$plan.append(
'<option value="' + plan.id + '">' + plan.name + "</option>",
);
});
}
}
}
function onPaidPlanChange() {
var lotteryId = $("#paidFilterLottery").val();
var planId = $("#paidFilterPlan").val();
var $type = $("#paidFilterType");
$type.html('<option value="">请选择类型</option>');
if (lotteryId && planId) {
var selected = menuListData.find(function (item) {
return item.id == lotteryId;
});
if (selected && selected.children) {
var plan = selected.children.find(function (item) {
return item.id == planId;
});
if (plan && plan.children) {
$.each(plan.children, function (i, type) {
$type.append(
'<option value="' + type.id + '">' + type.name + "</option>",
);
});
}
}
}
}
function buildPaidArticleHref(item) {
var params = new URLSearchParams();
var articleId = item.id || item.articleId || item.payArticleId || "";
if (articleId) params.set("articleId", articleId);
if (item.expertId || item.createBy) params.set("expertId", item.expertId || item.createBy);
if (item.code || item.lotteryCode || item.menuCode) params.set("code", item.code || item.lotteryCode || item.menuCode);
if (item.menuId || item.parentId || item.lotteryId) params.set("menuId", item.menuId || item.parentId || item.lotteryId);
if (item.accountType) params.set("accountType", item.accountType);
return params.toString() ? "caiinfo.html?" + params.toString() : "cai.html";
}
function loadPaidArticles(pageNum) {
paidArticlePageNum = pageNum || 1;
var menuId =
$("#paidFilterType").val() ||
$("#paidFilterPlan").val() ||
$("#paidFilterLottery").val() ||
"";
ApiClient.get(
"/api/web/mine/pay-article/list",
{
menuId: menuId,
pageNum: paidArticlePageNum,
pageSize: pageSize,
},
{ headers: CommonUtil.authHeaders() },
).then(function (res) {
if (ApiClient.isSuccess(res)) {
renderPaidArticleTable(pageRows(res));
renderPaidArticlePager(pageTotal(res));
} else {
renderPaidArticleTable([]);
}
});
}
function renderPaidArticleTable(records) {
var $tbody = $("#paidArticleTableBody");
$tbody.empty();
if (!records || records.length === 0) {
$tbody.html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:30px;">暂无付费文章</td></tr>',
);
return;
}
$.each(records, function (i, item) {
$tbody.append(
"<tr>" +
'<td><a href="' +
buildPaidArticleHref(item) +
'" target="_blank">' +
(item.title || item.articleTitle || item.name || "") +
"</a></td>" +
"<td>" +
(item.lotteryName || item.menuName || item.codeName || "") +
"</td>" +
'<td style="color:var(--orange);font-weight:600;">' +
(item.price || item.amount || item.payAmount || 0) +
(item.payUnit || item.unit || "积分") +
"</td>" +
"<td>" +
(item.createTime || "") +
"</td>" +
'<td><a href="' +
buildPaidArticleHref(item) +
'" target="_blank">查看</a></td>' +
"</tr>",
);
});
}
function renderPaidArticlePager(total) {
layui.laypage.render({
elem: "paidArticlePager",
count: total,
limit: pageSize,
curr: paidArticlePageNum,
theme: "#102b6a",
jump: function (obj, first) {
if (!first) loadPaidArticles(obj.curr);
},
});
}
// ====== Purchase Records ======
var purchasePageNum = 1;
var purchaseTotalRow = 0;
function loadPurchaseRecords(pageNum) {
purchasePageNum = pageNum || 1;
ApiClient.get(
ApiClient.API.minePurchasedPayArticleList,
{
pageNum: purchasePageNum,
pageSize: pageSize,
},
{ headers: CommonUtil.authHeaders() },
)
.then(function (res) {
if (ApiClient.isSuccess(res)) {
purchaseTotalRow = pageTotal(res);
renderPurchaseTable(pageRows(res));
renderPurchasePager(purchaseTotalRow);
} else {
purchaseTotalRow = 0;
renderPurchaseTable([]);
}
})
.catch(function () {
purchaseTotalRow = 0;
renderPurchaseTable([]);
});
}
function purchaseSourceText(item) {
var source = String(firstValue(item, ["sourceType", "type", "bizType"], ""));
if (source === "fc3d_scheme") return "方案";
if (source === "pay_article") return "付费文章";
if (/方案|断组|杀组合/.test(String(firstValue(item, ["title", "goodsName", "productName"], "")))) return "方案";
return "付费文章";
}
function purchaseTitle(item) {
return firstValue(
item,
["title", "articleTitle", "goodsName", "productName", "schemeName", "name"],
"未命名商品",
);
}
function purchaseIssueText(item) {
var issue = firstValue(item, ["issue", "issueNo", "period", "expect"], "");
var start = firstValue(item, ["issueStartNo", "startIssue"], "");
var end = firstValue(item, ["issueEndNo", "endIssue"], "");
if (issue) return issue;
if (start && end && String(start) !== String(end)) return start + "-" + end;
return start || end || "-";
}
function purchaseAmountText(item) {
var amount = firstValue(item, ["paidAmount", "payAmount", "amount", "price", "totalAmount"], 0);
return money(amount) + (item.payUnit || item.unit || "积分");
}
function purchaseDeleteSourceType(item) {
var directSourceType = firstValue(item, ["sourceType", "recordSourceType", "bizSourceType", "type", "bizType"], "");
var sourceTypeText = String(directSourceType || "").toLowerCase();
if (/fc3d|scheme/.test(sourceTypeText) || /方案/.test(String(directSourceType || ""))) {
return "fc3d_scheme";
}
if (/pay[_-]?article|article|preorder/.test(sourceTypeText) || /预购|付费文章/.test(String(directSourceType || ""))) {
return "pay_article";
}
return /断组|杀组合|方案/.test(purchaseTitle(item))
? "fc3d_scheme"
: "pay_article";
}
function purchaseDeleteRecordId(item) {
return firstValue(
item,
[
"recordId",
"purchaseRecordId",
"purchasedRecordId",
"buyRecordId",
"payRecordId",
"orderRecordId",
"id",
],
"",
);
}
function purchaseDetailUrl(item) {
var source = String(firstValue(item, ["sourceType", "type", "bizType"], ""));
var title = purchaseTitle(item);
if (source === "fc3d_scheme" || /断组|杀组合|方案/.test(title)) {
if (/杀组合/.test(title)) return "shazuhe.html";
if (/断组/.test(title)) return "duanzuhe.html";
return "duanzuhe.html";
}
var expertId = firstValue(item, ["expertId", "createBy", "accountId"], "");
var code = firstValue(item, ["code", "lotteryCode", "suoxie"], "");
var parentId = firstValue(item, ["menuId", "parentId", "typeId"], "");
if (!expertId) return "javascript:void(0)";
return (
"caiinfo.html?createBy=" +
encodeURIComponent(expertId) +
"&code=" +
encodeURIComponent(code) +
"&parentId=" +
encodeURIComponent(parentId)
);
}
function renderPurchaseTable(records) {
var $tbody = $("#purchaseTableBody");
$tbody.empty();
if (!records || records.length === 0) {
$tbody.html(
'<tr><td colspan="7" style="text-align:center;color:var(--text-muted);padding:30px;">暂无购买记录</td></tr>',
);
return;
}
$.each(records, function (i, item) {
var url = purchaseDetailUrl(item);
var sourceType = purchaseDeleteSourceType(item);
var recordId = purchaseDeleteRecordId(item);
var actionList = [];
if (url !== "javascript:void(0)") {
actionList.push('<a href="' + safeText(url) + '" target="_blank">查看</a>');
}
if (sourceType && recordId) {
actionList.push(
'<button class="purchase-delete-btn" type="button" data-source-type="' +
safeText(sourceType) +
'" data-record-id="' +
safeText(recordId) +
'">删除</button>',
);
}
var action = actionList.length
? '<div class="purchase-action-box">' + actionList.join("") + "</div>"
: "-";
$tbody.append(
"<tr>" +
"<td>" +
safeText(purchaseSourceText(item)) +
"</td>" +
"<td>" +
safeText(purchaseTitle(item)) +
"</td>" +
"<td>" +
safeText(purchaseIssueText(item)) +
"</td>" +
"<td>" +
safeText(firstValue(item, ["expertName", "createUserName", "nickname"], "-")) +
"</td>" +
"<td>" +
safeText(firstValue(item, ["purchaseTime", "payTime", "createTime"], "-")) +
"</td>" +
'<td style="color:var(--orange);font-weight:600;">' +
safeText(purchaseAmountText(item)) +
"</td>" +
"<td>" +
action +
"</td>" +
"</tr>",
);
});
}
function deletePurchaseRecord(sourceType, recordId) {
if (!sourceType || !recordId) {
layui.layer.msg("缺少购买记录信息,无法删除", { icon: 2 });
return;
}
layui.layer.confirm(
"确定删除这条购买记录吗?",
{
title: "删除购买记录",
btn: ["删除", "取消"],
},
function (index) {
layui.layer.close(index);
ApiClient.delete(
ApiClient.API.minePurchasedPayArticleDelete(sourceType, recordId),
null,
{ headers: CommonUtil.authHeaders() },
)
.then(function (res) {
if (!ApiClient.isSuccess(res)) {
throw new Error((res && (res.msg || res.message)) || "删除购买记录失败");
}
layui.layer.msg("删除成功", { icon: 1 });
var nextPage =
purchaseTotalRow > 1 &&
purchasePageNum > 1 &&
purchaseTotalRow - 1 <= (purchasePageNum - 1) * pageSize
? purchasePageNum - 1
: purchasePageNum;
loadPurchaseRecords(nextPage);
})
.catch(function (error) {
layui.layer.msg((error && error.message) || "删除购买记录失败", { icon: 2 });
});
},
);
}
function renderPurchasePager(total) {
layui.laypage.render({
elem: "purchasePager",
count: total,
limit: pageSize,
curr: purchasePageNum,
theme: "#102b6a",
jump: function (obj, first) {
if (!first) loadPurchaseRecords(obj.curr);
},
});
}
// ====== Edit Profile Popup ======
function openEditProfile() {
layui.use("layer", function () {
var layer = layui.layer;
var avatar = currentUserData
? currentUserData.avatar || "../public/img/userimg.png"
: "../public/img/userimg.png";
var nickName = currentUserData
? currentUserData.nickName || currentUserData.username || ""
: "";
uploadedAvatarUrl = "";
userAvatarFile = null;
var content =
'<div class="uc-edit-profile-panel">' +
'<div class="uc-edit-avatar-zone">' +
'<button class="uc-edit-avatar-button" type="button" onclick="document.getElementById(\'editAvatarInput\').click()">' +
'<img id="editAvatarImg" src="' +
safeText(avatar) +
'" class="uc-edit-avatar" alt="头像" />' +
"</button>" +
'<div class="uc-edit-avatar-tip">点击头像更换</div>' +
'<input class="uc-edit-file-input" type="file" id="editAvatarInput" accept="image/*" onchange="previewAndUploadAvatar(this)" />' +
"</div>" +
'<div class="uc-edit-field">' +
"<label>昵称</label>" +
'<input type="text" id="editNickName" value="' +
safeText(nickName) +
'" placeholder="请输入昵称" maxlength="20" />' +
"</div>" +
'<div class="uc-edit-field">' +
"<label>新密码(不修改请留空)</label>" +
'<input type="password" id="editPassword" placeholder="不修改请留空" maxlength="20" />' +
"</div>" +
'<div class="uc-edit-field">' +
"<label>确认密码</label>" +
'<input type="password" id="editPasswordConfirm" placeholder="再次输入新密码" maxlength="20" />' +
"</div>" +
'<div class="uc-edit-actions">' +
'<button class="uc-edit-cancel" type="button" onclick="closeEditProfile()">取消</button>' +
'<button class="uc-edit-submit" id="editProfileSubmitBtn" type="button" onclick="submitEditProfile()">保存修改</button>' +
"</div>" +
"</div>";
editProfileLayerIndex = layer.open({
type: 1,
title: "编辑资料",
area: ["420px", "auto"],
skin: "uc-edit-popup",
shadeClose: true,
content: content,
end: function () {
editProfileLayerIndex = null;
uploadedAvatarUrl = "";
userAvatarFile = null;
},
});
});
}
var uploadedAvatarUrl = "";
var editProfileLayerIndex = null;
var userAvatarFile = null;
function closeEditProfile() {
if (editProfileLayerIndex !== null) {
layui.layer.close(editProfileLayerIndex);
}
}
function previewAndUploadAvatar(input) {
if (!input.files || !input.files[0]) return;
var file = input.files[0];
if (!/^image\//.test(file.type || "")) {
layui.layer.msg("请选择图片文件", { icon: 2 });
input.value = "";
return;
}
userAvatarFile = file;
uploadedAvatarUrl = "";
var reader = new FileReader();
reader.onload = function (e) {
$("#editAvatarImg").attr("src", e.target.result);
};
reader.readAsDataURL(file);
}
function getAvatarIdFromUploadResponse(res) {
var data = ApiClient.pickData(res, null);
if (data === null || data === undefined || data === "") return "";
if (typeof data === "string" || typeof data === "number") {
return String(data);
}
return String(
firstValue(
data,
[
"id",
"fileId",
"avatarId",
"ossId",
"resourceId",
"attachmentId",
"file_id",
"avatar_id",
"url",
"avatar",
],
""
)
);
}
function isApiSuccess(res) {
return res && (res.code === 0 || res.code === 200);
}
function uploadSelectedAvatarIfNeeded() {
if (!userAvatarFile) return Promise.resolve("");
var formData = new FormData();
formData.append("file", userAvatarFile);
return ApiClient.post(ApiClient.API.accountProfileAvatar, formData).then(
function (res) {
if (!isApiSuccess(res)) {
throw new Error(res && res.msg ? res.msg : "头像上传失败");
}
var avatarId = getAvatarIdFromUploadResponse(res);
if (!avatarId) {
throw new Error("头像上传返回缺少文件编号");
}
uploadedAvatarUrl = avatarId;
return avatarId;
}
);
}
function submitEditProfile() {
var nickName = $("#editNickName").val().trim();
var password = $("#editPassword").val();
var passwordConfirm = $("#editPasswordConfirm").val();
if (!nickName) {
layui.layer.msg("昵称不能为空", { icon: 2 });
return;
}
if (password && password !== passwordConfirm) {
layui.layer.msg("两次密码输入不一致", { icon: 2 });
return;
}
var params = { username: nickName };
if (password) {
params.password = hex_md5(password);
}
var $submitBtn = $("#editProfileSubmitBtn");
$submitBtn.prop("disabled", true).text("保存中...");
uploadSelectedAvatarIfNeeded()
.then(function (avatarId) {
if (avatarId) params.avatar = avatarId;
return ApiClient.put(ApiClient.API.accountProfile, params);
})
.then(function (res) {
if (isApiSuccess(res)) {
layui.layer.msg("修改成功", { icon: 1, time: 1500 });
closeEditProfile();
loadUserDetail();
} else {
layui.layer.msg("修改失败: " + (res.msg || "未知错误"), {
icon: 2,
});
}
})
.catch(function (err) {
layui.layer.msg((err && err.message) || "网络错误", { icon: 2 });
})
.finally(function () {
$submitBtn.prop("disabled", false).text("保存修改");
});
}
// ====== Initialize ======
$(function () {
updateHeaderState();
if (checkAuth()) {
loadUserDetail();
loadSignInRecords(1);
loadMenuList();
loadPurchaseRecords(1);
}
$("#purchaseTableBody").on("click", ".purchase-delete-btn", function () {
deletePurchaseRecord($(this).data("sourceType"), $(this).data("recordId"));
});
});
CommonUtil.loadPageConfig();
</script>
</body>
</html>