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

775 lines
25 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/cai.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="userAvatar"
src="../public/img/userimg.png"
alt=""
class="topbar__avatar"
/>
<div class="topbar__meta">
<span id="userName" class="topbar__uname">用户</span>
<span id="userLevel" class="topbar__ubadge">会员</span>
</div>
</a>
<button class="topbar__btn topbar__btn--logout" onclick="logout()">
退出登录
</button>
</div>
</div>
</div>
</nav>
<!-- Main -->
<main class="cxz-main">
<!-- Breadcrumb -->
<div class="cxz-breadcrumb">
<a href="index.html">首页</a><span class="sep">></span>
<span id="breadcrumbLottery">彩票预测</span>
</div>
<!-- Filter Section -->
<div class="cxz-filter-box">
<div class="cxz-filter-row">
<div class="cxz-filter-label">彩种:</div>
<div class="cxz-filter-options" id="lotteryFilter"></div>
</div>
<div class="cxz-filter-row">
<div class="cxz-filter-label">方案:</div>
<div class="cxz-filter-options" id="planFilter"></div>
</div>
<div class="cxz-filter-row">
<div class="cxz-filter-label">类型:</div>
<div class="cxz-filter-options" id="typeFilter"></div>
</div>
</div>
<!-- Period Bar -->
<div class="cxz-period-bar">
<div class="cxz-period-title" id="tableTitle">预测列表</div>
<div class="cxz-period-select">
<button class="cxz-period-btn active" data-size="10">近10期</button>
<button class="cxz-period-btn" data-size="20">近20期</button>
<button class="cxz-period-btn" data-size="50">近50期</button>
</div>
</div>
<!-- Article Table -->
<div class="cxz-table-box">
<table class="cxz-data-table">
<thead>
<tr>
<th>专家</th>
<th>最新期号</th>
<th>最新推荐</th>
<th>正确率</th>
<th>操作</th>
</tr>
</thead>
<tbody id="articleBody">
<tr>
<td
colspan="5"
style="
text-align: center;
color: var(--text-muted);
padding: 40px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
<div class="cxz-pagination" id="pagination"></div>
</div>
<!-- Expert Ranking -->
<div class="cxz-ranking-box">
<div class="cxz-ranking-header">
<div class="cxz-ranking-title">专家排行榜</div>
</div>
<table class="cxz-rank-table">
<thead>
<tr>
<th>排名</th>
<th>专家</th>
<th>命中率</th>
<th>方案数</th>
<th>操作</th>
</tr>
</thead>
<tbody id="rankBody">
<tr>
<td
colspan="5"
style="
text-align: center;
color: var(--text-muted);
padding: 30px;
"
>
加载中...
</td>
</tr>
</tbody>
</table>
</div>
</main>
<!-- Footer -->
<footer class="site-footer">
<div class="site-footer__inner">
<img
src="../images/home-logo.png"
alt="神彩算"
class="site-footer__logo"
/>
<p id="copyright-info">神彩算以开奖数据、免费文章、资讯推荐为核心</p>
<div class="site-footer__meta">
<a
id="beian"
href="https://beian.miit.gov.cn/"
target="_blank"
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
>工信部备案号</a
>
<span id="additional-info">本站仅供数据分析参考</span>
</div>
</div>
</footer>
<button
class="gotop"
id="backTop"
type="button"
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
>
</button>
<script>
const $ = layui.$;
// URL params
const urlParams = new URLSearchParams(window.location.search);
let currentCode = urlParams.get("id") || "ssq";
let currentParentId = urlParams.get("planId") || "";
let currentTypeId =
urlParams.get("menuId") ||
urlParams.get("parentId") ||
urlParams.get("typeId") ||
"";
let currentPageSize = 10;
const currentRowPageSize = 10;
let currentPage = 1;
let menuData = [];
let currentLottery = null;
// Login status
function logout() {
localStorage.removeItem("token");
window.location.reload();
}
function checkLogin() {
const token = localStorage.getItem("token");
if (token) {
$("#notLoggedInBox").hide();
$("#loggedInBox").css("display", "flex");
CommonUtil.getCurrentUserDetail(
function (data) {
$("#userName").text(data.nickName || "用户");
$("#userLevel").text(data.isExpert === "1" ? "专家" : "会员");
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
},
function () {
$("#notLoggedInBox").show();
$("#loggedInBox").hide();
},
);
}
}
function renderNav() {
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
if (res.code !== 0 || !res.data) return;
var $nav = $("#navLotteryItems");
$nav.find(".topbar__nav-link").not(":first").remove();
$.each(res.data, function (i, item) {
$nav.append(
'<a href="cai.html?id=' +
item.suoxie +
'" class="topbar__nav-link">' +
item.name +
"</a>",
);
});
});
}
$(window).on("scroll", function () {
$(window).scrollTop() > 320
? $("#backTop").addClass("is-visible")
: $("#backTop").removeClass("is-visible");
});
// Load menu data (3-level cascade)
function loadMenuData() {
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
if (res.code === 0 && res.data) {
menuData = res.data;
renderLotteryFilter();
}
});
}
function renderLotteryFilter() {
const $box = $("#lotteryFilter");
$box.empty();
$.each(menuData, function (i, item) {
const btn = $(
'<button class="cxz-filter-btn" data-code="' +
item.suoxie +
'">' +
item.name +
"</button>",
);
if (item.suoxie === currentCode) {
btn.addClass("active");
currentLottery = item;
}
btn.on("click", function () {
currentCode = item.suoxie;
currentLottery = item;
currentParentId = "";
currentTypeId = "";
currentPage = 1;
$box.find(".cxz-filter-btn").removeClass("active");
$(this).addClass("active");
renderPlanFilter();
renderTypeFilter();
loadArticles();
loadRanking();
updateBreadcrumb();
});
$box.append(btn);
});
if (!currentLottery && menuData.length > 0) {
currentLottery = menuData[0];
currentCode = currentLottery.suoxie;
}
renderPlanFilter();
renderTypeFilter();
syncCurrentUrl();
}
function syncCurrentUrl() {
const params = new URLSearchParams();
params.set("id", currentCode || "ssq");
if (currentTypeId) params.set("parentId", currentTypeId);
if (currentParentId) params.set("planId", currentParentId);
const nextUrl = "cai.html?" + params.toString();
if (window.location.pathname.split("/").pop() + window.location.search !== nextUrl) {
window.history.replaceState(null, "", nextUrl);
}
}
function resolveParentIdByTypeId(list) {
if (!currentTypeId || currentParentId) return;
$.each(list || [], function (_, parent) {
if (currentParentId) return false;
const children = parent && parent.children ? parent.children : [];
const matched = children.find(function (child) {
return String(child.id) === String(currentTypeId);
});
if (matched) {
currentParentId = String(parent.id || "");
return false;
}
});
}
function renderPlanFilter() {
const $box = $("#planFilter");
$box.empty();
if (!currentLottery || !currentLottery.children) {
$box.append(
'<span style="color:var(--text-muted);font-size:13px;">暂无方案</span>',
);
return;
}
const list = CommonUtil.filterDuanzu(
currentLottery.children,
currentLottery.name,
);
resolveParentIdByTypeId(list);
$.each(list, function (i, item) {
const btn = $(
'<button class="cxz-filter-btn" data-id="' +
item.id +
'">' +
item.name +
"</button>",
);
if (i === 0 && !currentParentId) {
btn.addClass("active");
currentParentId = String(item.id || "");
} else if (String(item.id) === String(currentParentId)) {
btn.addClass("active");
}
btn.on("click", function () {
currentParentId = String(item.id || "");
currentTypeId = "";
currentPage = 1;
$box.find(".cxz-filter-btn").removeClass("active");
$(this).addClass("active");
renderTypeFilter();
syncCurrentUrl();
loadArticles();
loadRanking();
});
$box.append(btn);
});
}
function renderTypeFilter() {
const $box = $("#typeFilter");
$box.empty();
let children = [];
if (currentLottery && currentLottery.children) {
const list = CommonUtil.filterDuanzu(
currentLottery.children,
currentLottery.name,
);
if (currentParentId) {
const parent = list.find(function (p) {
return String(p.id) === String(currentParentId);
});
children = parent && parent.children ? parent.children : [];
} else {
// Flatten all children of level-2
$.each(list, function (i, p) {
if (p.children) {
children = children.concat(p.children);
}
});
}
}
if (children.length === 0) {
$box.append(
'<span style="color:var(--text-muted);font-size:13px;">暂无类型</span>',
);
return;
}
let hasActiveType = false;
$.each(children, function (i, item) {
const btn = $(
'<button class="cxz-filter-btn" data-id="' +
item.id +
'">' +
item.name +
"</button>",
);
if (String(item.id) === String(currentTypeId)) {
btn.addClass("active");
hasActiveType = true;
}
btn.on("click", function () {
currentTypeId = String(item.id || "");
currentPage = 1;
$box.find(".cxz-filter-btn").removeClass("active");
$(this).addClass("active");
syncCurrentUrl();
loadArticles();
loadRanking();
});
$box.append(btn);
});
if (!hasActiveType && children[0]) {
currentTypeId = String(children[0].id || "");
$box.find('.cxz-filter-btn[data-id="' + currentTypeId + '"]').addClass("active");
}
syncCurrentUrl();
}
function updateBreadcrumb() {
const name = currentLottery ? currentLottery.name : "彩票预测";
$("#breadcrumbLottery").text(name + " - 预测推荐");
$("#tableTitle").text(name + " 预测列表");
document.title = "神彩算 - " + name + "预测推荐";
}
function getCurrentTypeId() {
const activeTypeId = $("#typeFilter .cxz-filter-btn.active").data("id");
return String(activeTypeId || currentTypeId || "");
}
function escapeText(value) {
return CommonUtil.escapeHtml ? CommonUtil.escapeHtml(String(value || "")) : String(value || "");
}
function getExpertName(item) {
return (
item.nickname ||
item.nickName ||
item.createUserName ||
item.expertName ||
item.accountName ||
item.userName ||
"专家"
);
}
function getExpertAvatar(item) {
return item.avatar || item.accountAvatar || item.expertAvatar || item.headImg || item.headUrl || "";
}
function getExpertId(item) {
return item.createBy || item.expertId || item.accountId || item.userId || item.createUserId || "";
}
function getIssueText(item) {
const issue = item.latestIssue || item.issue || item.expect || item.period || item.issueNo || "";
if (!issue) return "--";
const lotteryName = currentLottery ? currentLottery.name : item.lotteryName || item.menuName || "";
return (lotteryName ? lotteryName + "-第" : "第") + issue + "期";
}
function getRecommendTitle(item) {
return (
item.latestTitle ||
item.title ||
item.articleTitle ||
item.recommendTitle ||
item.latestRecommendTitle ||
item.contentTitle ||
"--"
);
}
function getCorrectDisplayText(item) {
const raw =
item.status ??
item.resultText ??
item.statusText ??
item.drawStatusText ??
item.openStatusText ??
item.hitText ??
item.hitResult ??
item.correctText ??
item.latestStatus ??
item.result ??
"";
const text = String(raw ?? "").trim();
if (text) {
if (/^中/.test(text)) return text;
if (/^-?\d+(?:\.\d+)?$/.test(text) || /^\d+\+\d+$/.test(text)) return "中" + text;
return text;
}
const rate =
item.hitRate ??
item.successRate ??
item.correctRate ??
item.winRate ??
item.rate ??
"";
if (rate !== "" && rate !== null && rate !== undefined) {
if (String(rate).indexOf("%") >= 0) return String(rate);
const value = Number(rate);
if (Number.isFinite(value)) {
return (value > 0 && value <= 1 ? value * 100 : value).toFixed(2) + "%";
}
}
return "--";
}
function getRatePercentText(item) {
const raw =
item.hitRate ??
item.successRate ??
item.correctRate ??
item.winRate ??
item.rate ??
"";
if (raw !== "" && raw !== null && raw !== undefined) {
if (String(raw).indexOf("%") >= 0) return String(raw);
const value = Number(raw);
if (Number.isFinite(value)) {
return (value > 0 && value <= 1 ? value * 100 : value).toFixed(2) + "%";
}
}
const hit = Number(item.correctCount ?? item.hitCount ?? item.hit ?? 0);
const total = Number(item.totalCount ?? item.total ?? item.articleCount ?? 0);
return total > 0 ? ((hit / total) * 100).toFixed(2) + "%" : "0.00%";
}
function buildCaiinfoUrl(item) {
const params = new URLSearchParams();
params.set("createBy", getExpertId(item));
params.set("code", currentCode || "");
params.set("parentId", getCurrentTypeId());
if (item.accountType) params.set("accountType", item.accountType);
return "caiinfo.html?" + params.toString();
}
// Load articles
function loadArticles(page) {
currentPage = page || 1;
const typeId = getCurrentTypeId();
if (!typeId) {
$("#articleBody").html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
);
renderPagination(0);
return;
}
currentTypeId = typeId;
ApiClient.get("/api/web/pay-article/expert-rank", {
menuId: typeId,
issueCount: currentPageSize,
pageNum: currentPage,
pageSize: currentRowPageSize,
}).then(function (res) {
if (ApiClient.isSuccess(res) && ApiClient.pickData(res, null)) {
const data = ApiClient.pickData(res, {}) || {};
const list = data.records || data.rows || ApiClient.asArray(data);
renderArticles(list);
renderPagination(data.totalRow || data.total || data.count || list.length || 0);
} else {
$("#articleBody").html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
);
}
});
}
function renderArticles(list) {
const $body = $("#articleBody");
$body.empty();
if (!list || list.length === 0) {
$body.html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
);
return;
}
$.each(list, function (i, item) {
const expertName = getExpertName(item);
const avatar = getExpertAvatar(item);
const periodText = getIssueText(item);
const predictHtml = getRecommendTitle(item);
const avatarHtml = avatar
? '<img src="' + escapeText(avatar) + '" class="table-img" />'
: '<span class="cxz-expert-avatar">' +
escapeText(expertName).charAt(0) +
"</span>";
const linkUrl = buildCaiinfoUrl(item);
$body.append(
"<tr>" +
'<td><a href="' +
escapeText(linkUrl) +
'" class="cxz-expert-cell">' +
avatarHtml +
"<span>" +
escapeText(expertName) +
"</span></a></td>" +
"<td>" +
escapeText(periodText) +
"</td>" +
"<td>" +
escapeText(predictHtml) +
"</td>" +
'<td><span class="cxz-rate" style="color:#de2103;font-weight:700;">' +
escapeText(getCorrectDisplayText(item)) +
"</span></td>" +
'<td><a href="' +
escapeText(linkUrl) +
'" class="cxz-btn-buy">查看</a></td>' +
"</tr>",
);
});
}
function renderBalls(code) {
if (!code) return '<span style="color:var(--text-muted);">--</span>';
const parts = code.split("+");
let html = "";
const reds = parts[0] ? parts[0].split(",") : [];
$.each(reds, function (i, b) {
html += '<span class="red-q">' + b.trim() + "</span>";
});
for (let p = 1; p < parts.length; p++) {
const blues = parts[p].split(",");
$.each(blues, function (j, b) {
html += '<span class="bule-q">' + b.trim() + "</span>";
});
}
return html;
}
function renderPagination(total) {
layui.laypage.render({
elem: "pagination",
count: total,
limit: currentRowPageSize,
curr: currentPage,
jump: function (obj, first) {
if (!first) {
loadArticles(obj.curr);
}
},
});
}
// Load expert ranking
function loadRanking() {
const typeId = getCurrentTypeId();
if (!typeId) {
$("#rankBody").html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:30px;">暂无数据</td></tr>',
);
return;
}
ApiClient.get("/api/web/pay-article/expert-rank", {
menuId: typeId,
issueCount: 50,
pageNum: 1,
pageSize: currentRowPageSize,
}).then(function (res) {
if (ApiClient.isSuccess(res) && ApiClient.pickData(res, null)) {
const data = ApiClient.pickData(res, {}) || {};
renderRanking(data.records || data.rows || ApiClient.asArray(data));
}
});
}
function renderRanking(list) {
const $body = $("#rankBody");
$body.empty();
if (!list || list.length === 0) {
$body.html(
'<tr><td colspan="5" style="text-align:center;color:var(--text-muted);padding:30px;">暂无数据</td></tr>',
);
return;
}
const experts = list
.map(function (item) {
const total = Number(item.totalCount || item.total || 0);
const hit = Number(item.correctCount || item.hit || 0);
const rateText = getRatePercentText(item);
const hitText = getCorrectDisplayText(item);
const rateNum = rateText
? parseFloat(String(rateText).replace("%", ""))
: total > 0
? (hit / total) * 100
: 0;
return {
raw: item,
name: getExpertName(item),
createBy: getExpertId(item),
total: total || item.articleCount || item.totalCount || 0,
hit,
hitText,
rate: Number.isFinite(rateNum) ? rateNum : 0,
rank: item.rank,
accountType: item.accountType,
};
})
.sort(function (a, b) {
return (a.rank || 9999) - (b.rank || 9999) || b.rate - a.rate;
})
.slice(0, 10);
$.each(experts, function (i, exp) {
const rate = exp.rate.toFixed(1);
const badgeClass =
i === 0
? "cxz-rank-1"
: i === 1
? "cxz-rank-2"
: i === 2
? "cxz-rank-3"
: "cxz-rank-n";
$body.append(
"<tr>" +
'<td><span class="cxz-rank-badge ' +
badgeClass +
'">' +
(i + 1) +
"</span></td>" +
'<td><a href="' +
escapeText(buildCaiinfoUrl(exp.raw)) +
'" class="cxz-expert-link">' +
escapeText(exp.name) +
"</a></td>" +
'<td><span style="color:#de2103;font-weight:700;">' +
escapeText(exp.hitText !== "--" ? exp.hitText : rate + "%") +
"</span></td>" +
"<td>" +
exp.total +
"</td>" +
'<td><a href="' +
escapeText(buildCaiinfoUrl(exp.raw)) +
'" class="cxz-btn-buy">查看</a></td>' +
"</tr>",
);
});
}
// Period selector
$(document).on("click", ".cxz-period-btn", function () {
$(".cxz-period-btn").removeClass("active");
$(this).addClass("active");
currentPageSize = parseInt($(this).data("size"));
loadArticles();
});
// Init
$(function () {
checkLogin();
loadMenuData();
CommonUtil.loadPageConfig();
setTimeout(function () {
loadArticles();
loadRanking();
updateBreadcrumb();
}, 300);
});
</script>
</body>
</html>