彩先知pc
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(npm list *)",
|
||||||
|
"Bash(npm install *)",
|
||||||
|
"Bash(node *)",
|
||||||
|
"Bash(python -c ' *)",
|
||||||
|
"Bash(python -c \"print\\('python works'\\)\")",
|
||||||
|
"Bash(awk '{print $5, $NF}')",
|
||||||
|
"Bash(ls -la \"C:\\\\\\\\Users\\\\\\\\Administrator\\\\\\\\Desktop\\\\\\\\ceshi\\\\\\\\html\\\\\\\\\")",
|
||||||
|
"Bash(dir \"C:\\\\\\\\Users\\\\\\\\Administrator\\\\\\\\Desktop\\\\\\\\ceshi\\\\\\\\html\\\\\\\\\")",
|
||||||
|
"Bash(dir \"C:\\\\Users\\\\Administrator\\\\Desktop\\\\ceshi\\\\public\\\\css\\\\*.css\")",
|
||||||
|
"Bash(awk '{printf \"%6d bytes %s\\\\n\", $5, $NF}')",
|
||||||
|
"Bash(sort -t/ -k6)",
|
||||||
|
"Bash(dir \"C:\\\\Users\\\\Administrator\\\\Desktop\\\\ceshi\" /s /b)",
|
||||||
|
"Read(//c/Users/Administrator/.claude/**)",
|
||||||
|
"Read(//c/Users/Administrator/.claude//**)",
|
||||||
|
"Read(//c/Users/Administrator/**)",
|
||||||
|
"Bash(dir *)",
|
||||||
|
"Bash(xxd \"c:/Users/Administrator/Desktop/ceshi/public/css/public.css\")",
|
||||||
|
"Bash(iconv -f UTF-8 -t UTF-8 \"c:/Users/Administrator/Desktop/ceshi/public/css/public.css\")",
|
||||||
|
"Bash(powershell *)",
|
||||||
|
"Bash(xxd \"C:/Users/Administrator/Desktop/caixiansheng/html/fabumianfeiwenzhang.html\")"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"liveServer.settings.port": 5503
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
method,path,summary,tags
|
||||||
|
"GET","/api/web/account/info","获取当前登录用户信息接口",""
|
||||||
|
"PUT","/api/web/account/profile","个人信息修改",""
|
||||||
|
"GET","/api/web/account/profile/avatar","头像上传",""
|
||||||
|
"GET","/api/web/ad/list","广告按位置筛选",""
|
||||||
|
"GET","/api/web/agreement/{type}","隐私/协议",""
|
||||||
|
"GET","/api/web/auth/code","获取验证码",""
|
||||||
|
"POST","/api/web/auth/heartbeat","登录心跳接口-前端可不接",""
|
||||||
|
"POST","/api/web/auth/login","登录接口",""
|
||||||
|
"POST","/api/web/auth/logout","退出登录",""
|
||||||
|
"POST","/api/web/auth/register","注册",""
|
||||||
|
"GET","/api/web/auth/slide-captcha","滑动验证",""
|
||||||
|
"POST","/api/web/auth/slide-captcha/verify","校验滑动结果",""
|
||||||
|
"GET","/api/web/auth/sms/code","发短信接口",""
|
||||||
|
"POST","/api/web/auth/social-bind","第三方账号绑定本地账号",""
|
||||||
|
"POST","/api/web/auth/social-callback","三方回调地址(前端不需要接,给平台用)",""
|
||||||
|
"POST","/api/web/auth/social-login","三方登录接口-暂时不接",""
|
||||||
|
"GET","/api/web/auth/verify-config","查询验证方式",""
|
||||||
|
"GET","/api/web/banner/list","轮播图",""
|
||||||
|
"GET","/api/web/config","网站基础信息接口-简化接口选一接就行",""
|
||||||
|
"GET","/api/web/config/list","网站基础信息",""
|
||||||
|
"GET","/api/web/config/site","网站图标",""
|
||||||
|
"POST","/api/web/expert/apply","专家申请",""
|
||||||
|
"GET","/api/web/expert/config","内容长度验证",""
|
||||||
|
"POST","/api/web/expert/upload-id-card-back","上传身份证反面",""
|
||||||
|
"POST","/api/web/expert/upload-id-card-front","上传身份证正面",""
|
||||||
|
"GET","/api/web/fc3d/free-predict/list","断组查询接口",""
|
||||||
|
"GET","/api/web/fc3d/free-predict/menus","断组杀组合菜单",""
|
||||||
|
"GET","/api/web/fc3d/scheme/{id}","方案详情",""
|
||||||
|
"GET","/api/web/fc3d/scheme/list","方案查询",""
|
||||||
|
"GET","/api/web/free-article/{id}","免费文章详情",""
|
||||||
|
"POST","/api/web/free-article/{id}/collect","收藏",""
|
||||||
|
"POST","/api/web/free-article/{id}/comment","评论",""
|
||||||
|
"GET","/api/web/free-article/{id}/comments","免费文章评论",""
|
||||||
|
"POST","/api/web/free-article/{id}/like","点赞",""
|
||||||
|
"GET","/api/web/free-article/{id}/related","相关推荐",""
|
||||||
|
"GET","/api/web/free-article/latest","最新推荐",""
|
||||||
|
"GET","/api/web/free-article/list","免费文章列表",""
|
||||||
|
"POST","/api/web/free-article/publish","发布",""
|
||||||
|
"GET","/api/web/free-article/recommend","免费文章",""
|
||||||
|
"GET","/api/web/link/friend","友情链接",""
|
||||||
|
"GET","/api/web/link/other-recommend","其他推荐",""
|
||||||
|
"GET","/api/web/lottery/result/latest","开奖结果",""
|
||||||
|
"GET","/api/web/lottery/result/list","开奖记录",""
|
||||||
|
"GET","/api/web/lottery/result/trend","走势图",""
|
||||||
|
"GET","/api/web/lottery/result/trend/tools","获取彩种信息排序",""
|
||||||
|
"GET","/api/web/menu/{id}/children","获取下级菜单ID",""
|
||||||
|
"GET","/api/web/menu/home-nav","导航栏",""
|
||||||
|
"GET","/api/web/mine/expert-collect/list","专家收藏",""
|
||||||
|
"GET","/api/web/mine/free-article/{id}","我的免费文章详情",""
|
||||||
|
"GET","/api/web/mine/free-article/list","我的免费文章列表",""
|
||||||
|
"GET","/api/web/mine/free-collect/list","免费文章收藏列表",""
|
||||||
|
"GET","/api/web/mine/pay-article/{id}","我的付费文章详情",""
|
||||||
|
"GET","/api/web/mine/pay-article/list","我的付费文章列表",""
|
||||||
|
"GET","/api/web/mine/pay-collect/list","付费文章收藏列表",""
|
||||||
|
"GET","/api/web/mine/purchased-pay-article/list","我的购买记录",""
|
||||||
|
"POST","/api/web/mine/sign-in","签到",""
|
||||||
|
"GET","/api/web/mine/sign-in/list","签到记录",""
|
||||||
|
"GET","/api/web/mine/sign-in/status","签到状态接口",""
|
||||||
|
"GET","/api/web/mine/summary","个人信息",""
|
||||||
|
"GET","/api/web/notice/{id}","公告详情",""
|
||||||
|
"GET","/api/web/notice/list","网站公告",""
|
||||||
|
"GET","/api/web/pay-article/{id}/related","相关推荐",""
|
||||||
|
"POST","/api/web/pay-article/article-collect/{articleId}","文章收藏",""
|
||||||
|
"POST","/api/web/pay-article/expert-collect","专家收藏",""
|
||||||
|
"GET","/api/web/pay-article/expert-list","专家预测详情列表",""
|
||||||
|
"GET","/api/web/pay-article/expert-profile","付费文章专家头部信息",""
|
||||||
|
"GET","/api/web/pay-article/expert-rank","专家预测列表",""
|
||||||
|
"GET","/api/web/pay-article/latest","最新推荐",""
|
||||||
|
"GET","/api/web/pay-article/publish","发布付费文章",""
|
||||||
|
"GET","/api/web/pay-article/publish/options","发布规则查询",""
|
||||||
|
"POST","/api/web/referral/bind","绑定推荐人",""
|
||||||
|
"GET","/api/web/referral/bind-preview","先查推荐人信息,用来弹确认框",""
|
||||||
|
"GET","/api/web/referral/invite-list","邀请用户列表",""
|
||||||
|
"GET","/api/web/referral/rebate-list","返利流水列表",""
|
||||||
|
"GET","/api/web/referral/share-info","邀请码和推广链接",""
|
||||||
|
"GET","/api/web/referral/summary","返利比例",""
|
||||||
|
"GET","/api/web/wallet/flow/list","资金流水按类型",""
|
||||||
|
"GET","/api/web/wallet/overview","钱包",""
|
||||||
|
"POST","/api/web/wallet/purchase/fc3d-scheme","购买接口",""
|
||||||
|
"POST","/api/web/wallet/purchase/pay-article","购买付费文章/专家预测",""
|
||||||
|
"POST","/api/web/wallet/receive-account","新增收款账户",""
|
||||||
|
"DELETE","/api/web/wallet/receive-account/{id}","删除",""
|
||||||
|
"PUT","/api/web/wallet/receive-account/{id}","修改收款账户",""
|
||||||
|
"PUT","/api/web/wallet/receive-account/{id}/default","把支付方式设置默认",""
|
||||||
|
"GET","/api/web/wallet/receive-account/list","查询收款账户",""
|
||||||
|
"POST","/api/web/wallet/receive-account/upload-qrcode","上传收款二维码",""
|
||||||
|
"GET","/api/web/wallet/recharge/config/list","创建充值订单",""
|
||||||
|
"GET","/api/web/wallet/recharge/notify","充值回调-前端不接(平台对接)",""
|
||||||
|
"POST","/api/web/wallet/recharge/order","创建充值订单",""
|
||||||
|
"POST","/api/web/wallet/transfer-to-account","分销余额或专家佣金转到账户余额",""
|
||||||
|
"POST","/api/web/wallet/withdraw","分销余额或专家佣金申请提现到收款账户",""
|
||||||
|
"GET","/api/web/wallet/withdraw/list","提现申请记录-单独接口",""
|
||||||
|
@@ -0,0 +1,147 @@
|
|||||||
|
# 彩票 WEB_API 接口摘要
|
||||||
|
|
||||||
|
来源:C:/Users/Administrator/Desktop/彩票WEB_API.openapi.json
|
||||||
|
接口数量:92
|
||||||
|
|
||||||
|
## /api/web/account
|
||||||
|
|
||||||
|
- `GET` `/api/web/account/info`:获取当前登录用户信息接口
|
||||||
|
- `PUT` `/api/web/account/profile`:个人信息修改
|
||||||
|
- `GET` `/api/web/account/profile/avatar`:头像上传
|
||||||
|
|
||||||
|
## /api/web/ad
|
||||||
|
|
||||||
|
- `GET` `/api/web/ad/list`:广告按位置筛选
|
||||||
|
|
||||||
|
## /api/web/agreement
|
||||||
|
|
||||||
|
- `GET` `/api/web/agreement/{type}`:隐私/协议
|
||||||
|
|
||||||
|
## /api/web/auth
|
||||||
|
|
||||||
|
- `GET` `/api/web/auth/code`:获取验证码
|
||||||
|
- `POST` `/api/web/auth/heartbeat`:登录心跳接口-前端可不接
|
||||||
|
- `POST` `/api/web/auth/login`:登录接口
|
||||||
|
- `POST` `/api/web/auth/logout`:退出登录
|
||||||
|
- `POST` `/api/web/auth/register`:注册
|
||||||
|
- `GET` `/api/web/auth/slide-captcha`:滑动验证
|
||||||
|
- `POST` `/api/web/auth/slide-captcha/verify`:校验滑动结果
|
||||||
|
- `GET` `/api/web/auth/sms/code`:发短信接口
|
||||||
|
- `POST` `/api/web/auth/social-bind`:第三方账号绑定本地账号
|
||||||
|
- `POST` `/api/web/auth/social-callback`:三方回调地址(前端不需要接,给平台用)
|
||||||
|
- `POST` `/api/web/auth/social-login`:三方登录接口-暂时不接
|
||||||
|
- `GET` `/api/web/auth/verify-config`:查询验证方式
|
||||||
|
|
||||||
|
## /api/web/banner
|
||||||
|
|
||||||
|
- `GET` `/api/web/banner/list`:轮播图
|
||||||
|
|
||||||
|
## /api/web/config
|
||||||
|
|
||||||
|
- `GET` `/api/web/config`:网站基础信息接口-简化接口选一接就行
|
||||||
|
- `GET` `/api/web/config/list`:网站基础信息
|
||||||
|
- `GET` `/api/web/config/site`:网站图标
|
||||||
|
|
||||||
|
## /api/web/expert
|
||||||
|
|
||||||
|
- `POST` `/api/web/expert/apply`:专家申请
|
||||||
|
- `GET` `/api/web/expert/config`:内容长度验证
|
||||||
|
- `POST` `/api/web/expert/upload-id-card-back`:上传身份证反面
|
||||||
|
- `POST` `/api/web/expert/upload-id-card-front`:上传身份证正面
|
||||||
|
|
||||||
|
## /api/web/fc3d
|
||||||
|
|
||||||
|
- `GET` `/api/web/fc3d/free-predict/list`:断组查询接口
|
||||||
|
- `GET` `/api/web/fc3d/free-predict/menus`:断组杀组合菜单
|
||||||
|
- `GET` `/api/web/fc3d/scheme/{id}`:方案详情
|
||||||
|
- `GET` `/api/web/fc3d/scheme/list`:方案查询
|
||||||
|
|
||||||
|
## /api/web/free-article
|
||||||
|
|
||||||
|
- `GET` `/api/web/free-article/{id}`:免费文章详情
|
||||||
|
- `POST` `/api/web/free-article/{id}/collect`:收藏
|
||||||
|
- `POST` `/api/web/free-article/{id}/comment`:评论
|
||||||
|
- `GET` `/api/web/free-article/{id}/comments`:免费文章评论
|
||||||
|
- `POST` `/api/web/free-article/{id}/like`:点赞
|
||||||
|
- `GET` `/api/web/free-article/{id}/related`:相关推荐
|
||||||
|
- `GET` `/api/web/free-article/latest`:最新推荐
|
||||||
|
- `GET` `/api/web/free-article/list`:免费文章列表
|
||||||
|
- `POST` `/api/web/free-article/publish`:发布
|
||||||
|
- `GET` `/api/web/free-article/recommend`:免费文章
|
||||||
|
|
||||||
|
## /api/web/link
|
||||||
|
|
||||||
|
- `GET` `/api/web/link/friend`:友情链接
|
||||||
|
- `GET` `/api/web/link/other-recommend`:其他推荐
|
||||||
|
|
||||||
|
## /api/web/lottery
|
||||||
|
|
||||||
|
- `GET` `/api/web/lottery/result/latest`:开奖结果
|
||||||
|
- `GET` `/api/web/lottery/result/list`:开奖记录
|
||||||
|
- `GET` `/api/web/lottery/result/trend`:走势图
|
||||||
|
- `GET` `/api/web/lottery/result/trend/tools`:获取彩种信息排序
|
||||||
|
|
||||||
|
## /api/web/menu
|
||||||
|
|
||||||
|
- `GET` `/api/web/menu/{id}/children`:获取下级菜单ID
|
||||||
|
- `GET` `/api/web/menu/home-nav`:导航栏
|
||||||
|
|
||||||
|
## /api/web/mine
|
||||||
|
|
||||||
|
- `GET` `/api/web/mine/expert-collect/list`:专家收藏
|
||||||
|
- `GET` `/api/web/mine/free-article/{id}`:我的免费文章详情
|
||||||
|
- `GET` `/api/web/mine/free-article/list`:我的免费文章列表
|
||||||
|
- `GET` `/api/web/mine/free-collect/list`:免费文章收藏列表
|
||||||
|
- `GET` `/api/web/mine/pay-article/{id}`:我的付费文章详情
|
||||||
|
- `GET` `/api/web/mine/pay-article/list`:我的付费文章列表
|
||||||
|
- `GET` `/api/web/mine/pay-collect/list`:付费文章收藏列表
|
||||||
|
- `GET` `/api/web/mine/purchased-pay-article/list`:我的购买记录
|
||||||
|
- `POST` `/api/web/mine/sign-in`:签到
|
||||||
|
- `GET` `/api/web/mine/sign-in/list`:签到记录
|
||||||
|
- `GET` `/api/web/mine/sign-in/status`:签到状态接口
|
||||||
|
- `GET` `/api/web/mine/summary`:个人信息
|
||||||
|
|
||||||
|
## /api/web/notice
|
||||||
|
|
||||||
|
- `GET` `/api/web/notice/{id}`:公告详情
|
||||||
|
- `GET` `/api/web/notice/list`:网站公告
|
||||||
|
|
||||||
|
## /api/web/pay-article
|
||||||
|
|
||||||
|
- `GET` `/api/web/pay-article/{id}/related`:相关推荐
|
||||||
|
- `POST` `/api/web/pay-article/article-collect/{articleId}`:文章收藏
|
||||||
|
- `POST` `/api/web/pay-article/expert-collect`:专家收藏
|
||||||
|
- `GET` `/api/web/pay-article/expert-list`:专家预测详情列表
|
||||||
|
- `GET` `/api/web/pay-article/expert-profile`:付费文章专家头部信息
|
||||||
|
- `GET` `/api/web/pay-article/expert-rank`:专家预测列表
|
||||||
|
- `GET` `/api/web/pay-article/latest`:最新推荐
|
||||||
|
- `GET` `/api/web/pay-article/publish`:发布付费文章
|
||||||
|
- `GET` `/api/web/pay-article/publish/options`:发布规则查询
|
||||||
|
|
||||||
|
## /api/web/referral
|
||||||
|
|
||||||
|
- `POST` `/api/web/referral/bind`:绑定推荐人
|
||||||
|
- `GET` `/api/web/referral/bind-preview`:先查推荐人信息,用来弹确认框
|
||||||
|
- `GET` `/api/web/referral/invite-list`:邀请用户列表
|
||||||
|
- `GET` `/api/web/referral/rebate-list`:返利流水列表
|
||||||
|
- `GET` `/api/web/referral/share-info`:邀请码和推广链接
|
||||||
|
- `GET` `/api/web/referral/summary`:返利比例
|
||||||
|
|
||||||
|
## /api/web/wallet
|
||||||
|
|
||||||
|
- `GET` `/api/web/wallet/flow/list`:资金流水按类型
|
||||||
|
- `GET` `/api/web/wallet/overview`:钱包
|
||||||
|
- `POST` `/api/web/wallet/purchase/fc3d-scheme`:购买接口
|
||||||
|
- `POST` `/api/web/wallet/purchase/pay-article`:购买付费文章/专家预测
|
||||||
|
- `POST` `/api/web/wallet/receive-account`:新增收款账户
|
||||||
|
- `DELETE` `/api/web/wallet/receive-account/{id}`:删除
|
||||||
|
- `PUT` `/api/web/wallet/receive-account/{id}`:修改收款账户
|
||||||
|
- `PUT` `/api/web/wallet/receive-account/{id}/default`:把支付方式设置默认
|
||||||
|
- `GET` `/api/web/wallet/receive-account/list`:查询收款账户
|
||||||
|
- `POST` `/api/web/wallet/receive-account/upload-qrcode`:上传收款二维码
|
||||||
|
- `GET` `/api/web/wallet/recharge/config/list`:创建充值订单
|
||||||
|
- `GET` `/api/web/wallet/recharge/notify`:充值回调-前端不接(平台对接)
|
||||||
|
- `POST` `/api/web/wallet/recharge/order`:创建充值订单
|
||||||
|
- `POST` `/api/web/wallet/transfer-to-account`:分销余额或专家佣金转到账户余额
|
||||||
|
- `POST` `/api/web/wallet/withdraw`:分销余额或专家佣金申请提现到收款账户
|
||||||
|
- `GET` `/api/web/wallet/withdraw/list`:提现申请记录-单独接口
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// config.js
|
||||||
|
window.ENV = {
|
||||||
|
// 开发环境配置
|
||||||
|
development: {
|
||||||
|
API_BASE_URL: 'http://47.108.24.205:9100',
|
||||||
|
// API_BASE_URL: 'http://192.168.10.119:9100',
|
||||||
|
// 后端租户标识,会作为 header tenantId 发送;后面更换租户只改这里。
|
||||||
|
TENANT_ID: '000000',
|
||||||
|
CLIENT_ID: '209ef407810e3856f40870a9f0e769d7',
|
||||||
|
DEBUG: true,
|
||||||
|
APP_NAME: 'Lottery App Dev'
|
||||||
|
},
|
||||||
|
// 生产环境配置
|
||||||
|
production: {
|
||||||
|
API_BASE_URL: 'http://47.108.24.205:9100',
|
||||||
|
// 后端租户标识,会作为 header tenantId 发送;后面更换租户只改这里。
|
||||||
|
TENANT_ID: '000000',
|
||||||
|
CLIENT_ID: '209ef407810e3856f40870a9f0e769d7',
|
||||||
|
DEBUG: false,
|
||||||
|
APP_NAME: 'Lottery App'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据域名自动判断环境
|
||||||
|
window.CURRENT_ENV = (function () {
|
||||||
|
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.port !== '') {
|
||||||
|
return 'development';
|
||||||
|
} else {
|
||||||
|
return 'production';
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
// 获取当前环境配置
|
||||||
|
window.CURRENT_CONFIG = window.ENV[window.CURRENT_ENV];
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
<!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">彩先知 - APP下载</title>
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../public/js/qrcode.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/appdown.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 Content -->
|
||||||
|
<main class="page-main">
|
||||||
|
<!-- Hero with QR -->
|
||||||
|
<div class="download-hero">
|
||||||
|
<div class="hero-text">
|
||||||
|
<h1>下载彩先知<span>APP</span></h1>
|
||||||
|
<p>随时随地查看预测分析,不错过任何精彩推荐</p>
|
||||||
|
<p>扫码下载,畅享移动端体验</p>
|
||||||
|
</div>
|
||||||
|
<div class="hero-qr">
|
||||||
|
<div class="hero-qr-box">
|
||||||
|
<img id="downloadQrImg" src="" alt="下载二维码" />
|
||||||
|
</div>
|
||||||
|
<div class="hero-qr-label">扫描二维码下载APP</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Download Buttons -->
|
||||||
|
<div class="download-cards">
|
||||||
|
<div class="dl-card">
|
||||||
|
<div class="dl-card-icon android">
|
||||||
|
<i class="layui-icon layui-icon-android"></i>
|
||||||
|
</div>
|
||||||
|
<h3>Android 下载</h3>
|
||||||
|
<p>支持 Android 5.0 及以上系统<br />安装包大小约 15MB</p>
|
||||||
|
<a href="#" class="dl-btn android-btn" id="androidBtn"
|
||||||
|
>Android 下载</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="dl-card">
|
||||||
|
<div class="dl-card-icon ios">
|
||||||
|
<i class="layui-icon layui-icon-ios"></i>
|
||||||
|
</div>
|
||||||
|
<h3>iOS 下载</h3>
|
||||||
|
<p>支持 iOS 12.0 及以上系统<br />App Store 搜索"彩先知"</p>
|
||||||
|
<a href="#" class="dl-btn ios-btn" id="iosBtn">iOS 下载</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Features -->
|
||||||
|
<div class="features-section">
|
||||||
|
<div class="features-title">APP特色功能</div>
|
||||||
|
<div class="features-grid">
|
||||||
|
<div class="feature-item">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="layui-icon layui-icon-notice"></i>
|
||||||
|
</div>
|
||||||
|
<div class="feature-name">实时推送</div>
|
||||||
|
<div class="feature-desc">开奖结果即时通知</div>
|
||||||
|
</div>
|
||||||
|
<div class="feature-item">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="layui-icon layui-icon-chart"></i>
|
||||||
|
</div>
|
||||||
|
<div class="feature-name">走势分析</div>
|
||||||
|
<div class="feature-desc">专业走势图表工具</div>
|
||||||
|
</div>
|
||||||
|
<div class="feature-item">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="layui-icon layui-icon-star"></i>
|
||||||
|
</div>
|
||||||
|
<div class="feature-name">专家预测</div>
|
||||||
|
<div class="feature-desc">权威专家精准推荐</div>
|
||||||
|
</div>
|
||||||
|
<div class="feature-item">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="layui-icon layui-icon-group"></i>
|
||||||
|
</div>
|
||||||
|
<div class="feature-name">社区交流</div>
|
||||||
|
<div class="feature-desc">彩民互动交流平台</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
var layer = layui.layer;
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
// Load page config
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
|
||||||
|
// Check login state for topbar
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var token = CommonUtil.getToken();
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (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");
|
||||||
|
});
|
||||||
|
var downloadUrl = window.location.origin;
|
||||||
|
CommonUtil.generateQRCode(downloadUrl, "downloadQrImg", {
|
||||||
|
width: 180,
|
||||||
|
height: 180,
|
||||||
|
colorDark: "#102b6a",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load download links from page config
|
||||||
|
ApiClient.post("/api/web/index", {})
|
||||||
|
.then(function (result) {
|
||||||
|
if (result.data && result.data.webConfigs) {
|
||||||
|
var configs = result.data.webConfigs;
|
||||||
|
configs.forEach(function (item) {
|
||||||
|
if (item.type === "android_download_url") {
|
||||||
|
$("#androidBtn").attr("href", item.content);
|
||||||
|
} else if (item.type === "ios_download_url") {
|
||||||
|
$("#iosBtn").attr("href", item.content);
|
||||||
|
} else if (item.type === "app_download_url") {
|
||||||
|
CommonUtil.generateQRCode(item.content, "downloadQrImg", {
|
||||||
|
width: 180,
|
||||||
|
height: 180,
|
||||||
|
colorDark: "#102b6a",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {});
|
||||||
|
|
||||||
|
// Default fallback - generate QR for current origin
|
||||||
|
if (!$("#downloadQrImg").attr("src")) {
|
||||||
|
CommonUtil.generateQRCode(window.location.origin, "downloadQrImg", {
|
||||||
|
width: 180,
|
||||||
|
height: 180,
|
||||||
|
colorDark: "#102b6a",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
<!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/apply.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<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 apply-hidden">
|
||||||
|
<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 class="apply-page">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<span>专家申请</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="apply-shell">
|
||||||
|
<div class="apply-hero">
|
||||||
|
<div>
|
||||||
|
<h1>申请成为专家</h1>
|
||||||
|
<p>提交身份资料和个人简介,审核通过后即可发布专家预测内容。</p>
|
||||||
|
</div>
|
||||||
|
<div class="apply-user-card">
|
||||||
|
<span>当前账号</span>
|
||||||
|
<strong id="currentUsername">--</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="apply-layout">
|
||||||
|
<aside class="apply-side">
|
||||||
|
<h2>申请说明</h2>
|
||||||
|
<ul>
|
||||||
|
<li>资料需真实有效,身份证照片需清晰完整。</li>
|
||||||
|
<li>简介用于审核您的分析经验和内容方向。</li>
|
||||||
|
<li>审核通过后,可在个人中心发布相关预测文章。</li>
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<section class="apply-card">
|
||||||
|
<div class="apply-section-title">
|
||||||
|
<span></span>
|
||||||
|
资料上传
|
||||||
|
</div>
|
||||||
|
<div class="apply-upload-grid">
|
||||||
|
<button class="apply-upload-card" type="button" onclick="triggerUpload('uploadFront')">
|
||||||
|
<span class="apply-upload-plus" id="idCardFrontPlus">+</span>
|
||||||
|
<img class="apply-upload-preview" id="idCardFrontPreview" alt="身份证正面" />
|
||||||
|
<strong>身份证正面</strong>
|
||||||
|
<em>点击上传</em>
|
||||||
|
</button>
|
||||||
|
<button class="apply-upload-card" type="button" onclick="triggerUpload('uploadBack')">
|
||||||
|
<span class="apply-upload-plus" id="idCardBackPlus">+</span>
|
||||||
|
<img class="apply-upload-preview" id="idCardBackPreview" alt="身份证反面" />
|
||||||
|
<strong>身份证反面</strong>
|
||||||
|
<em>点击上传</em>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class="apply-file-input"
|
||||||
|
type="file"
|
||||||
|
id="uploadFront"
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
onchange="handleFileUpload(this, 'front')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="apply-file-input"
|
||||||
|
type="file"
|
||||||
|
id="uploadBack"
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
onchange="handleFileUpload(this, 'back')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="apply-section-title apply-intro-title">
|
||||||
|
<span></span>
|
||||||
|
个人简介
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
class="apply-intro-textarea"
|
||||||
|
id="introTextarea"
|
||||||
|
placeholder="请输入个人简介"
|
||||||
|
oninput="updateIntro(this)"
|
||||||
|
></textarea>
|
||||||
|
<div class="apply-intro-count">
|
||||||
|
<span id="introCount">0</span> / <span id="introMinCount">80</span> 字(最低)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="apply-submit" id="applyBtn" type="button" onclick="submitApply()">提交申请</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<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">工信部备案号</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>
|
||||||
|
var updateData = {
|
||||||
|
idCardFrontId: "",
|
||||||
|
idCardBackId: "",
|
||||||
|
intro: "",
|
||||||
|
};
|
||||||
|
var expertIntroMinLength = 80;
|
||||||
|
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
renderLoginState();
|
||||||
|
renderNav();
|
||||||
|
loadExpertApplyConfig();
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadUserDetail();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$("#backTop").toggleClass("is-visible", $(window).scrollTop() > 320);
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderLoginState() {
|
||||||
|
var token = CommonUtil.getAuthToken();
|
||||||
|
if (!token) {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
$("#userName").text(data.nickName || data.username || "用户");
|
||||||
|
$("#userLevel").text(CommonUtil.getUserLevelText ? CommonUtil.getUserLevelText(data) : "会员");
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
|
||||||
|
if (res.code !== 0 && res.code !== 200) return;
|
||||||
|
var list = ApiClient.asArray(ApiClient.pickData(res, []));
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.find(".topbar__nav-link").not(":first").remove();
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
var code = item.suoxie || item.code || item.id || "";
|
||||||
|
var name = item.name || item.menuName || "";
|
||||||
|
if (!code || !name) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code) +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
safeText(name) +
|
||||||
|
"</a>"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadUserDetail() {
|
||||||
|
CommonUtil.getCurrentUserDetail(function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
$("#currentUsername").text(data.nickName || data.username || data.phoneNumber || "用户");
|
||||||
|
var isExpert =
|
||||||
|
data.expert === true ||
|
||||||
|
data.regularExpert === true ||
|
||||||
|
data.isExpert === 1 ||
|
||||||
|
data.isExpert === "1";
|
||||||
|
if (isExpert) {
|
||||||
|
$("#applyBtn").text("已申请").prop("disabled", true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function safeText(value) {
|
||||||
|
return CommonUtil.escapeHtml ? CommonUtil.escapeHtml(value) : String(value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isApiSuccess(res) {
|
||||||
|
return res && (res.code === 0 || res.code === 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 loadExpertApplyConfig() {
|
||||||
|
ApiClient.get(ApiClient.API.expertConfig)
|
||||||
|
.then(function (res) {
|
||||||
|
var data = ApiClient.pickData(res, {}) || {};
|
||||||
|
var minLength = Number(
|
||||||
|
firstValue(
|
||||||
|
data,
|
||||||
|
["bioMinLength", "introMinLength", "minBioLength", "minIntroLength", "bio_min_length"],
|
||||||
|
80
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (Number.isFinite(minLength) && minLength > 0) {
|
||||||
|
expertIntroMinLength = minLength;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {})
|
||||||
|
.finally(function () {
|
||||||
|
$("#introMinCount").text(expertIntroMinLength);
|
||||||
|
$("#introTextarea").attr("placeholder", "请输入个人简介(不低于" + expertIntroMinLength + "字)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.triggerUpload = function (inputId) {
|
||||||
|
var input = document.getElementById(inputId);
|
||||||
|
if (input) input.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
function getUploadFileId(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,
|
||||||
|
["objectId", "fileId", "id", "ossId", "resourceId", "attachmentId", "file_id"],
|
||||||
|
""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUploadFileUrl(res, file) {
|
||||||
|
var data = ApiClient.pickData(res, null);
|
||||||
|
if (data && typeof data === "object") {
|
||||||
|
return firstValue(data, ["url", "fileUrl", "fullUrl", "previewUrl"], "");
|
||||||
|
}
|
||||||
|
return URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.handleFileUpload = function (input, type) {
|
||||||
|
var file = input.files && input.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
if (!/^image\//.test(file.type || "")) {
|
||||||
|
layui.layer.msg("请选择图片文件", { icon: 2 });
|
||||||
|
input.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.size > 5 * 1024 * 1024) {
|
||||||
|
layui.layer.msg("文件大小不能超过5MB", { icon: 2 });
|
||||||
|
input.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
var uploadUrl =
|
||||||
|
type === "front" ? ApiClient.API.expertUploadIdCardFront : ApiClient.API.expertUploadIdCardBack;
|
||||||
|
var plusId = type === "front" ? "idCardFrontPlus" : "idCardBackPlus";
|
||||||
|
var previewId = type === "front" ? "idCardFrontPreview" : "idCardBackPreview";
|
||||||
|
|
||||||
|
ApiClient.post(uploadUrl, formData)
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isApiSuccess(res)) {
|
||||||
|
layui.layer.msg(res.msg || "上传失败", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fileId = getUploadFileId(res);
|
||||||
|
if (!fileId) {
|
||||||
|
layui.layer.msg("上传返回缺少文件编号", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === "front") updateData.idCardFrontId = fileId;
|
||||||
|
else updateData.idCardBackId = fileId;
|
||||||
|
|
||||||
|
$("#" + plusId).hide();
|
||||||
|
$("#" + previewId).attr("src", getUploadFileUrl(res, file)).show();
|
||||||
|
layui.layer.msg("上传成功", { icon: 1, time: 1000 });
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layui.layer.msg("上传失败,请稍后重试", { icon: 2 });
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
input.value = "";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.updateIntro = function (textarea) {
|
||||||
|
updateData.intro = textarea.value;
|
||||||
|
$("#introCount").text(textarea.value.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.submitApply = function () {
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
if (!updateData.intro || updateData.intro.trim().length < expertIntroMinLength) {
|
||||||
|
layui.layer.msg("个人简介不能低于" + expertIntroMinLength + "字", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!updateData.idCardFrontId) {
|
||||||
|
layui.layer.msg("请上传身份证正面", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!updateData.idCardBackId) {
|
||||||
|
layui.layer.msg("请上传身份证反面", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var btn = document.getElementById("applyBtn");
|
||||||
|
btn.textContent = "申请中...";
|
||||||
|
btn.disabled = true;
|
||||||
|
|
||||||
|
ApiClient.post(ApiClient.API.expertApply, {
|
||||||
|
bio: updateData.intro.trim(),
|
||||||
|
idCardFrontImage: updateData.idCardFrontId,
|
||||||
|
idCardBackImage: updateData.idCardBackId,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (isApiSuccess(res)) {
|
||||||
|
layui.layer.msg(
|
||||||
|
"资料上传成功,请等待审核通过",
|
||||||
|
{ icon: 1, time: 1800 },
|
||||||
|
function () {
|
||||||
|
window.location.href = "usercenter.html";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "申请失败", { icon: 2 });
|
||||||
|
btn.textContent = "提交申请";
|
||||||
|
btn.disabled = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layui.layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
btn.textContent = "提交申请";
|
||||||
|
btn.disabled = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
<!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/mianfei.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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<span>我的收藏</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-section-header">
|
||||||
|
<div class="cxz-section-title">免费文章收藏</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-collect-grid" id="collectGrid"></div>
|
||||||
|
<div class="cxz-empty" id="emptyState" style="display: none">
|
||||||
|
<div class="cxz-empty-icon">
|
||||||
|
<i
|
||||||
|
class="layui-icon layui-icon-star-fill"
|
||||||
|
style="font-size: 48px"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-empty-text">暂无收藏文章</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="pagination"></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.$;
|
||||||
|
let currentPage = 1;
|
||||||
|
const pageSize = 12;
|
||||||
|
|
||||||
|
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 || "用户");
|
||||||
|
$("#userAvatar").attr(
|
||||||
|
"src",
|
||||||
|
data.avatar || "../public/img/userimg.png",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function authHeaders() {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
return { Authorization: "Bearer " + token };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load collection list
|
||||||
|
function loadCollections() {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiClient.get(
|
||||||
|
"/api/user/collect/list?page=" +
|
||||||
|
currentPage +
|
||||||
|
"&pageSize=" +
|
||||||
|
pageSize,
|
||||||
|
{ headers: authHeaders() },
|
||||||
|
).then(function (res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
const list = res.data.records || res.data || [];
|
||||||
|
const total = res.data.total || 0;
|
||||||
|
renderCollections(list);
|
||||||
|
renderPagination(total);
|
||||||
|
if (list.length === 0) {
|
||||||
|
$("#emptyState").show();
|
||||||
|
} else {
|
||||||
|
$("#emptyState").hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#collectGrid").empty();
|
||||||
|
$("#emptyState").show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCollections(list) {
|
||||||
|
const $grid = $("#collectGrid");
|
||||||
|
$grid.empty();
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
$grid.empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
let displayDate = "";
|
||||||
|
if (item.createTime) displayDate = item.createTime.substring(0, 10);
|
||||||
|
const articleId = item.articleId || item.id || "";
|
||||||
|
$grid.append(
|
||||||
|
'<div class="cxz-collect-card" data-collect-id="' +
|
||||||
|
(item.id || "") +
|
||||||
|
'">' +
|
||||||
|
'<div class="cxz-card-body">' +
|
||||||
|
'<div class="cxz-card-title"><a href="' +
|
||||||
|
CommonUtil.freeArticleHref(articleId) +
|
||||||
|
'">' +
|
||||||
|
(item.articleTitle || item.title || "无标题") +
|
||||||
|
"</a></div>" +
|
||||||
|
'<div class="cxz-card-meta">' +
|
||||||
|
"<span>" +
|
||||||
|
displayDate +
|
||||||
|
"</span>" +
|
||||||
|
'<button class="cxz-card-remove" onclick="removeCollect(this, ' +
|
||||||
|
(item.id || 0) +
|
||||||
|
')">取消收藏</button>' +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCollect(btn, collectId) {
|
||||||
|
layui.layer.confirm(
|
||||||
|
"确定要取消收藏吗?",
|
||||||
|
{ icon: 3, title: "提示" },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/user/collect/delete",
|
||||||
|
{ id: collectId },
|
||||||
|
{ headers: authHeaders() },
|
||||||
|
).then(function (res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layui.layer.msg("已取消收藏", { icon: 1 });
|
||||||
|
const $card = $(btn).closest(".cxz-collect-card");
|
||||||
|
$card.addClass("removing");
|
||||||
|
setTimeout(function () {
|
||||||
|
$card.remove();
|
||||||
|
// Check if empty
|
||||||
|
if ($("#collectGrid .cxz-collect-card").length === 0) {
|
||||||
|
loadCollections();
|
||||||
|
}
|
||||||
|
}, 400);
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "操作失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(total) {
|
||||||
|
layui.use("laypage", function () {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "pagination",
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPage,
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) {
|
||||||
|
currentPage = obj.curr;
|
||||||
|
loadCollections();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
loadCollections();
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,774 @@
|
|||||||
|
<!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>
|
||||||
@@ -0,0 +1,894 @@
|
|||||||
|
<!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/publish.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/finance.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged" style="display: none">
|
||||||
|
<a href="usercenter.html" class="topbar__profile">
|
||||||
|
<img
|
||||||
|
id="userAvatar"
|
||||||
|
src="../public/img/userimg.png"
|
||||||
|
alt=""
|
||||||
|
class="topbar__avatar"
|
||||||
|
/>
|
||||||
|
<div class="topbar__meta">
|
||||||
|
<span id="userName" class="topbar__uname">用户</span>
|
||||||
|
<span id="userLevel" class="topbar__ubadge">会员</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<button class="topbar__btn topbar__btn--logout" onclick="logout()">
|
||||||
|
退出登录
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main -->
|
||||||
|
<main class="cxz-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<span>充值</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Balance Overview -->
|
||||||
|
<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)"
|
||||||
|
>
|
||||||
|
<i class="layui-icon layui-icon-rmb"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cz-balance-bar__info">
|
||||||
|
<div class="cz-balance-bar__label">账户余额</div>
|
||||||
|
<div class="cz-balance-bar__value" id="currentBalance">
|
||||||
|
0.00<span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Package Selection -->
|
||||||
|
<div class="cxz-form-card">
|
||||||
|
<div class="cxz-form-title">选择充值套餐</div>
|
||||||
|
|
||||||
|
<div class="cz-package-grid" id="packageGrid">
|
||||||
|
<div class="cz-package-loading">
|
||||||
|
<i
|
||||||
|
class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"
|
||||||
|
></i>
|
||||||
|
<span>加载套餐中...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="cxz-submit-btn"
|
||||||
|
id="rechargeBtn"
|
||||||
|
onclick="handleRecharge()"
|
||||||
|
>
|
||||||
|
立即充值
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- QR Code Payment Section -->
|
||||||
|
<div class="cxz-form-card" id="qrcodeCard" style="display: none">
|
||||||
|
<div class="cz-qr-section" id="qrSection">
|
||||||
|
<div class="cz-qr-header">
|
||||||
|
<div class="cz-qr-icon">
|
||||||
|
<i class="layui-icon layui-icon-cellphone"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cz-qr-title">微信扫码支付</div>
|
||||||
|
<div class="cz-qr-subtitle">请使用微信扫描下方二维码完成支付</div>
|
||||||
|
</div>
|
||||||
|
<div class="cz-qr-amount" id="payAmountDisplay">0<span>元</span></div>
|
||||||
|
<div class="cz-qr-wrap">
|
||||||
|
<div id="qrcodeContainer"></div>
|
||||||
|
</div>
|
||||||
|
<div class="cz-qr-hint">
|
||||||
|
二维码有效期 <strong>5分钟</strong>,请尽快完成支付
|
||||||
|
</div>
|
||||||
|
<div class="cz-qr-timer">
|
||||||
|
剩余时间:<span id="countdownTimer">05:00</span>
|
||||||
|
</div>
|
||||||
|
<button class="cz-qr-cancel" onclick="cancelPayment()">
|
||||||
|
取消支付
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cz-pay-result" id="paymentSuccess" style="display: none">
|
||||||
|
<div class="cz-pay-result__icon success">
|
||||||
|
<i class="layui-icon layui-icon-ok-circle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cz-pay-result__title">支付成功</div>
|
||||||
|
<div class="cz-pay-result__desc">充值金额已到账,请查看余额</div>
|
||||||
|
<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__icon timeout">
|
||||||
|
<i class="layui-icon layui-icon-close-fill"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cz-pay-result__title">支付超时</div>
|
||||||
|
<div class="cz-pay-result__desc">二维码已过期,请重新发起充值</div>
|
||||||
|
<button class="cz-pay-result__btn" onclick="resetPayment()">
|
||||||
|
重新充值
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tips -->
|
||||||
|
<div class="cz-tips-card">
|
||||||
|
<div class="cz-tips-title">
|
||||||
|
<i class="layui-icon layui-icon-about"></i> 充值说明
|
||||||
|
</div>
|
||||||
|
<ul class="cz-tips-list">
|
||||||
|
<li>充值后余额将实时到账,可用于购买付费方案</li>
|
||||||
|
<li>微信扫码支付请在5分钟内完成,超时需重新发起</li>
|
||||||
|
<li>如遇支付问题,请联系客服处理</li>
|
||||||
|
<li>充值金额不支持退款,请确认后再支付</li>
|
||||||
|
</ul>
|
||||||
|
</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 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 = [];
|
||||||
|
var selectedConfigId = "";
|
||||||
|
var selectedConfigAmount = 0;
|
||||||
|
var pollingTimer = null;
|
||||||
|
var countdownTimer = null;
|
||||||
|
var countdownSeconds = 300;
|
||||||
|
var pollingStartTime = 0;
|
||||||
|
var MAX_POLLING_DURATION = 300000;
|
||||||
|
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return String(value == null ? "" : value)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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);
|
||||||
|
var accountBalance = Number(
|
||||||
|
data.accountBalance || data.balance || data.amount || 0,
|
||||||
|
);
|
||||||
|
$("#currentBalance").html(
|
||||||
|
(Number.isFinite(accountBalance) ? accountBalance : 0).toFixed(2) +
|
||||||
|
'<span class="unit">\u5143</span>',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.get(ApiClient.API.homeNav).then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res) || !res.data) return;
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.find(".topbar__nav-link").not(":first").remove();
|
||||||
|
$.each(ApiClient.asArray(res.data), function (i, item) {
|
||||||
|
if (item.type && item.type !== "lottery") return;
|
||||||
|
var code = item.code || item.suoxie || "";
|
||||||
|
if (!code) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code) +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name || item.lotteryName || code) +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load packages from API
|
||||||
|
function loadConfigList() {
|
||||||
|
ApiClient.get(ApiClient.API.walletRechargeConfigList)
|
||||||
|
.then(function (res) {
|
||||||
|
var data = ApiClient.pickData ? ApiClient.pickData(res) : res.data;
|
||||||
|
var list = ApiClient.asArray(data);
|
||||||
|
if (ApiClient.isSuccess(res) && list.length > 0) {
|
||||||
|
configList = list;
|
||||||
|
// Sort by sort field
|
||||||
|
configList.sort(function (a, b) {
|
||||||
|
return (a.sort || 0) - (b.sort || 0);
|
||||||
|
});
|
||||||
|
renderPackages(configList);
|
||||||
|
} else {
|
||||||
|
renderEmptyPackages();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
renderEmptyPackages("加载失败,请刷新重试");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMoney(value) {
|
||||||
|
var number = Number(value || 0);
|
||||||
|
return Number.isFinite(number) ? number.toFixed(2) : "0.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPackages(list) {
|
||||||
|
var $grid = $("#packageGrid");
|
||||||
|
$grid.empty();
|
||||||
|
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
var paidAmount =
|
||||||
|
parseFloat(item.paidAmount || item.amount || item.price) || 0;
|
||||||
|
var totalCredited =
|
||||||
|
parseFloat(
|
||||||
|
item.totalCredited ||
|
||||||
|
item.arrivalAmount ||
|
||||||
|
item.creditedAmount ||
|
||||||
|
item.receiveAmount,
|
||||||
|
) || paidAmount;
|
||||||
|
var bonus =
|
||||||
|
parseFloat(item.giftAmount || item.bonusAmount || item.giveAmount) ||
|
||||||
|
totalCredited - paidAmount;
|
||||||
|
var bonusRate =
|
||||||
|
paidAmount > 0 ? Math.round((bonus / paidAmount) * 100) : 0;
|
||||||
|
|
||||||
|
var tagHtml = "";
|
||||||
|
if (bonusRate >= 80) {
|
||||||
|
tagHtml = '<div class="cz-pkg__tag hot">超值</div>';
|
||||||
|
} else if (bonusRate >= 30) {
|
||||||
|
tagHtml = '<div class="cz-pkg__tag rec">推荐</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var creditHtml =
|
||||||
|
'<div class="cz-pkg__credit">\u5230\u8d26 ' +
|
||||||
|
formatMoney(totalCredited) +
|
||||||
|
" \u5143</div>";
|
||||||
|
var bonusHtml =
|
||||||
|
bonus > 0
|
||||||
|
? '<div class="cz-pkg__bonus">\u8d60 ' +
|
||||||
|
formatMoney(bonus) +
|
||||||
|
" \u5143</div>"
|
||||||
|
: "";
|
||||||
|
|
||||||
|
var selectedClass = i === 0 ? " selected" : "";
|
||||||
|
if (i === 0) {
|
||||||
|
selectedConfigId = item.id;
|
||||||
|
selectedConfigAmount = paidAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$grid.append(
|
||||||
|
'<div class="cz-pkg' +
|
||||||
|
selectedClass +
|
||||||
|
'" data-id="' +
|
||||||
|
item.id +
|
||||||
|
'" data-amount="' +
|
||||||
|
paidAmount +
|
||||||
|
'" onclick="selectPackage(this)">' +
|
||||||
|
tagHtml +
|
||||||
|
'<div class="cz-pkg__price">' +
|
||||||
|
formatMoney(paidAmount) +
|
||||||
|
"<span>\u5143</span></div>" +
|
||||||
|
creditHtml +
|
||||||
|
bonusHtml +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEmptyPackages(msg) {
|
||||||
|
$("#packageGrid").html(
|
||||||
|
'<div class="cz-package-loading">' +
|
||||||
|
'<i class="layui-icon layui-icon-face-surprised"></i>' +
|
||||||
|
"<span>" +
|
||||||
|
(msg || "暂无充值套餐") +
|
||||||
|
"</span>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPackage(el) {
|
||||||
|
$(".cz-pkg").removeClass("selected");
|
||||||
|
$(el).addClass("selected");
|
||||||
|
selectedConfigId = $(el).data("id");
|
||||||
|
selectedConfigAmount = parseFloat($(el).data("amount")) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle recharge
|
||||||
|
function handleRecharge() {
|
||||||
|
if (!selectedConfigId) {
|
||||||
|
layui.layer.msg("请选择充值套餐", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $btn = $("#rechargeBtn");
|
||||||
|
$btn.text("正在生成订单...").prop("disabled", true);
|
||||||
|
|
||||||
|
ApiClient.post(ApiClient.API.walletRechargeOrder, {
|
||||||
|
rechargeId: selectedConfigId,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
$btn.text("\u7acb\u5373\u5145\u503c").prop("disabled", false);
|
||||||
|
var data = ApiClient.pickData ? ApiClient.pickData(res) : res.data;
|
||||||
|
if (ApiClient.isSuccess(res) && data) {
|
||||||
|
var payUrl = getRechargePaymentUrl(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);
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "创建订单失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
$btn.text("立即充值").prop("disabled", false);
|
||||||
|
layui.layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRechargePaymentUrl(data) {
|
||||||
|
if (typeof data === "string") return data;
|
||||||
|
if (!data || typeof data !== "object") return "";
|
||||||
|
return (
|
||||||
|
data.qrCode ||
|
||||||
|
data.payUrl ||
|
||||||
|
data.paymentUrl ||
|
||||||
|
data.codeUrl ||
|
||||||
|
data.qrCodeUrl ||
|
||||||
|
data.nativeUrl ||
|
||||||
|
data.url ||
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show QR code
|
||||||
|
function showQRCode(url, amount) {
|
||||||
|
$("#qrcodeCard").show();
|
||||||
|
$("#qrSection").show();
|
||||||
|
$("#paymentSuccess").hide();
|
||||||
|
$("#paymentTimeout").hide();
|
||||||
|
$("#qrcodeContainer").empty();
|
||||||
|
|
||||||
|
$("#payAmountDisplay").html(amount + "<span>元</span>");
|
||||||
|
|
||||||
|
new QRCode(document.getElementById("qrcodeContainer"), {
|
||||||
|
text: url,
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
colorDark: "#102b6a",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
correctLevel: QRCode.CorrectLevel.H,
|
||||||
|
});
|
||||||
|
|
||||||
|
countdownSeconds = 300;
|
||||||
|
pollingStartTime = Date.now();
|
||||||
|
startCountdown();
|
||||||
|
|
||||||
|
$("html,body").animate(
|
||||||
|
{ scrollTop: $("#qrcodeCard").offset().top - 20 },
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Countdown
|
||||||
|
function startCountdown() {
|
||||||
|
if (countdownTimer) clearInterval(countdownTimer);
|
||||||
|
countdownTimer = setInterval(function () {
|
||||||
|
countdownSeconds--;
|
||||||
|
if (countdownSeconds <= 0) {
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
stopPolling();
|
||||||
|
$("#qrSection").hide();
|
||||||
|
$("#paymentTimeout").show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var min = Math.floor(countdownSeconds / 60);
|
||||||
|
var sec = countdownSeconds % 60;
|
||||||
|
$("#countdownTimer").text(
|
||||||
|
(min < 10 ? "0" + min : min) + ":" + (sec < 10 ? "0" + sec : sec),
|
||||||
|
);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polling for payment confirmation
|
||||||
|
function startPolling() {
|
||||||
|
stopPolling();
|
||||||
|
doPoll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doPoll() {
|
||||||
|
var elapsed = Date.now() - pollingStartTime;
|
||||||
|
if (elapsed >= MAX_POLLING_DURATION) {
|
||||||
|
stopPolling();
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
$("#qrSection").hide();
|
||||||
|
$("#paymentTimeout").show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleNextPoll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleNextPoll() {
|
||||||
|
var delay = 1000 + Math.floor(Math.random() * 4000);
|
||||||
|
pollingTimer = setTimeout(doPoll, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPolling() {
|
||||||
|
if (pollingTimer) {
|
||||||
|
clearTimeout(pollingTimer);
|
||||||
|
pollingTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelPayment() {
|
||||||
|
stopPolling();
|
||||||
|
if (countdownTimer) clearInterval(countdownTimer);
|
||||||
|
$("#qrcodeCard").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetPayment() {
|
||||||
|
$("#paymentTimeout").hide();
|
||||||
|
$("#qrSection").hide();
|
||||||
|
$("#qrcodeCard").hide();
|
||||||
|
$("html,body").animate({ scrollTop: 0 }, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadConfigList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on("beforeunload", function () {
|
||||||
|
stopPolling();
|
||||||
|
if (countdownTimer) clearInterval(countdownTimer);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>大乐透走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">大乐透走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="35" class="zone-front-header">前区</td>
|
||||||
|
<td colspan="12" class="zone-back-header">后区</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var FRONT_MAX = 35,
|
||||||
|
BACK_MAX = 12;
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var i = 1; i <= FRONT_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= BACK_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(code) {
|
||||||
|
var parts = code.split("+");
|
||||||
|
var fronts = parts[0].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
var backs = [];
|
||||||
|
for (var p = 1; p < parts.length; p++) {
|
||||||
|
if (parts[p])
|
||||||
|
backs = backs.concat(
|
||||||
|
parts[p].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { fronts: fronts, backs: backs };
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var parsed = parseCode(item.openCode);
|
||||||
|
var frontSet = {},
|
||||||
|
backSet = {};
|
||||||
|
parsed.fronts.forEach(function (n) {
|
||||||
|
frontSet[n] = true;
|
||||||
|
});
|
||||||
|
parsed.backs.forEach(function (n) {
|
||||||
|
backSet[n] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
for (var i = 1; i <= FRONT_MAX; i++) {
|
||||||
|
if (frontSet[i]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-red">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= BACK_MAX; i++) {
|
||||||
|
if (backSet[i]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-blue">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcStats(data, maxNum, getNums) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
omitCount = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var nums = getNums(data[r]);
|
||||||
|
if (nums.indexOf(i) >= 0) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
omitCount++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] =
|
||||||
|
omitCount > 0 ? (totalOmit / omitCount).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var fs = calcStats(data, FRONT_MAX, function (d) {
|
||||||
|
return parseCode(d.openCode).fronts;
|
||||||
|
});
|
||||||
|
var bs = calcStats(data, BACK_MAX, function (d) {
|
||||||
|
return parseCode(d.openCode).backs;
|
||||||
|
});
|
||||||
|
var stats = "";
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var i = 1; i <= FRONT_MAX; i++)
|
||||||
|
stats += "<td>" + fs[keys[li]][i] + "</td>";
|
||||||
|
for (var i = 1; i <= BACK_MAX; i++)
|
||||||
|
stats += "<td>" + bs[keys[li]][i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "cjdlt" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,622 @@
|
|||||||
|
<!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/fabumianfeiwenzhang.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged publish-hidden">
|
||||||
|
<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 class="page-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<span>发布免费文章</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="publish-card">
|
||||||
|
<div class="publish-card-header">
|
||||||
|
<h2 class="publish-card-header-h2">发布文章</h2>
|
||||||
|
<p>发布您的预测分析,与彩民分享您的见解</p>
|
||||||
|
</div>
|
||||||
|
<div class="publish-card-body">
|
||||||
|
<div class="publish-tab-bar">
|
||||||
|
<a href="fabumianfeiwenzhang.html" class="publish-tab-item active"
|
||||||
|
>发布免费文章</a
|
||||||
|
>
|
||||||
|
<a href="fufei.html" class="publish-tab-item" id="paidPublishTab"
|
||||||
|
>发布付费文章</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="publish-tip-box">
|
||||||
|
<div class="publish-tip-item">
|
||||||
|
提示:实习期为三天,连续每天发布2篇以上的优质免费文章审核通过后,自动升级为正式专家。
|
||||||
|
</div>
|
||||||
|
<div class="publish-tip-item">
|
||||||
|
免费文章标准:标题20字以上(含期号、彩种、专家名称、标题),正文500字以上,需原创。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="publishForm">
|
||||||
|
<div class="form-row">
|
||||||
|
<label>彩种分类 <span class="required">*</span></label>
|
||||||
|
<select
|
||||||
|
class="form-select form-select--full is-empty"
|
||||||
|
id="lotterySelect"
|
||||||
|
>
|
||||||
|
<option value="">请选择彩种</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" id="menuId" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>文章标题 <span class="required">*</span></label>
|
||||||
|
<div class="form-input-with-count">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-input"
|
||||||
|
id="articleTitle"
|
||||||
|
placeholder="请输入文章标题(含期号、彩种、标题)"
|
||||||
|
maxlength="100"
|
||||||
|
oninput="updateTitleCount()"
|
||||||
|
/>
|
||||||
|
<span class="form-input-count"
|
||||||
|
><span id="titleCount">0</span>/100</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>文章内容 <span class="required">*</span></label>
|
||||||
|
<textarea
|
||||||
|
placeholder="请输入内容"
|
||||||
|
id="input-content1"
|
||||||
|
class="meui-input publish-editor-textarea"
|
||||||
|
name="nr"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="submit-row">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="submit-btn"
|
||||||
|
id="submitBtn"
|
||||||
|
onclick="submitArticle()"
|
||||||
|
>
|
||||||
|
发布文章
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
class="publish-footer-link"
|
||||||
|
>工信部备案号</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 src="../public/js/lay-config.js" charset="utf-8"></script>
|
||||||
|
<script charset="utf-8" src="../public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var menuList = [];
|
||||||
|
var layer;
|
||||||
|
var editor;
|
||||||
|
var pageReady = false;
|
||||||
|
|
||||||
|
function autoFormatEditorContent() {
|
||||||
|
if (!editor) return;
|
||||||
|
try {
|
||||||
|
if (typeof editor.clickToolbar === "function") {
|
||||||
|
editor.clickToolbar("quickformat");
|
||||||
|
} else if (typeof editor.exec === "function") {
|
||||||
|
editor.exec("quickformat");
|
||||||
|
}
|
||||||
|
if (typeof editor.sync === "function") editor.sync();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("auto quickformat failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KindEditor.ready(function (K) {
|
||||||
|
editor = K.create('textarea[id="input-content1"]', {
|
||||||
|
width: "100%",
|
||||||
|
height: "400px",
|
||||||
|
afterBlur: function () {
|
||||||
|
autoFormatEditorContent();
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
"source",
|
||||||
|
"justifyleft",
|
||||||
|
"justifycenter",
|
||||||
|
"justifyright",
|
||||||
|
"justifyfull",
|
||||||
|
"fontsize",
|
||||||
|
"forecolor",
|
||||||
|
"hilitecolor",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"underline",
|
||||||
|
"strikethrough",
|
||||||
|
"table",
|
||||||
|
"clearhtml",
|
||||||
|
"quickformat",
|
||||||
|
"selectall",
|
||||||
|
"link",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
layer = layui.layer;
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
renderLoginState();
|
||||||
|
renderNav();
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadPublishIdentity().then(function (allowed) {
|
||||||
|
if (!allowed) {
|
||||||
|
layer.alert(
|
||||||
|
"您还不是实习或正式专家,暂不能发布文章。",
|
||||||
|
{ title: "暂无权限" },
|
||||||
|
function () {
|
||||||
|
window.location.href = "apply.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageReady = true;
|
||||||
|
loadMenuList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$("#backTop").toggleClass("is-visible", $(window).scrollTop() > 320);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("change", "#lotterySelect", function () {
|
||||||
|
var value = $(this).val();
|
||||||
|
$("#menuId").val(value);
|
||||||
|
$(this).toggleClass("is-empty", !value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", "#paidPublishTab", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var targetHref = this.href || "fufei.html";
|
||||||
|
checkPaidPublishPermission().then(function (result) {
|
||||||
|
if (!result.canPaid) {
|
||||||
|
layer.alert(result.reason || "暂无付费文章发布权限。", {
|
||||||
|
title: "暂无权限",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.location.href = targetHref;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function safeText(value) {
|
||||||
|
return CommonUtil.escapeHtml
|
||||||
|
? CommonUtil.escapeHtml(value)
|
||||||
|
: String(value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isApiSuccess(res) {
|
||||||
|
return res && (res.code === 0 || res.code === 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTruthy(value) {
|
||||||
|
return (
|
||||||
|
value === true ||
|
||||||
|
value === 1 ||
|
||||||
|
value === "1" ||
|
||||||
|
String(value).toLowerCase() === "true"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function padDatePart(value) {
|
||||||
|
return String(value).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLocalDate(date) {
|
||||||
|
return (
|
||||||
|
date.getFullYear() +
|
||||||
|
"-" +
|
||||||
|
padDatePart(date.getMonth() + 1) +
|
||||||
|
"-" +
|
||||||
|
padDatePart(date.getDate())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArticleDateText(value) {
|
||||||
|
if (!value) return "";
|
||||||
|
if (typeof value === "number") {
|
||||||
|
var numericDate = new Date(value);
|
||||||
|
return isNaN(numericDate.getTime())
|
||||||
|
? ""
|
||||||
|
: formatLocalDate(numericDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = String(value).trim();
|
||||||
|
var match = text.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})/);
|
||||||
|
if (match) {
|
||||||
|
return (
|
||||||
|
match[1] + "-" + padDatePart(match[2]) + "-" + padDatePart(match[3])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedDate = new Date(text.replace(/-/g, "/"));
|
||||||
|
return isNaN(parsedDate.getTime()) ? "" : formatLocalDate(parsedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPublishedFreeArticle(item) {
|
||||||
|
if (!item) return false;
|
||||||
|
|
||||||
|
var statusText = String(
|
||||||
|
item.statusText ||
|
||||||
|
item.auditStatusText ||
|
||||||
|
item.publishStatusText ||
|
||||||
|
item.stateText ||
|
||||||
|
"",
|
||||||
|
).toLowerCase();
|
||||||
|
if (/已发布|审核通过|通过|published|approved|pass/.test(statusText)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status =
|
||||||
|
item.status != null
|
||||||
|
? item.status
|
||||||
|
: item.auditStatus != null
|
||||||
|
? item.auditStatus
|
||||||
|
: item.publishStatus;
|
||||||
|
return status === true || status === 1 || status === "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTodayPublishedFreeCount(rows) {
|
||||||
|
var today = formatLocalDate(new Date());
|
||||||
|
return ApiClient.asArray(rows).filter(function (item) {
|
||||||
|
var articleDate = getArticleDateText(
|
||||||
|
item.createTime ||
|
||||||
|
item.create_time ||
|
||||||
|
item.publishTime ||
|
||||||
|
item.publish_time ||
|
||||||
|
item.auditTime ||
|
||||||
|
item.audit_time ||
|
||||||
|
item.updateTime ||
|
||||||
|
item.update_time ||
|
||||||
|
item.createdAt,
|
||||||
|
);
|
||||||
|
return articleDate === today && isPublishedFreeArticle(item);
|
||||||
|
}).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadTodayPublishedFreeCount() {
|
||||||
|
return ApiClient.get(ApiClient.API.mineFreeArticleList, {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) return 0;
|
||||||
|
var data = res.data || res;
|
||||||
|
var rows = ApiClient.asArray(
|
||||||
|
data.rows || data.records || data.list || data.data || data,
|
||||||
|
);
|
||||||
|
return getTodayPublishedFreeCount(rows);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPaidPublishPermission() {
|
||||||
|
return ApiClient.get(ApiClient.API.mineSummary)
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res) || !res.data) {
|
||||||
|
return { canPaid: false, reason: "暂时无法获取发布权限。" };
|
||||||
|
}
|
||||||
|
|
||||||
|
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: "专家才能发布付费文章。" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadTodayPublishedFreeCount().then(function (count) {
|
||||||
|
return {
|
||||||
|
canPaid: count >= 2,
|
||||||
|
reason:
|
||||||
|
count >= 2
|
||||||
|
? ""
|
||||||
|
: "今天需先发布2篇审核通过的免费文章后,才能发布付费文章(当前" +
|
||||||
|
count +
|
||||||
|
"篇)。",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
return { canPaid: false, reason: "暂时无法获取发布权限。" };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 renderLoginState() {
|
||||||
|
var $ = layui.$;
|
||||||
|
var token = CommonUtil.getAuthToken();
|
||||||
|
if (!token) {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
$("#userName").text(data.nickName || data.username || "用户");
|
||||||
|
$("#userLevel").text(
|
||||||
|
CommonUtil.getUserLevelText
|
||||||
|
? CommonUtil.getUserLevelText(data)
|
||||||
|
: "会员",
|
||||||
|
);
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
|
||||||
|
if (!isApiSuccess(res)) return;
|
||||||
|
var list = ApiClient.asArray(ApiClient.pickData(res, []));
|
||||||
|
var $nav = layui.$("#navLotteryItems");
|
||||||
|
$nav.empty();
|
||||||
|
list.forEach(function (item) {
|
||||||
|
var code = item.suoxie || item.code || item.id || "";
|
||||||
|
var name = item.name || item.menuName || item.lotteryName || "";
|
||||||
|
if (!code || !name) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code) +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
safeText(name) +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPublishIdentity() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
resolve(isExpertUser(data));
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
resolve(false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPublishLotteryMenu(item) {
|
||||||
|
if (!item) return false;
|
||||||
|
var name = String(
|
||||||
|
item.name || item.menuName || item.title || "",
|
||||||
|
).trim();
|
||||||
|
var code = String(item.suoxie || item.code || "").trim();
|
||||||
|
if (["首页", "专家推荐"].indexOf(name) > -1) return false;
|
||||||
|
if (/^(home|index|zhuanjia|expert|expertRecommend)$/i.test(code))
|
||||||
|
return false;
|
||||||
|
return !!(item.id || item.menuId) && !!name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMenuList() {
|
||||||
|
ApiClient.post("/api/web/menu/getFormatList", {})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isApiSuccess(res)) throw new Error(res.msg || "获取彩种失败");
|
||||||
|
menuList = ApiClient.asArray(ApiClient.pickData(res, [])).filter(
|
||||||
|
isPublishLotteryMenu,
|
||||||
|
);
|
||||||
|
var $sel = layui.$("#lotterySelect");
|
||||||
|
$sel.find("option:not(:first)").remove();
|
||||||
|
menuList.forEach(function (item) {
|
||||||
|
var id = item.id || item.menuId || "";
|
||||||
|
var name = item.lotteryName || item.menuName || item.name || "";
|
||||||
|
if (!id || !name) return;
|
||||||
|
$sel.append(
|
||||||
|
'<option value="' +
|
||||||
|
safeText(id) +
|
||||||
|
'">' +
|
||||||
|
safeText(name) +
|
||||||
|
"</option>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (!menuList.length) {
|
||||||
|
$sel.append('<option value="" disabled>暂无可发布彩种</option>');
|
||||||
|
}
|
||||||
|
$sel.toggleClass("is-empty", !$sel.val());
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layer.msg((err && err.message) || "获取彩种失败", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.updateTitleCount = function () {
|
||||||
|
var titleInput = document.getElementById("articleTitle");
|
||||||
|
document.getElementById("titleCount").textContent = titleInput
|
||||||
|
? titleInput.value.length
|
||||||
|
: 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getEditorHtml() {
|
||||||
|
autoFormatEditorContent();
|
||||||
|
if (editor && typeof editor.sync === "function") editor.sync();
|
||||||
|
return editor && typeof editor.html === "function"
|
||||||
|
? editor.html()
|
||||||
|
: layui.$("#input-content1").val();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEditorText() {
|
||||||
|
if (editor && typeof editor.text === "function")
|
||||||
|
return editor.text().trim();
|
||||||
|
return layui.$("<div>").html(getEditorHtml()).text().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.submitArticle = function () {
|
||||||
|
if (!pageReady) {
|
||||||
|
layer.msg("页面尚未准备完成", { icon: 0 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var $ = layui.$;
|
||||||
|
var menuId = $("#menuId").val();
|
||||||
|
var title = $("#articleTitle").val().trim();
|
||||||
|
var content = getEditorHtml();
|
||||||
|
var text = getEditorText();
|
||||||
|
|
||||||
|
if (!menuId) {
|
||||||
|
layer.msg("请选择彩种", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (title.length < 20) {
|
||||||
|
layer.msg("标题不能少于20字", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (title.length > 100) {
|
||||||
|
layer.msg("标题不能超过100字", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!content || text.length < 500) {
|
||||||
|
layer.msg("正文内容不能少于500字", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $btn = $("#submitBtn");
|
||||||
|
$btn.text("发布中...").prop("disabled", true);
|
||||||
|
|
||||||
|
ApiClient.post(ApiClient.API.freeArticlePublish, {
|
||||||
|
menuId: menuId,
|
||||||
|
title: title,
|
||||||
|
content: content,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (isApiSuccess(res)) {
|
||||||
|
layer.msg(
|
||||||
|
"发布成功,请等待审核",
|
||||||
|
{ icon: 1, time: 1600 },
|
||||||
|
function () {
|
||||||
|
window.location.href = "usercenter.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || "发布失败", { icon: 2 });
|
||||||
|
$btn.text("发布文章").prop("disabled", false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
$btn.text("发布文章").prop("disabled", false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,421 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>彩先知 - 福彩3D走势图</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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>福彩3D走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">福彩3D走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="3" rowspan="2" class="zone-type">类型</td>
|
||||||
|
<td colspan="10" class="zone-hundred">百位</td>
|
||||||
|
<td colspan="10" class="zone-ten">十位</td>
|
||||||
|
<td colspan="10" class="zone-unit">个位</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var g = 0; g < 3; g++) {
|
||||||
|
for (var i = 0; i <= 9; i++) html += "<td>" + i + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(code) {
|
||||||
|
var nums = code.split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
hundred: nums[0] || 0,
|
||||||
|
ten: nums[1] || 0,
|
||||||
|
unit: nums[2] || 0,
|
||||||
|
nums: nums,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType(h, t, u) {
|
||||||
|
if (h === t && t === u) return "baozi";
|
||||||
|
if (h === t || t === u || h === u) return "zu3";
|
||||||
|
return "zu6";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var parsed = parseCode(item.openCode);
|
||||||
|
var type = getType(parsed.hundred, parsed.ten, parsed.unit);
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
// Type columns
|
||||||
|
var typeNames = ["baozi", "zu3", "zu6"];
|
||||||
|
var typeLabels = ["豹子", "组三", "组六"];
|
||||||
|
for (var ti = 0; ti < 3; ti++) {
|
||||||
|
if (type === typeNames[ti]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="type-' +
|
||||||
|
typeNames[ti] +
|
||||||
|
'">' +
|
||||||
|
typeLabels[ti] +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="type-empty">' +
|
||||||
|
typeLabels[ti] +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hundred position
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.hundred === i) {
|
||||||
|
html += '<td><span class="hit-hundred">' + i + "</span></td>";
|
||||||
|
} else {
|
||||||
|
html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ten position
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.ten === i) {
|
||||||
|
html += '<td><span class="hit-ten">' + i + "</span></td>";
|
||||||
|
} else {
|
||||||
|
html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unit position
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.unit === i) {
|
||||||
|
html += '<td><span class="hit-unit">' + i + "</span></td>";
|
||||||
|
} else {
|
||||||
|
html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcPosStats(data, getVal) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
if (getVal(data[r]) === i) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcTypeStats(data, typeName) {
|
||||||
|
var count = 0,
|
||||||
|
maxOmit = 0,
|
||||||
|
currOmit = 0,
|
||||||
|
maxConsec = 0,
|
||||||
|
avgOmit = 0;
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var p = parseCode(data[r].openCode);
|
||||||
|
var t = getType(p.hundred, p.ten, p.unit);
|
||||||
|
if (t === typeName) {
|
||||||
|
count++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: mo,
|
||||||
|
currOmit: omit,
|
||||||
|
maxConsec: mc,
|
||||||
|
avgOmit: oc > 0 ? (totalOmit / oc).toFixed(1) : data.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var hs = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).hundred;
|
||||||
|
});
|
||||||
|
var ts = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).ten;
|
||||||
|
});
|
||||||
|
var us = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).unit;
|
||||||
|
});
|
||||||
|
var bz = calcTypeStats(data, "baozi");
|
||||||
|
var z3 = calcTypeStats(data, "zu3");
|
||||||
|
var z6 = calcTypeStats(data, "zu6");
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var typeStats = [bz, z3, z6];
|
||||||
|
var stats = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
// Type columns
|
||||||
|
for (var ti = 0; ti < 3; ti++)
|
||||||
|
stats += "<td>" + typeStats[ti][keys[li]] + "</td>";
|
||||||
|
// Position columns
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + hs[keys[li]][i] + "</td>";
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + ts[keys[li]][i] + "</td>";
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + us[keys[li]][i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "fc3d" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
<!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/distribution.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems">
|
||||||
|
<!-- <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 Content -->
|
||||||
|
<main class="page-main">
|
||||||
|
<!-- User Info Card -->
|
||||||
|
<div class="user-card" id="userCard">
|
||||||
|
<div class="user-info-row">
|
||||||
|
<div class="user-avatar-placeholder" id="userAvatar">
|
||||||
|
<i class="layui-icon layui-icon-user"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="user-name">
|
||||||
|
<span id="userNickName">加载中...</span>
|
||||||
|
<span class="user-role-tag role-none" id="roleTag">未申请</span>
|
||||||
|
</div>
|
||||||
|
<div class="user-phone" id="userPhone">--</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-grid">
|
||||||
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">可用余额</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span id="balanceAvailable">0.00</span
|
||||||
|
><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">累计收益</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span id="balanceIncome">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">冻结金额</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span id="balanceFrozen">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">累计提现</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span id="balanceWithdraw">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Section -->
|
||||||
|
<div class="action-section">
|
||||||
|
<div class="action-card">
|
||||||
|
<div class="action-card-title">
|
||||||
|
<i class="layui-icon layui-icon-group"></i> 申请分销
|
||||||
|
</div>
|
||||||
|
<div class="action-card-desc">
|
||||||
|
成为分销商,推广赚佣金。邀请好友注册即可获得分销收益,多级返佣,轻松赚钱。
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="action-card-btn btn-apply-dist"
|
||||||
|
id="btnApplyDist"
|
||||||
|
onclick="applyDistribution()"
|
||||||
|
>
|
||||||
|
申请分销
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="action-card">
|
||||||
|
<div class="action-card-title">
|
||||||
|
<i class="layui-icon layui-icon-star"></i> 申请专家
|
||||||
|
</div>
|
||||||
|
<div class="action-card-desc">
|
||||||
|
成为平台专家,发布预测文章获取收益。展示你的分析能力,让更多彩民看到你的精彩预测。
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="action-card-btn btn-apply-expert"
|
||||||
|
id="btnApplyExpert"
|
||||||
|
onclick="applyExpert()"
|
||||||
|
>
|
||||||
|
申请专家
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Links -->
|
||||||
|
<div class="links-section">
|
||||||
|
<div class="links-section-title">常用功能</div>
|
||||||
|
<div class="links-grid">
|
||||||
|
<a href="wodefenxiao.html" class="link-item">
|
||||||
|
<div class="link-item-icon icon-fenxiao">
|
||||||
|
<i class="layui-icon layui-icon-group"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="link-item-text">我的分销</div>
|
||||||
|
<div class="link-item-desc">查看下级用户和分销数据</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="tuiguang.html" class="link-item">
|
||||||
|
<div class="link-item-icon icon-tuiguang">
|
||||||
|
<i class="layui-icon layui-icon-share"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="link-item-text">推广赚钱</div>
|
||||||
|
<div class="link-item-desc">生成推广链接和二维码</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="tixian.html" class="link-item">
|
||||||
|
<div class="link-item-icon icon-tixian">
|
||||||
|
<i class="layui-icon layui-icon-rmb"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="link-item-text">我要提现</div>
|
||||||
|
<div class="link-item-desc">申请提现到账户</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
var layer = layui.layer;
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
// Load page config
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
|
||||||
|
// Check login state for topbar
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
// Check auth and load user detail
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadUserDetail();
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var token = CommonUtil.getToken();
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (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");
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadUserDetail() {
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
// Display user info
|
||||||
|
$("#userNickName").text(
|
||||||
|
data.nickName || data.phoneNumber || "用户",
|
||||||
|
);
|
||||||
|
$("#userPhone").text(
|
||||||
|
data.phoneNumber
|
||||||
|
? data.phoneNumber.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")
|
||||||
|
: "--",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Avatar
|
||||||
|
if (data.avatar) {
|
||||||
|
$("#userAvatar").replaceWith(
|
||||||
|
'<img class="user-avatar" src="' +
|
||||||
|
data.avatar +
|
||||||
|
'" alt="头像" />',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Balances
|
||||||
|
$("#balanceAvailable").text(
|
||||||
|
(data.availableBalance || 0).toFixed(2),
|
||||||
|
);
|
||||||
|
$("#balanceIncome").text((data.totalIncome || 0).toFixed(2));
|
||||||
|
$("#balanceFrozen").text((data.frozenBalance || 0).toFixed(2));
|
||||||
|
$("#balanceWithdraw").text((data.totalWithdraw || 0).toFixed(2));
|
||||||
|
|
||||||
|
// Role tags
|
||||||
|
var $roleTag = $("#roleTag");
|
||||||
|
if (data.isDistribution === 1 || data.isDistribution === true) {
|
||||||
|
$roleTag
|
||||||
|
.text("分销商")
|
||||||
|
.removeClass("role-none role-expert")
|
||||||
|
.addClass("role-distribution");
|
||||||
|
$("#btnApplyDist").text("已开通").addClass("btn-disabled");
|
||||||
|
}
|
||||||
|
if (data.isExpert === 1 || data.isExpert === true) {
|
||||||
|
$roleTag
|
||||||
|
.text("专家")
|
||||||
|
.removeClass("role-none role-distribution")
|
||||||
|
.addClass("role-expert");
|
||||||
|
$("#btnApplyExpert").text("已开通").addClass("btn-disabled");
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(data.isDistribution === 1 || data.isDistribution === true) &&
|
||||||
|
(data.isExpert === 1 || data.isExpert === true)
|
||||||
|
) {
|
||||||
|
$roleTag.text("分销商 / 专家");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
layer.msg("获取用户信息失败", { icon: 2 });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply for distribution
|
||||||
|
window.applyDistribution = function () {
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
layer.confirm(
|
||||||
|
"确定要申请成为分销商吗?",
|
||||||
|
{
|
||||||
|
title: "申请分销",
|
||||||
|
btn: ["确定申请", "取消"],
|
||||||
|
btnAlign: "c",
|
||||||
|
},
|
||||||
|
function (index) {
|
||||||
|
layer.close(index);
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/user/applyDistribution",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: CommonUtil.authHeaders(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then(function (res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(
|
||||||
|
"申请成功!",
|
||||||
|
{ icon: 1, time: 2000 },
|
||||||
|
function () {
|
||||||
|
loadUserDetail();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || "申请失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply for expert
|
||||||
|
window.applyExpert = function () {
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
layer.confirm(
|
||||||
|
"确定要申请成为专家吗?",
|
||||||
|
{
|
||||||
|
title: "申请专家",
|
||||||
|
btn: ["确定申请", "取消"],
|
||||||
|
btnAlign: "c",
|
||||||
|
},
|
||||||
|
function (index) {
|
||||||
|
layer.close(index);
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/user/applyExpert",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: CommonUtil.authHeaders(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then(function (res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(
|
||||||
|
"申请成功!",
|
||||||
|
{ icon: 1, time: 2000 },
|
||||||
|
function () {
|
||||||
|
loadUserDetail();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || "申请失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,278 @@
|
|||||||
|
<!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>
|
||||||
|
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/fufei.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged pay-hidden">
|
||||||
|
<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 class="page-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a>
|
||||||
|
<span class="sep">></span>
|
||||||
|
<span>发布付费文章</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="pay-publish-card">
|
||||||
|
<header class="pay-publish-header">
|
||||||
|
<h1>发布文章</h1>
|
||||||
|
<p>发布您的付费预测方案,与彩民分享您的专业判断</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="pay-publish-body">
|
||||||
|
<div class="publish-tab-bar">
|
||||||
|
<a href="fabumianfeiwenzhang.html" class="publish-tab-item"
|
||||||
|
>发布免费文章</a
|
||||||
|
>
|
||||||
|
<a href="fufei.html" class="publish-tab-item active"
|
||||||
|
>发布付费文章</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-form">
|
||||||
|
<div class="pay-form-group mianfeiThreeSelect">
|
||||||
|
<label class="pay-form-label"
|
||||||
|
>彩种方案 <span class="required">*</span></label
|
||||||
|
>
|
||||||
|
<input type="hidden" id="a1" value="" name="topid" />
|
||||||
|
<input type="hidden" id="a2" value="" name="seid" />
|
||||||
|
<input type="hidden" id="a3" value="" name="thid" />
|
||||||
|
<input type="hidden" id="qi" value="" name="qi" />
|
||||||
|
<input type="hidden" id="vv" value="" name="vv" />
|
||||||
|
<input type="hidden" id="payMenuId" value="" />
|
||||||
|
<input type="hidden" id="payCode" value="" />
|
||||||
|
<input type="hidden" id="gmjl" value="" />
|
||||||
|
</div>
|
||||||
|
<div class="mianfeiThreeText">
|
||||||
|
<div class="pay-form-group">
|
||||||
|
<label class="pay-form-label">方案标题 <span class="required">*</span></label>
|
||||||
|
<div class="pay-title-input">
|
||||||
|
<input class="pay-form-input" id="payTitle" maxlength="100" placeholder="请输入付费文章标题" />
|
||||||
|
<span id="payTitleCount">0/100</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-pool-section">
|
||||||
|
<div class="pay-pool-title">选号区域</div>
|
||||||
|
<div class="number-pool" id="numberPool"></div>
|
||||||
|
<div class="pay-selected-row mianfeiThreeTextSelectBox">
|
||||||
|
<span class="pay-selected-label">已选:</span>
|
||||||
|
<span id="jieguo">暂无号码</span>
|
||||||
|
<button id="resetBtn" type="button" class="pay-reset-btn">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="pay-issue-row mianfeiThreeTextISSUEBox">
|
||||||
|
<span>当前期号:</span>
|
||||||
|
<strong id="qihao">请选择方案</strong>
|
||||||
|
</div>
|
||||||
|
<div id="finalResult" class="pay-hidden"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-info-grid">
|
||||||
|
<div class="pay-form-group">
|
||||||
|
<label class="pay-form-label">预测期号</label>
|
||||||
|
<input
|
||||||
|
class="pay-form-input"
|
||||||
|
id="expectInput"
|
||||||
|
placeholder="选择方案后自动获取"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
<div class="pay-form-help" id="expectText">
|
||||||
|
选择方案后自动获取
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-form-group">
|
||||||
|
<label class="pay-form-label">定金</label>
|
||||||
|
<div class="pay-price-input">
|
||||||
|
<input
|
||||||
|
class="pay-form-input"
|
||||||
|
type="text"
|
||||||
|
id="priceInput"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
<span>积分</span>
|
||||||
|
</div>
|
||||||
|
<div class="pay-form-help">
|
||||||
|
当前方案定金:<em id="priceText">0</em> 积分
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-form-group">
|
||||||
|
<label class="pay-form-label">价格说明</label>
|
||||||
|
<div class="pay-price-info" id="payPriceInfo">请选择方案后加载价格说明</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mianfeiThreeButBox">
|
||||||
|
<button
|
||||||
|
class="pay-submit-btn mianfeiThreeBut"
|
||||||
|
type="button"
|
||||||
|
onclick="chk()"
|
||||||
|
>
|
||||||
|
发布方案
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
class="fufei-footer-link"
|
||||||
|
>工信部备案号</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 src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../public/js/lay-config.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../public/js/jquery.js"></script>
|
||||||
|
<script src="../public/js/fufei-3dyjs-publish.js"></script>
|
||||||
|
<script>
|
||||||
|
function isApiSuccess(res) {
|
||||||
|
return (
|
||||||
|
res && (res.code === 0 || res.code === 200 || res.success === true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeText(value) {
|
||||||
|
return CommonUtil.escapeHtml
|
||||||
|
? CommonUtil.escapeHtml(value)
|
||||||
|
: String(value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.href = "login.html";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLoginState() {
|
||||||
|
var $ = layui.$;
|
||||||
|
var token = CommonUtil.getAuthToken
|
||||||
|
? CommonUtil.getAuthToken()
|
||||||
|
: localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").addClass("pay-hidden").hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").removeClass("pay-hidden").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
$("#userName").text(data.nickName || data.username || "用户");
|
||||||
|
$("#userLevel").text(
|
||||||
|
CommonUtil.getUserLevelText
|
||||||
|
? CommonUtil.getUserLevelText(data)
|
||||||
|
: "会员",
|
||||||
|
);
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTopNav() {
|
||||||
|
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
|
||||||
|
if (!isApiSuccess(res)) return;
|
||||||
|
var list = ApiClient.asArray(ApiClient.pickData(res, []));
|
||||||
|
var $nav = layui.$("#navLotteryItems");
|
||||||
|
$nav.empty();
|
||||||
|
list.forEach(function (item) {
|
||||||
|
var code = item.suoxie || item.code || item.id || "";
|
||||||
|
var name = item.name || item.menuName || item.lotteryName || "";
|
||||||
|
if (!code || !name) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code) +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
safeText(name) +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layui.use(["jquery", "layer"], function () {
|
||||||
|
var $ = layui.$;
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
renderLoginState();
|
||||||
|
renderTopNav();
|
||||||
|
});
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$("#backTop").toggleClass("is-visible", $(window).scrollTop() > 320);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
<!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/gonggao.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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="gonggaolist.html">网站公告</a><span class="sep">></span>
|
||||||
|
<span>公告详情</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-notice-card">
|
||||||
|
<div class="cxz-notice-header">
|
||||||
|
<h1 class="cxz-notice-title" id="noticeTitle">加载中...</h1>
|
||||||
|
<div class="cxz-notice-meta" id="noticeTime">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-notice-body" id="noticeContent">
|
||||||
|
<p style="text-align: center; color: var(--text-muted)">加载中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-back-bar">
|
||||||
|
<a href="gonggaolist.html" class="cxz-back-btn">返回公告列表</a>
|
||||||
|
</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.$;
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const noticeId = urlParams.get("id") || "";
|
||||||
|
|
||||||
|
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");
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadNotice() {
|
||||||
|
ApiClient.post("/api/web/notice/getDetail?id=" + noticeId).then(
|
||||||
|
function (res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
renderNotice(res.data);
|
||||||
|
} else {
|
||||||
|
layui.layer.msg("公告不存在", { icon: 2 });
|
||||||
|
$("#noticeTitle").text("公告不存在");
|
||||||
|
$("#noticeContent").html(
|
||||||
|
'<p style="text-align:center;color:var(--text-muted);">该公告不存在或已删除</p>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNotice(data) {
|
||||||
|
$("#noticeTitle").text(data.noticeTitle || "无标题");
|
||||||
|
if (data.createTime) {
|
||||||
|
$("#noticeTime").text(
|
||||||
|
"发布时间:" + DateUtil.formatDateToYearMonthDay(data.createTime),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$("#noticeContent").html(data.noticeContent || "");
|
||||||
|
document.title = "彩先知 - " + (data.noticeTitle || "公告详情");
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
if (noticeId) {
|
||||||
|
loadNotice();
|
||||||
|
} else {
|
||||||
|
layui.layer.msg("公告ID不存在", { icon: 2 });
|
||||||
|
$("#noticeTitle").text("参数错误");
|
||||||
|
$("#noticeContent").html(
|
||||||
|
'<p style="text-align:center;color:var(--text-muted);">缺少公告ID参数</p>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
renderNav();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
<!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/gonggao.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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<span>网站公告</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-section-header">
|
||||||
|
<div class="cxz-section-title">网站公告</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-notice-list" id="noticeList">
|
||||||
|
<div class="cxz-notice-item">
|
||||||
|
<span style="color: var(--text-muted)">加载中...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="pagination"></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.$;
|
||||||
|
let currentPage = 1;
|
||||||
|
const pageSize = 20;
|
||||||
|
|
||||||
|
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 notice list
|
||||||
|
function loadNotices() {
|
||||||
|
ApiClient.post("/api/web/notice/getPageList", {
|
||||||
|
pageNum: currentPage,
|
||||||
|
pageSize: pageSize,
|
||||||
|
}).then(function (res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
renderNotices(res.data.records || []);
|
||||||
|
renderPagination(res.data.totalRow || 0);
|
||||||
|
} else {
|
||||||
|
$("#noticeList").html(
|
||||||
|
'<div class="cxz-notice-item"><span style="color:var(--text-muted);">暂无公告</span></div>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNotices(list) {
|
||||||
|
const $container = $("#noticeList");
|
||||||
|
$container.empty();
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
$container.html(
|
||||||
|
'<div class="cxz-notice-item"><span style="color:var(--text-muted);">暂无公告</span></div>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
let displayDate = "";
|
||||||
|
if (item.createTime) displayDate = item.createTime.substring(0, 10);
|
||||||
|
else if (item.date) displayDate = item.date.substring(0, 10);
|
||||||
|
|
||||||
|
$container.append(
|
||||||
|
'<div class="cxz-notice-item">' +
|
||||||
|
'<a href="gonggao.html?id=' +
|
||||||
|
(item.id || "") +
|
||||||
|
'">' +
|
||||||
|
'<span class="cxz-notice-dot"></span>' +
|
||||||
|
(item.noticeTitle || "无标题") +
|
||||||
|
"</a>" +
|
||||||
|
'<span class="cxz-notice-date">' +
|
||||||
|
displayDate +
|
||||||
|
"</span>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(total) {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "pagination",
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPage,
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) {
|
||||||
|
currentPage = obj.curr;
|
||||||
|
loadNotices();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
loadNotices();
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
renderNav();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,929 @@
|
|||||||
|
<!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>
|
||||||
|
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/index.css" />
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../public/js/qrcode.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="./" 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 is-active">首页</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 class="page-shell">
|
||||||
|
<section class="hero">
|
||||||
|
<div class="hero__inner">
|
||||||
|
<div class="hero__main">
|
||||||
|
<!-- <div class="panel-head panel-head--hero">
|
||||||
|
<div>
|
||||||
|
<h1>彩先知 PC 预测首页</h1>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="hero__history-btn"
|
||||||
|
type="button"
|
||||||
|
onclick="openHistoryModal()"
|
||||||
|
>
|
||||||
|
<img src="../images/home-icon-history.png" alt="" />
|
||||||
|
<span>历史查询</span>
|
||||||
|
</button>
|
||||||
|
</div> -->
|
||||||
|
<div class="hero__carousel-wrap">
|
||||||
|
<div class="layui-carousel" id="bannerCarousel">
|
||||||
|
<div carousel-item id="bannerBox"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside class="hero__side">
|
||||||
|
<div class="hero-card hero-card--focus">
|
||||||
|
<div class="hero-card__title">
|
||||||
|
<img src="../images/home-icon-calendar.png" alt="" />
|
||||||
|
<span>开奖焦点</span>
|
||||||
|
</div>
|
||||||
|
<div class="hero-focus-list" id="heroFocusList"></div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="section-divider section-divider--blue">
|
||||||
|
<span>彩票分类导航</span>
|
||||||
|
<!-- <p>八大彩种统一入口,快速进入对应文章与数据页</p> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="lottery-nav">
|
||||||
|
<div class="lottery-nav__inner" id="lotteryNavGrid"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="section-divider section-divider--gold">
|
||||||
|
<span>最新开奖与免费文章</span>
|
||||||
|
<!-- <p>开奖结果、开奖日期、专家推荐文章同步聚合展示</p> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="draw">
|
||||||
|
<div class="draw__inner">
|
||||||
|
<div class="draw__header">
|
||||||
|
<div class="draw__title">
|
||||||
|
<img src="../images/home-icon-history.png" alt="" />
|
||||||
|
<div>
|
||||||
|
<strong>最新开奖</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="draw__grid" id="resultsGrid"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="content">
|
||||||
|
<div class="content__inner">
|
||||||
|
<aside class="content__rail">
|
||||||
|
<div class="sidebar-card">
|
||||||
|
<div class="sidebar-card__head sidebar-card__head--navy">
|
||||||
|
<span>平台公告</span>
|
||||||
|
<a href="gonggaolist.html" class="sidebar-card__more">更多</a>
|
||||||
|
</div>
|
||||||
|
<ul class="notice-list" id="noticeList"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-card">
|
||||||
|
<div class="sidebar-card__head sidebar-card__head--gold">
|
||||||
|
<span>APP下载</span>
|
||||||
|
</div>
|
||||||
|
<div class="qrcode-box">
|
||||||
|
<img id="downloadQrImg" alt="二维码" />
|
||||||
|
<p>打开手机浏览器扫描二维码</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-card">
|
||||||
|
<div class="sidebar-card__head sidebar-card__head--teal">
|
||||||
|
<span>走势图</span>
|
||||||
|
</div>
|
||||||
|
<div class="trend-grid" id="trendGrid"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-card combo-tool-card">
|
||||||
|
<div class="sidebar-card__head sidebar-card__head--gold">
|
||||||
|
<span>组合工具</span>
|
||||||
|
</div>
|
||||||
|
<div class="combo-tool-grid">
|
||||||
|
<a href="duanzuhe.html" class="combo-tool-item">
|
||||||
|
<img src="../images/icon-duanzuhe.png" alt="断组合" />
|
||||||
|
<span>断组合</span>
|
||||||
|
</a>
|
||||||
|
<a href="shazuhe.html" class="combo-tool-item">
|
||||||
|
<img src="../images/icon-shazuhe.png" alt="杀组合" />
|
||||||
|
<span>杀组合</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<section class="content__main">
|
||||||
|
<div class="article-matrix" id="articleGroups"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<aside class="content__ads">
|
||||||
|
<div id="sidebarAdContainer"></div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="resource-section">
|
||||||
|
<div class="resource-section__inner">
|
||||||
|
<div class="resource-card">
|
||||||
|
<div class="resource-card__head">
|
||||||
|
<img src="../images/home-icon-article.png" alt="" />
|
||||||
|
<h2>其它推荐</h2>
|
||||||
|
</div>
|
||||||
|
<div class="resource-card__body" id="otherRecommend"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="resource-card">
|
||||||
|
<div class="resource-card__head">
|
||||||
|
<img src="../images/home-icon-link.png" alt="" />
|
||||||
|
<h2>友情链接</h2>
|
||||||
|
</div>
|
||||||
|
<div class="resource-card__body" id="friendLinks"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">
|
||||||
|
彩先知以开奖数据、免费文章、资讯推荐为核心,提供清晰、密集、分层的 PC
|
||||||
|
端彩票信息首页。
|
||||||
|
</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,.5)">工信部:蜀ICP备2024044594号-4</a>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考,不构成任何投注建议</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var $ = layui.$;
|
||||||
|
var token = localStorage.getItem("token");
|
||||||
|
var lotteryOrder = [
|
||||||
|
"双色球",
|
||||||
|
"大乐透",
|
||||||
|
"福彩3D",
|
||||||
|
"排列三",
|
||||||
|
"排列五",
|
||||||
|
"快乐8",
|
||||||
|
"七乐彩",
|
||||||
|
"七星彩",
|
||||||
|
];
|
||||||
|
var currentLotteryMenu = [];
|
||||||
|
var lotteryAliasMap = {
|
||||||
|
排列3: "排列三",
|
||||||
|
排列三: "排列三",
|
||||||
|
排列5: "排列五",
|
||||||
|
排列五: "排列五",
|
||||||
|
};
|
||||||
|
var lotteryIconMap = {
|
||||||
|
双色球: {
|
||||||
|
icon: "../images/icon-ssq.png",
|
||||||
|
color: "red",
|
||||||
|
blueColor: "blue",
|
||||||
|
code: "ssq",
|
||||||
|
accent: "#ff5d6c",
|
||||||
|
},
|
||||||
|
大乐透: {
|
||||||
|
icon: "../images/icon-dlt.png",
|
||||||
|
color: "blue",
|
||||||
|
blueColor: "gold",
|
||||||
|
code: "cjdlt",
|
||||||
|
accent: "#4f8cff",
|
||||||
|
},
|
||||||
|
福彩3D: {
|
||||||
|
icon: "../images/icon-fc3d.png",
|
||||||
|
color: "orange",
|
||||||
|
blueColor: "orange",
|
||||||
|
code: "fc3d",
|
||||||
|
accent: "#ff9a3d",
|
||||||
|
},
|
||||||
|
排列三: {
|
||||||
|
icon: "../images/icon-pl3.png",
|
||||||
|
color: "green",
|
||||||
|
blueColor: "green",
|
||||||
|
code: "pl3",
|
||||||
|
accent: "#37c28f",
|
||||||
|
},
|
||||||
|
排列五: {
|
||||||
|
icon: "../images/icon-pl5.png",
|
||||||
|
color: "purple",
|
||||||
|
blueColor: "purple",
|
||||||
|
code: "pl5",
|
||||||
|
accent: "#8d62ff",
|
||||||
|
},
|
||||||
|
快乐8: {
|
||||||
|
icon: "../images/icon-kl8.png",
|
||||||
|
color: "gold",
|
||||||
|
blueColor: "gold",
|
||||||
|
code: "kl8",
|
||||||
|
accent: "#fdb933",
|
||||||
|
},
|
||||||
|
七乐彩: {
|
||||||
|
icon: "../images/icon-qlc.png",
|
||||||
|
color: "teal",
|
||||||
|
blueColor: "blue",
|
||||||
|
code: "qlc",
|
||||||
|
accent: "#29b6b0",
|
||||||
|
},
|
||||||
|
七星彩: {
|
||||||
|
icon: "../images/icon-qxc.png",
|
||||||
|
color: "violet",
|
||||||
|
blueColor: "violet",
|
||||||
|
code: "qxc",
|
||||||
|
accent: "#b06dff",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var fallbackAvatars = [
|
||||||
|
"../images/home-avatar-1.png",
|
||||||
|
"../images/home-avatar-2.png",
|
||||||
|
"../images/home-avatar-3.png",
|
||||||
|
"../images/home-avatar-4.png",
|
||||||
|
"../images/home-avatar-5.png",
|
||||||
|
"../images/home-avatar-6.png",
|
||||||
|
"../images/home-avatar-7.png",
|
||||||
|
"../images/home-avatar-8.png",
|
||||||
|
];
|
||||||
|
var historyCache = {};
|
||||||
|
|
||||||
|
function normalizeLotteryName(name) {
|
||||||
|
return lotteryAliasMap[name] || name || "";
|
||||||
|
}
|
||||||
|
function escapeHtml(text) {
|
||||||
|
return String(text || "").replace(/[&<>"']/g, function (char) {
|
||||||
|
return {
|
||||||
|
"&": "&",
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
'"': """,
|
||||||
|
"'": "'",
|
||||||
|
}[char];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function formatDateValue(value) {
|
||||||
|
if (!value) return "--";
|
||||||
|
var date = new Date(value);
|
||||||
|
if (isNaN(date.getTime()))
|
||||||
|
return typeof value === "string" && value.length >= 10
|
||||||
|
? value.substring(0, 10)
|
||||||
|
: String(value);
|
||||||
|
var year = date.getFullYear();
|
||||||
|
var month = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
|
var day = String(date.getDate()).padStart(2, "0");
|
||||||
|
return year + "-" + month + "-" + day;
|
||||||
|
}
|
||||||
|
function formatDateLabel(value) {
|
||||||
|
var date = new Date(value);
|
||||||
|
if (isNaN(date.getTime())) return formatDateValue(value);
|
||||||
|
return (
|
||||||
|
date.getFullYear() +
|
||||||
|
"年" +
|
||||||
|
(date.getMonth() + 1) +
|
||||||
|
"月" +
|
||||||
|
date.getDate() +
|
||||||
|
"日"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function sortLotteries(menuList) {
|
||||||
|
return (menuList || [])
|
||||||
|
.slice()
|
||||||
|
.map(function (item) {
|
||||||
|
var copy = $.extend(true, {}, item);
|
||||||
|
copy.name = normalizeLotteryName(copy.name);
|
||||||
|
return copy;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getResultDate(item) {
|
||||||
|
return item && item.lotteryResult
|
||||||
|
? item.lotteryResult.time ||
|
||||||
|
item.lotteryResult.createTime ||
|
||||||
|
item.lotteryResult.date ||
|
||||||
|
""
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
function getResultPeriod(item) {
|
||||||
|
return item && item.lotteryResult
|
||||||
|
? item.lotteryResult.expect || item.lotteryResult.name || ""
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
function buildBallHtml(openCode, cfg, compact) {
|
||||||
|
if (!openCode) return '<span class="ball ball--empty">--</span>';
|
||||||
|
var html = "";
|
||||||
|
var parts = String(openCode).split("+");
|
||||||
|
$.each(parts[0] ? parts[0].split(",") : [], function (_, ball) {
|
||||||
|
html +=
|
||||||
|
'<span class="ball ball--' +
|
||||||
|
cfg.color +
|
||||||
|
(compact ? " ball--compact" : "") +
|
||||||
|
'">' +
|
||||||
|
escapeHtml($.trim(ball)) +
|
||||||
|
"</span>";
|
||||||
|
});
|
||||||
|
for (var i = 1; i < parts.length; i++) {
|
||||||
|
$.each(parts[i].split(","), function (_, ball) {
|
||||||
|
html +=
|
||||||
|
'<span class="ball ball--' +
|
||||||
|
cfg.blueColor +
|
||||||
|
(compact ? " ball--compact" : "") +
|
||||||
|
'">' +
|
||||||
|
escapeHtml($.trim(ball)) +
|
||||||
|
"</span>";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return html || '<span class="ball ball--empty">--</span>';
|
||||||
|
}
|
||||||
|
function renderBannerImages(bannerData) {
|
||||||
|
var $box = $("#bannerBox");
|
||||||
|
$box.empty();
|
||||||
|
if (!bannerData || !bannerData.length) {
|
||||||
|
$box.append(
|
||||||
|
'<div class="banner-fallback"><div class="banner-fallback__content"><span>暂无轮播数据</span><strong>彩先知 · 专注开奖与文章聚合</strong></div></div>',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$.each(bannerData, function (_, item) {
|
||||||
|
$box.append(
|
||||||
|
'<div><a href="' +
|
||||||
|
escapeHtml(item.link || "#") +
|
||||||
|
'" target="_blank" rel="noopener noreferrer" class="banner-link"><img class="carousel-img" src="' +
|
||||||
|
escapeHtml(item.touxiang || "") +
|
||||||
|
'" alt="轮播图" loading="lazy" /></a></div>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
layui.use(["carousel"], function () {
|
||||||
|
layui.carousel.render({
|
||||||
|
elem: "#bannerCarousel",
|
||||||
|
interval: 5000,
|
||||||
|
anim: "fade",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
autoplay: true,
|
||||||
|
indicator: "inside",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderHeroSummary(menuList, noticeList) {
|
||||||
|
var articleCount = 0;
|
||||||
|
$.each(menuList, function (_, item) {
|
||||||
|
articleCount += (item.freeArticleList || []).slice(0, 5).length;
|
||||||
|
});
|
||||||
|
$("#heroLotteryCount").text(menuList.length);
|
||||||
|
$("#heroArticleCount").text(articleCount);
|
||||||
|
$("#heroNoticeCount").text((noticeList || []).length);
|
||||||
|
$("#heroMetaGrid").html(
|
||||||
|
[
|
||||||
|
'<div class="hero-meta"><span>彩种排序</span><strong>8 组固定顺序</strong><em>双色球至七星彩</em></div>',
|
||||||
|
'<div class="hero-meta"><span>免费文章</span><strong>' +
|
||||||
|
articleCount +
|
||||||
|
" 篇</strong><em>每组展示 5 篇以内</em></div>",
|
||||||
|
'<div class="hero-meta"><span>数据来源</span><strong>/api/web/index</strong><em>首页主数据接口</em></div>',
|
||||||
|
].join(""),
|
||||||
|
);
|
||||||
|
var $focus = $("#heroFocusList");
|
||||||
|
$focus.empty();
|
||||||
|
$.each(menuList.slice(0, 4), function (_, item) {
|
||||||
|
var name = item.name || "";
|
||||||
|
var cfg = lotteryIconMap[name] || lotteryIconMap["双色球"];
|
||||||
|
$focus.append(
|
||||||
|
'<a href="kaijiang.html?suoxie=' +
|
||||||
|
cfg.code +
|
||||||
|
'" class="hero-focus-item"><img src="' +
|
||||||
|
cfg.icon +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(name) +
|
||||||
|
'" /><div><strong>' +
|
||||||
|
escapeHtml(name) +
|
||||||
|
"</strong><span>第 " +
|
||||||
|
escapeHtml(getResultPeriod(item) || "--") +
|
||||||
|
" 期 · " +
|
||||||
|
escapeHtml(formatDateValue(getResultDate(item))) +
|
||||||
|
"</span></div></a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (!$focus.children().length)
|
||||||
|
$focus.html('<div class="hero-focus-empty">暂无开奖焦点数据</div>');
|
||||||
|
}
|
||||||
|
function renderDynamicNav(menuList) {
|
||||||
|
var sortedList = sortLotteries(menuList);
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
var $grid = $("#lotteryNavGrid");
|
||||||
|
var $trend = $("#trendGrid");
|
||||||
|
$nav.find(".topbar__nav-link").not(":first").remove();
|
||||||
|
$grid.empty();
|
||||||
|
$trend.empty();
|
||||||
|
$.each(sortedList, function (_, item) {
|
||||||
|
var cfg = lotteryIconMap[item.name];
|
||||||
|
if (!cfg) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
cfg.code +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
$grid.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
cfg.code +
|
||||||
|
'" class="lottery-nav__card" style="--accent:' +
|
||||||
|
cfg.accent +
|
||||||
|
'"><div class="lottery-nav__icon"><img src="' +
|
||||||
|
cfg.icon +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
'" /></div><div class="lottery-nav__text"><strong>' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
"</strong><span>进入预测文章</span></div><em>查看</em></a>",
|
||||||
|
);
|
||||||
|
$trend.append(
|
||||||
|
'<a href="' +
|
||||||
|
cfg.code +
|
||||||
|
'.html" class="trend-item"><img src="' +
|
||||||
|
cfg.icon +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
'" /><span>' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
"</span></a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function updateResultsGrid(menuList) {
|
||||||
|
var $grid = $("#resultsGrid");
|
||||||
|
$grid.empty();
|
||||||
|
$.each(sortLotteries(menuList), function (_, item) {
|
||||||
|
var cfg = lotteryIconMap[item.name] || lotteryIconMap["双色球"];
|
||||||
|
var result = item.lotteryResult || {};
|
||||||
|
var compact = item.name === "快乐8";
|
||||||
|
$grid.append(
|
||||||
|
'<div class="draw-card" style="--accent:' +
|
||||||
|
cfg.accent +
|
||||||
|
'"><div class="draw-card__head"><div class="draw-card__title"><img src="' +
|
||||||
|
cfg.icon +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
'" /><div><strong>' +
|
||||||
|
escapeHtml(item.name) +
|
||||||
|
"</strong><span>第 " +
|
||||||
|
escapeHtml(result.expect || result.name || "--") +
|
||||||
|
' 期</span></div></div><a class="draw-card__link" href="kaijiang.html?suoxie=' +
|
||||||
|
cfg.code +
|
||||||
|
'">历史开奖</a></div><div class="draw-card__balls' +
|
||||||
|
(compact ? " draw-card__balls--compact" : "") +
|
||||||
|
'">' +
|
||||||
|
buildBallHtml(result.openCode || "", cfg, compact) +
|
||||||
|
'</div><div class="draw-card__foot"><span>开奖日期</span><strong>' +
|
||||||
|
escapeHtml(
|
||||||
|
formatDateLabel(
|
||||||
|
result.time || result.createTime || result.date || "",
|
||||||
|
),
|
||||||
|
) +
|
||||||
|
"</strong></div></div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderNoticeList(noticeData) {
|
||||||
|
var $container = $("#noticeList");
|
||||||
|
$container.empty();
|
||||||
|
$.each((noticeData || []).slice(0, 6), function (_, notice) {
|
||||||
|
$container.append(
|
||||||
|
'<li class="notice-item"><a href="gonggao.html?id=' +
|
||||||
|
escapeHtml(notice.id || "") +
|
||||||
|
'" target="_blank">' +
|
||||||
|
escapeHtml(notice.noticeTitle || notice.content || "公告信息") +
|
||||||
|
"</a></li>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (!$container.children().length)
|
||||||
|
$container.html(
|
||||||
|
'<li class="notice-item notice-item--empty">暂无公告</li>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderChannelSections(menuList) {
|
||||||
|
var $container = $("#articleGroups");
|
||||||
|
$container.empty();
|
||||||
|
$.each(sortLotteries(menuList), function (index, lottery) {
|
||||||
|
var articles = (lottery.freeArticleList || []).slice(0, 5);
|
||||||
|
var cfg = lotteryIconMap[lottery.name] || lotteryIconMap["双色球"];
|
||||||
|
var listHtml = "";
|
||||||
|
$.each(articles, function (_, article) {
|
||||||
|
listHtml +=
|
||||||
|
`<li class="article-item"><img src="${article.accountAvatar || article.expertAvatar}" alt="" class="article-item__icon" /><a class="article-item__link" href="` +
|
||||||
|
CommonUtil.freeArticleHref(article.id || "") +
|
||||||
|
'" target="_blank">' +
|
||||||
|
escapeHtml(article.title || "文章标题") +
|
||||||
|
"</a></li>";
|
||||||
|
});
|
||||||
|
if (!listHtml)
|
||||||
|
listHtml =
|
||||||
|
'<li class="article-item article-item--empty"><span>暂无免费文章</span></li>';
|
||||||
|
$container.append(
|
||||||
|
'<section class="article-cluster" style="--accent:' +
|
||||||
|
cfg.accent +
|
||||||
|
'"><div class="article-cluster__head"><div class="article-cluster__title"><img src="' +
|
||||||
|
cfg.icon +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(lottery.name) +
|
||||||
|
'" /><div><strong>' +
|
||||||
|
escapeHtml(lottery.name) +
|
||||||
|
'</strong></div></div><a class="article-cluster__more" href="mianfeilist.html?id=' +
|
||||||
|
escapeHtml(lottery.id || "") +
|
||||||
|
'">更多文章</a></div><ul class="article-cluster__list">' +
|
||||||
|
listHtml +
|
||||||
|
"</ul></section>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderResourceLinks($container, list) {
|
||||||
|
$container.empty();
|
||||||
|
if (!list.length) {
|
||||||
|
$container.html('<span class="resource-empty">暂无数据</span>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (_, item) {
|
||||||
|
$container.append(
|
||||||
|
'<a class="resource-link" href="' +
|
||||||
|
escapeHtml(item.url || "#") +
|
||||||
|
'" target="_blank" rel="noopener noreferrer"><img src="../images/home-icon-link.png" alt="" /><span>' +
|
||||||
|
escapeHtml(item.name || "链接标题") +
|
||||||
|
"</span></a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderCompatLinks($container, list) {
|
||||||
|
$container.empty();
|
||||||
|
$.each(list, function (_, item) {
|
||||||
|
$container.append(
|
||||||
|
'<li class="link-listLi"><a href="' +
|
||||||
|
escapeHtml(item.url || "#") +
|
||||||
|
'" target="_blank"><div class="link-listLiText">' +
|
||||||
|
escapeHtml(item.name || "链接标题") +
|
||||||
|
"</div></a></li>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderRecommendGrid(linkList) {
|
||||||
|
var list = (linkList || []).filter(function (item) {
|
||||||
|
return item.type === 1;
|
||||||
|
});
|
||||||
|
renderResourceLinks($("#otherRecommend"), list);
|
||||||
|
renderCompatLinks($("#otherRecommendCompat"), list);
|
||||||
|
}
|
||||||
|
function renderLinksGrid(linkList) {
|
||||||
|
var list = (linkList || []).filter(function (item) {
|
||||||
|
return item.type === 2;
|
||||||
|
});
|
||||||
|
renderResourceLinks($("#friendLinks"), list);
|
||||||
|
renderCompatLinks($("#friendLinksCompat"), list);
|
||||||
|
}
|
||||||
|
function renderAdGroups(adList) {
|
||||||
|
var $container = $("#sidebarAdContainer");
|
||||||
|
$container.empty();
|
||||||
|
var validAds = CommonUtil.filterValidAds(adList || []);
|
||||||
|
if (!validAds.length) {
|
||||||
|
$container.html(
|
||||||
|
'<div class="ad-group ad-group--empty">暂无广告数据</div>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < validAds.length; i += 8) {
|
||||||
|
var html = "";
|
||||||
|
$.each(validAds.slice(i, i + 8), function (_, ad) {
|
||||||
|
html +=
|
||||||
|
'<a href="' +
|
||||||
|
escapeHtml(ad.link || "#") +
|
||||||
|
'" target="_blank" rel="noopener noreferrer" class="ad-item"><img src="' +
|
||||||
|
escapeHtml(ad.touxiang || "") +
|
||||||
|
'" alt="' +
|
||||||
|
escapeHtml(ad.title || "广告") +
|
||||||
|
'" loading="lazy" /></a>';
|
||||||
|
});
|
||||||
|
$container.append(
|
||||||
|
'<section class="ad-group">' +
|
||||||
|
'<div class="ad-group__grid">' +
|
||||||
|
html +
|
||||||
|
"</div></section>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getDefaultHistoryRange() {
|
||||||
|
var end = new Date();
|
||||||
|
var start = new Date();
|
||||||
|
start.setDate(end.getDate() - 30);
|
||||||
|
return { start: formatDateValue(start), end: formatDateValue(end) };
|
||||||
|
}
|
||||||
|
function openHistoryModal() {
|
||||||
|
var options = "";
|
||||||
|
var sourceList = currentLotteryMenu.length
|
||||||
|
? currentLotteryMenu
|
||||||
|
: lotteryOrder.map(function (name) {
|
||||||
|
return { name: name };
|
||||||
|
});
|
||||||
|
$.each(sourceList, function (_, item) {
|
||||||
|
var name = normalizeLotteryName(item.name);
|
||||||
|
var code =
|
||||||
|
item.suoxie ||
|
||||||
|
item.code ||
|
||||||
|
(lotteryIconMap[name] ? lotteryIconMap[name].code : "");
|
||||||
|
if (!code || !lotteryIconMap[name]) return;
|
||||||
|
options +=
|
||||||
|
'<option value="' +
|
||||||
|
code +
|
||||||
|
'">' +
|
||||||
|
name +
|
||||||
|
"</option>";
|
||||||
|
});
|
||||||
|
$("#historyLotterySelect").html(options);
|
||||||
|
var range = getDefaultHistoryRange();
|
||||||
|
$("#historyStartDate").val(range.start);
|
||||||
|
$("#historyEndDate").val(range.end);
|
||||||
|
$("#historyModal").addClass("is-open");
|
||||||
|
searchHistory();
|
||||||
|
}
|
||||||
|
function closeHistoryModal() {
|
||||||
|
$("#historyModal").removeClass("is-open");
|
||||||
|
}
|
||||||
|
function resolveLotteryNameByCode(code) {
|
||||||
|
var found = "";
|
||||||
|
$.each(lotteryIconMap, function (name, cfg) {
|
||||||
|
if (cfg.code === code) found = name;
|
||||||
|
});
|
||||||
|
return found || code;
|
||||||
|
}
|
||||||
|
function renderHistoryRows(code, list) {
|
||||||
|
var $body = $("#historyTableBody");
|
||||||
|
$body.empty();
|
||||||
|
if (!list.length) {
|
||||||
|
$body.html(
|
||||||
|
'<tr><td colspan="4" class="is-empty">暂无历史开奖数据</td></tr>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list.slice(0, 50), function (_, item) {
|
||||||
|
$body.append(
|
||||||
|
"<tr><td>" +
|
||||||
|
escapeHtml(resolveLotteryNameByCode(code)) +
|
||||||
|
"</td><td>" +
|
||||||
|
escapeHtml(item.expect || item.name || "--") +
|
||||||
|
'</td><td class="history-code">' +
|
||||||
|
escapeHtml(item.openCode || "--") +
|
||||||
|
"</td><td>" +
|
||||||
|
escapeHtml(
|
||||||
|
formatDateValue(
|
||||||
|
item.date || item.time || item.createTime || "",
|
||||||
|
),
|
||||||
|
) +
|
||||||
|
"</td></tr>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function searchHistory() {
|
||||||
|
var code = $("#historyLotterySelect").val();
|
||||||
|
var startDate = $("#historyStartDate").val();
|
||||||
|
var endDate = $("#historyEndDate").val();
|
||||||
|
if (!code) return;
|
||||||
|
function applyFilter(list) {
|
||||||
|
var filtered = (list || []).filter(function (item) {
|
||||||
|
var current = formatDateValue(
|
||||||
|
item.date || item.time || item.createTime || "",
|
||||||
|
);
|
||||||
|
if (startDate && current < startDate) return false;
|
||||||
|
if (endDate && current > endDate) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
renderHistoryRows(code, filtered);
|
||||||
|
}
|
||||||
|
if (historyCache[code]) {
|
||||||
|
applyFilter(historyCache[code]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#historyTableBody").html(
|
||||||
|
'<tr><td colspan="4" class="is-empty">正在加载历史开奖数据...</td></tr>',
|
||||||
|
);
|
||||||
|
ApiClient.post("/api/web/lotteryResult/getList", { suoxie: code })
|
||||||
|
.then(function (res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
historyCache[code] = res.data.records || res.data || [];
|
||||||
|
applyFilter(historyCache[code]);
|
||||||
|
} else {
|
||||||
|
$("#historyTableBody").html(
|
||||||
|
'<tr><td colspan="4" class="is-empty">历史开奖数据加载失败</td></tr>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
$("#historyTableBody").html(
|
||||||
|
'<tr><td colspan="4" class="is-empty">历史开奖数据加载失败</td></tr>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
function checkLoginStatus() {
|
||||||
|
if (!token) return;
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
$("#userName").text(data.nickName || "用户");
|
||||||
|
$("#userLevel").text(
|
||||||
|
String(data.isExpert) === "1" ? "专家" : "会员",
|
||||||
|
);
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function bindStaticEvents() {
|
||||||
|
$("#historyModal").on("click", function (event) {
|
||||||
|
if ($(event.target).is("#historyModal")) closeHistoryModal();
|
||||||
|
});
|
||||||
|
$(document).on("change", "#historyLotterySelect", searchHistory);
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
$(document).on("click", ".topbar__nav-link", function () {
|
||||||
|
$(".topbar__nav-link").removeClass("is-active");
|
||||||
|
$(this).addClass("is-active");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function hydrateHome(result) {
|
||||||
|
var data = result.data || {};
|
||||||
|
var sortedMenu = sortLotteries(data.menuList || []);
|
||||||
|
currentLotteryMenu = sortedMenu;
|
||||||
|
$("#currentDate").text(formatDateLabel(new Date()));
|
||||||
|
renderBannerImages(data.bannerList || []);
|
||||||
|
renderDynamicNav(sortedMenu);
|
||||||
|
updateResultsGrid(sortedMenu);
|
||||||
|
renderChannelSections(sortedMenu);
|
||||||
|
renderHeroSummary(sortedMenu, data.noticeList || []);
|
||||||
|
renderNoticeList(data.noticeList || []);
|
||||||
|
renderAdGroups(data.adList || []);
|
||||||
|
renderRecommendGrid(data.linkList || []);
|
||||||
|
renderLinksGrid(data.linkList || []);
|
||||||
|
ApiClient.post("/api/web/QRCode").then(function (res) {
|
||||||
|
if (res.code === 0 && res.data)
|
||||||
|
CommonUtil.generateQRCode(res.data, "downloadQrImg");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$(function () {
|
||||||
|
bindStaticEvents();
|
||||||
|
checkLoginStatus();
|
||||||
|
CommonUtil.loadPageConfig({
|
||||||
|
ads: false,
|
||||||
|
links: false,
|
||||||
|
onSuccess: hydrateHome,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<!-- Code injected by live-server -->
|
||||||
|
<script>
|
||||||
|
// <![CDATA[ <-- For SVG support
|
||||||
|
if ('WebSocket' in window) {
|
||||||
|
(function () {
|
||||||
|
function refreshCSS() {
|
||||||
|
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||||
|
var head = document.getElementsByTagName("head")[0];
|
||||||
|
for (var i = 0; i < sheets.length; ++i) {
|
||||||
|
var elem = sheets[i];
|
||||||
|
var parent = elem.parentElement || head;
|
||||||
|
parent.removeChild(elem);
|
||||||
|
var rel = elem.rel;
|
||||||
|
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||||
|
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||||
|
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||||
|
}
|
||||||
|
parent.appendChild(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||||
|
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||||
|
var socket = new WebSocket(address);
|
||||||
|
socket.onmessage = function (msg) {
|
||||||
|
if (msg.data == 'reload') window.location.reload();
|
||||||
|
else if (msg.data == 'refreshcss') refreshCSS();
|
||||||
|
};
|
||||||
|
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||||
|
console.log('Live reload enabled.');
|
||||||
|
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||||
|
}
|
||||||
|
// ]]>
|
||||||
|
</script>
|
||||||
|
<!-- Code injected by live-server -->
|
||||||
|
<script>
|
||||||
|
// <![CDATA[ <-- For SVG support
|
||||||
|
if ('WebSocket' in window) {
|
||||||
|
(function () {
|
||||||
|
function refreshCSS() {
|
||||||
|
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||||
|
var head = document.getElementsByTagName("head")[0];
|
||||||
|
for (var i = 0; i < sheets.length; ++i) {
|
||||||
|
var elem = sheets[i];
|
||||||
|
var parent = elem.parentElement || head;
|
||||||
|
parent.removeChild(elem);
|
||||||
|
var rel = elem.rel;
|
||||||
|
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||||
|
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||||
|
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||||
|
}
|
||||||
|
parent.appendChild(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||||
|
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||||
|
var socket = new WebSocket(address);
|
||||||
|
socket.onmessage = function (msg) {
|
||||||
|
if (msg.data == 'reload') window.location.reload();
|
||||||
|
else if (msg.data == 'refreshcss') refreshCSS();
|
||||||
|
};
|
||||||
|
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||||
|
console.log('Live reload enabled.');
|
||||||
|
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||||
|
}
|
||||||
|
// ]]>
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,595 @@
|
|||||||
|
<!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/finance.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged" style="display: none">
|
||||||
|
<a href="usercenter.html" class="topbar__profile">
|
||||||
|
<img
|
||||||
|
id="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>
|
||||||
|
|
||||||
|
<div class="je-container">
|
||||||
|
<div class="je-card">
|
||||||
|
<div class="je-tabs">
|
||||||
|
<div
|
||||||
|
class="je-tab active"
|
||||||
|
data-type="POINTS"
|
||||||
|
onclick="switchTab(this)"
|
||||||
|
>
|
||||||
|
<span class="tab-icon icon-points">P</span>积分明细
|
||||||
|
</div>
|
||||||
|
<div class="je-tab" data-type="BALANCE" onclick="switchTab(this)">
|
||||||
|
<span class="tab-icon icon-balance">B</span>余额明细
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="je-tab"
|
||||||
|
data-type="SALES_BALANCE"
|
||||||
|
onclick="switchTab(this)"
|
||||||
|
>
|
||||||
|
<span class="tab-icon icon-sales">S</span>销售余额明细
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="je-tab"
|
||||||
|
data-type="EXPERT_BALANCE"
|
||||||
|
onclick="switchTab(this)"
|
||||||
|
>
|
||||||
|
<span class="tab-icon icon-expert">E</span>专家余额明细
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="je-summary">
|
||||||
|
<div>
|
||||||
|
<div class="je-summary-label">
|
||||||
|
当前 <span id="currentTypeName">积分</span>
|
||||||
|
</div>
|
||||||
|
<div class="je-summary-value" id="currentBalance">
|
||||||
|
0<span id="currentUnit">点</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="je-summary-actions" id="summaryActions">
|
||||||
|
<a href="chongzhi.html" class="je-btn-recharge" id="btnRecharge"
|
||||||
|
>充值</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="tixian.html"
|
||||||
|
class="je-btn-withdraw"
|
||||||
|
id="btnWithdraw"
|
||||||
|
style="display: none"
|
||||||
|
>提现</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="je-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>类型</th>
|
||||||
|
<th>金额</th>
|
||||||
|
<th>操作类型</th>
|
||||||
|
<th class="balance-after-col" style="display: none">
|
||||||
|
变动后余额
|
||||||
|
</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th>时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="flowTableBody">
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="je-empty">
|
||||||
|
<div class="je-empty-icon">📋</div>
|
||||||
|
<div class="je-empty-text">加载中...</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="je-pagination" id="flowPager"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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.$;
|
||||||
|
var currentCapitalType = "POINTS";
|
||||||
|
var currentPageNum = 1;
|
||||||
|
var pageSize = 10;
|
||||||
|
var userData = null;
|
||||||
|
|
||||||
|
var typeNames = {
|
||||||
|
POINTS: "积分",
|
||||||
|
BALANCE: "余额",
|
||||||
|
SALES_BALANCE: "销售余额",
|
||||||
|
EXPERT_BALANCE: "专家余额",
|
||||||
|
};
|
||||||
|
var typeUnits = {
|
||||||
|
POINTS: "点",
|
||||||
|
BALANCE: "元",
|
||||||
|
SALES_BALANCE: "元",
|
||||||
|
EXPERT_BALANCE: "元",
|
||||||
|
};
|
||||||
|
var typeBalanceKeys = {
|
||||||
|
POINTS: "points",
|
||||||
|
BALANCE: "accountBalance",
|
||||||
|
SALES_BALANCE: "salesBalance",
|
||||||
|
EXPERT_BALANCE: "expertBalance",
|
||||||
|
};
|
||||||
|
var typeCssClass = {
|
||||||
|
POINTS: "je-capital-points",
|
||||||
|
BALANCE: "je-capital-balance",
|
||||||
|
SALES_BALANCE: "je-capital-sales",
|
||||||
|
EXPERT_BALANCE: "je-capital-expert",
|
||||||
|
};
|
||||||
|
var flowTypeMap = {
|
||||||
|
BALANCE: "",
|
||||||
|
SALES_BALANCE: "sales",
|
||||||
|
EXPERT_BALANCE: "expert",
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkAuth() {
|
||||||
|
if (CommonUtil.getAuthToken()) return true;
|
||||||
|
layui.use("layer", function () {
|
||||||
|
layui.layer.confirm(
|
||||||
|
"请先登录",
|
||||||
|
{ btn: ["去登录", "取消"] },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
window.location.href = "login.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHeaderState() {
|
||||||
|
if (!CommonUtil.getAuthToken()) {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
userData = data || {};
|
||||||
|
$("#headerUserName").text(
|
||||||
|
userData.nickName || userData.nickname || "用户",
|
||||||
|
);
|
||||||
|
$("#headerUserLevel").text(
|
||||||
|
CommonUtil.getUserLevelText
|
||||||
|
? CommonUtil.getUserLevelText(userData)
|
||||||
|
: "会员",
|
||||||
|
);
|
||||||
|
if (userData.avatar)
|
||||||
|
$("#headerAvatar").attr("src", userData.avatar);
|
||||||
|
updateSummary();
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.get(ApiClient.API.homeNav).then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res) || !res.data) return;
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.empty();
|
||||||
|
$.each(ApiClient.asArray(res.data), function (i, item) {
|
||||||
|
if (item.type && item.type !== "lottery") return;
|
||||||
|
var code = item.code || item.suoxie || "";
|
||||||
|
if (!code) return;
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code) +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name || item.lotteryName || code) +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
function switchTab(el) {
|
||||||
|
$(".je-tab").removeClass("active");
|
||||||
|
$(el).addClass("active");
|
||||||
|
currentCapitalType = $(el).data("type");
|
||||||
|
currentPageNum = 1;
|
||||||
|
updateSummary();
|
||||||
|
loadFlowList(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSummary() {
|
||||||
|
$("#currentTypeName").text(typeNames[currentCapitalType]);
|
||||||
|
$("#currentUnit").text(typeUnits[currentCapitalType]);
|
||||||
|
if (userData) {
|
||||||
|
var key = typeBalanceKeys[currentCapitalType];
|
||||||
|
var val = firstValue(
|
||||||
|
userData,
|
||||||
|
[key, legacyBalanceKey(currentCapitalType)],
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
$("#currentBalance").html(
|
||||||
|
escapeHtml(val) +
|
||||||
|
"<span>" +
|
||||||
|
typeUnits[currentCapitalType] +
|
||||||
|
"</span>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCapitalType === "BALANCE") {
|
||||||
|
$("#btnRecharge").show();
|
||||||
|
$("#btnWithdraw").show();
|
||||||
|
} else if (currentCapitalType === "EXPERT_BALANCE") {
|
||||||
|
$("#btnRecharge").hide();
|
||||||
|
$("#btnWithdraw").show();
|
||||||
|
} else {
|
||||||
|
$("#btnRecharge").hide();
|
||||||
|
$("#btnWithdraw").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFlowList(pageNum) {
|
||||||
|
currentPageNum = pageNum || 1;
|
||||||
|
renderLoadingTable();
|
||||||
|
|
||||||
|
if (currentCapitalType === "POINTS") {
|
||||||
|
loadPointFlowList(currentPageNum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiClient.get(ApiClient.API.walletFlowList, {
|
||||||
|
flowType: flowTypeMap[currentCapitalType],
|
||||||
|
pageNum: currentPageNum,
|
||||||
|
pageSize: pageSize,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res) && res.data) {
|
||||||
|
var page = normalizePageData(res.data);
|
||||||
|
renderFlowTable(page.records);
|
||||||
|
renderFlowPager(page.total);
|
||||||
|
} else {
|
||||||
|
renderEmptyTable();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
renderEmptyTable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPointFlowList(pageNum) {
|
||||||
|
ApiClient.get(ApiClient.API.mineSignInList, {
|
||||||
|
pageNum: pageNum,
|
||||||
|
pageSize: pageSize,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res) && res.data) {
|
||||||
|
var page = normalizePageData(res.data);
|
||||||
|
var records = page.records.map(function (item) {
|
||||||
|
return {
|
||||||
|
capitalType: "POINTS",
|
||||||
|
amount: item.pointsAwarded || item.points || item.amount || 0,
|
||||||
|
operationType: "ADD",
|
||||||
|
remark: item.remark || item.signDate || "签到奖励",
|
||||||
|
createTime:
|
||||||
|
item.createTime || item.signTime || item.signDate || "",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
renderFlowTable(records);
|
||||||
|
renderFlowPager(page.total);
|
||||||
|
} else {
|
||||||
|
renderEmptyTable();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
renderEmptyTable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFlowTable(records) {
|
||||||
|
var $tbody = $("#flowTableBody");
|
||||||
|
$tbody.empty();
|
||||||
|
if (!records || records.length === 0) {
|
||||||
|
renderEmptyTable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(records, function (i, item) {
|
||||||
|
var amount = firstValue(
|
||||||
|
item,
|
||||||
|
[
|
||||||
|
"amountText",
|
||||||
|
"changeAmountText",
|
||||||
|
"amount",
|
||||||
|
"changeAmount",
|
||||||
|
"money",
|
||||||
|
"flowAmount",
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
var opType = resolveOperationType(item, amount);
|
||||||
|
var opClass = opType === "ADD" ? "je-op-add" : "je-op-subtract";
|
||||||
|
var opText =
|
||||||
|
currentCapitalType === "POINTS"
|
||||||
|
? opType === "ADD"
|
||||||
|
? "收入"
|
||||||
|
: "支出"
|
||||||
|
: firstValue(
|
||||||
|
item,
|
||||||
|
["flowName", "typeText", "operationName"],
|
||||||
|
opType === "ADD" ? "收入" : "支出",
|
||||||
|
);
|
||||||
|
var amountClass =
|
||||||
|
opType === "ADD" ? "je-amount-add" : "je-amount-subtract";
|
||||||
|
var capitalType = normalizeCapitalType(item);
|
||||||
|
var capitalClass = typeCssClass[capitalType] || "je-capital-balance";
|
||||||
|
var remark = firstValue(
|
||||||
|
item,
|
||||||
|
["remark", "description", "title"],
|
||||||
|
"-",
|
||||||
|
);
|
||||||
|
var time = firstValue(
|
||||||
|
item,
|
||||||
|
["createTime", "flowTime", "payTime", "updateTime"],
|
||||||
|
"-",
|
||||||
|
);
|
||||||
|
$tbody.append(
|
||||||
|
"<tr>" +
|
||||||
|
'<td><span class="je-capital-type ' +
|
||||||
|
capitalClass +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(typeNames[capitalType] || capitalType) +
|
||||||
|
"</span></td>" +
|
||||||
|
'<td><span class="je-amount ' +
|
||||||
|
amountClass +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(formatSignedAmount(amount, opType)) +
|
||||||
|
"</span></td>" +
|
||||||
|
'<td><span class="je-op-type ' +
|
||||||
|
opClass +
|
||||||
|
'">' +
|
||||||
|
opText +
|
||||||
|
"</span></td>" +
|
||||||
|
'<td style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="' +
|
||||||
|
escapeHtml(remark) +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(remark) +
|
||||||
|
"</td>" +
|
||||||
|
'<td style="white-space:nowrap;color:var(--text-muted);">' +
|
||||||
|
escapeHtml(time) +
|
||||||
|
"</td>" +
|
||||||
|
"</tr>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLoadingTable() {
|
||||||
|
$("#flowTableBody").html(
|
||||||
|
'<tr><td colspan="' +
|
||||||
|
emptyColspan() +
|
||||||
|
'" class="je-empty">' +
|
||||||
|
'<div class="je-empty-icon">📋</div>' +
|
||||||
|
'<div class="je-empty-text">加载中...</div>' +
|
||||||
|
"</td></tr>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEmptyTable() {
|
||||||
|
$("#flowTableBody").html(
|
||||||
|
'<tr><td colspan="' +
|
||||||
|
emptyColspan() +
|
||||||
|
'" class="je-empty">' +
|
||||||
|
'<div class="je-empty-icon">📋</div>' +
|
||||||
|
'<div class="je-empty-text">暂无记录</div>' +
|
||||||
|
"</td></tr>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFlowPager(total) {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "flowPager",
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPageNum,
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) loadFlowList(obj.curr);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePageData(data) {
|
||||||
|
var records = ApiClient.asArray(data);
|
||||||
|
return {
|
||||||
|
records: records,
|
||||||
|
total: Number(
|
||||||
|
data.totalRow || data.total || data.count || records.length || 0,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCapitalType(item) {
|
||||||
|
if (item.capitalType && typeNames[item.capitalType])
|
||||||
|
return item.capitalType;
|
||||||
|
var flowType = String(item.flowType || "").toLowerCase();
|
||||||
|
if (flowType === "sales") return "SALES_BALANCE";
|
||||||
|
if (flowType === "expert") return "EXPERT_BALANCE";
|
||||||
|
if (flowType === "points") return "POINTS";
|
||||||
|
return currentCapitalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveOperationType(item, amount) {
|
||||||
|
var raw = String(
|
||||||
|
item.operationType ||
|
||||||
|
item.opType ||
|
||||||
|
item.direction ||
|
||||||
|
item.inOut ||
|
||||||
|
item.type ||
|
||||||
|
"",
|
||||||
|
).toLowerCase();
|
||||||
|
if (/expense|expenditure|debit|consume|purchase|withdraw|payment/.test(raw))
|
||||||
|
return "SUB";
|
||||||
|
if (/add|income|in|plus|收入|增加|充值|返利|佣金|奖励/.test(raw))
|
||||||
|
return "ADD";
|
||||||
|
if (/sub|out|minus|支出|减少|消费|购买|提现|扣除/.test(raw))
|
||||||
|
return "SUB";
|
||||||
|
return Number(amount) < 0 ? "SUB" : "ADD";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSignedAmount(amount, opType) {
|
||||||
|
var value = String(
|
||||||
|
amount === undefined || amount === null || amount === "" ? 0 : amount,
|
||||||
|
)
|
||||||
|
.replace(/^\s*[+-]\s*/, "")
|
||||||
|
.trim();
|
||||||
|
if (!value) value = "0";
|
||||||
|
return opType === "ADD" ? value : "-" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function emptyColspan() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstValue(source, keys, fallback) {
|
||||||
|
source = source || {};
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
if (
|
||||||
|
key &&
|
||||||
|
source[key] !== undefined &&
|
||||||
|
source[key] !== null &&
|
||||||
|
source[key] !== ""
|
||||||
|
) {
|
||||||
|
return source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function legacyBalanceKey(type) {
|
||||||
|
if (type === "BALANCE") return "balance";
|
||||||
|
if (type === "SALES_BALANCE") return "distributionBalance";
|
||||||
|
if (type === "EXPERT_BALANCE") return "expertCommission";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return CommonUtil.escapeHtml
|
||||||
|
? CommonUtil.escapeHtml(value)
|
||||||
|
: String(value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
ApiClient.post(ApiClient.API.authLogout, {})
|
||||||
|
.then(function () {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.href = "login.html";
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.href = "login.html";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
renderNav();
|
||||||
|
updateHeaderState();
|
||||||
|
|
||||||
|
if (!checkAuth()) return;
|
||||||
|
|
||||||
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
|
var typeParam = urlParams.get("type");
|
||||||
|
if (typeParam && typeNames[typeParam]) {
|
||||||
|
currentCapitalType = typeParam;
|
||||||
|
$(".je-tab").removeClass("active");
|
||||||
|
$('.je-tab[data-type="' + typeParam + '"]').addClass("active");
|
||||||
|
}
|
||||||
|
updateSummary();
|
||||||
|
loadFlowList(1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
<!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/kaijiang.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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<span id="breadcrumbLottery">开奖公告</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Lottery Tabs -->
|
||||||
|
<div class="cxz-lottery-tabs" id="lotteryTabs"></div>
|
||||||
|
|
||||||
|
<!-- Latest Result Card -->
|
||||||
|
<div class="cxz-latest-card" id="latestCard" style="display: none">
|
||||||
|
<div class="cxz-latest-header">
|
||||||
|
<div>
|
||||||
|
<div class="cxz-latest-label">最新开奖</div>
|
||||||
|
<div class="cxz-latest-period" id="latestPeriod">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-latest-date" id="latestDate">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-latest-balls" id="latestBalls"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Results Table -->
|
||||||
|
<div class="cxz-section-header">
|
||||||
|
<div class="cxz-section-title" id="tableTitle">历史开奖</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-table-box">
|
||||||
|
<table class="cxz-data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>期号</th>
|
||||||
|
<th>开奖日期</th>
|
||||||
|
<th>开奖号码</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="resultBody">
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colspan="3"
|
||||||
|
style="
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 40px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
加载中...
|
||||||
|
</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.$;
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
let currentSuoxie = urlParams.get("suoxie") || urlParams.get("code") || "";
|
||||||
|
let currentMenuId = urlParams.get("id") || "";
|
||||||
|
let lotteryMenus = [];
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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 escapeHtml(str) {
|
||||||
|
if (!str) return "";
|
||||||
|
return String(str)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLotteryMenus(list) {
|
||||||
|
return ApiClient.asArray(list).filter(function (item) {
|
||||||
|
return item && (!item.type || item.type === "lottery");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function menuCode(item) {
|
||||||
|
return item && (item.suoxie || item.code || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function currentMenu() {
|
||||||
|
return (
|
||||||
|
lotteryMenus.find(function (item) {
|
||||||
|
return String(item.id) === String(currentMenuId);
|
||||||
|
}) ||
|
||||||
|
lotteryMenus.find(function (item) {
|
||||||
|
return menuCode(item) && String(menuCode(item)) === String(currentSuoxie);
|
||||||
|
}) ||
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveCurrentMenu() {
|
||||||
|
if (!lotteryMenus.length) return null;
|
||||||
|
let selected = currentMenu();
|
||||||
|
if (!selected) selected = lotteryMenus[0];
|
||||||
|
currentMenuId = String(selected.id || "");
|
||||||
|
currentSuoxie = menuCode(selected);
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNavFromMenus() {
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.empty();
|
||||||
|
$.each(lotteryMenus, function (_, item) {
|
||||||
|
var code = menuCode(item);
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
encodeURIComponent(code || item.id || "") +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name || "") +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLotteryTabs() {
|
||||||
|
return ApiClient.get(ApiClient.API.homeNav)
|
||||||
|
.then(function (res) {
|
||||||
|
lotteryMenus = normalizeLotteryMenus(ApiClient.pickData(res, []));
|
||||||
|
resolveCurrentMenu();
|
||||||
|
renderNavFromMenus();
|
||||||
|
var $tabs = $("#lotteryTabs");
|
||||||
|
$tabs.empty();
|
||||||
|
$.each(lotteryMenus, function (_, item) {
|
||||||
|
var code = menuCode(item);
|
||||||
|
$tabs.append(
|
||||||
|
'<a href="kaijiang.html?suoxie=' +
|
||||||
|
encodeURIComponent(code || "") +
|
||||||
|
'" class="cxz-lottery-tab" data-code="' +
|
||||||
|
escapeHtml(code) +
|
||||||
|
'" data-id="' +
|
||||||
|
escapeHtml(item.id || "") +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(item.name || "") +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
highlightTab();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
lotteryMenus = [];
|
||||||
|
$("#navLotteryItems").empty();
|
||||||
|
$("#lotteryTabs").empty();
|
||||||
|
$("#breadcrumbLottery").text("开奖公告");
|
||||||
|
$("#tableTitle").text("历史开奖");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highlight tab
|
||||||
|
function highlightTab() {
|
||||||
|
const selected = resolveCurrentMenu();
|
||||||
|
$(".cxz-lottery-tab").removeClass("active");
|
||||||
|
$('.cxz-lottery-tab[data-id="' + currentMenuId + '"]').addClass("active");
|
||||||
|
const name = (selected && selected.name) || "开奖公告";
|
||||||
|
$("#breadcrumbLottery").text(name + " - 开奖公告");
|
||||||
|
$("#tableTitle").text(name + " 历史开奖");
|
||||||
|
document.title = "彩先知 - " + name + "开奖公告";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load results
|
||||||
|
function loadResults() {
|
||||||
|
if (!currentMenuId) {
|
||||||
|
$("#resultBody").html(
|
||||||
|
'<tr><td colspan="3" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApiClient.get("/api/web/lottery/result/list", {
|
||||||
|
menuId: currentMenuId,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
}).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);
|
||||||
|
renderResults(list);
|
||||||
|
} else {
|
||||||
|
$("#resultBody").html(
|
||||||
|
'<tr><td colspan="3" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderResults(list) {
|
||||||
|
const $body = $("#resultBody");
|
||||||
|
$body.empty();
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
$body.html(
|
||||||
|
'<tr><td colspan="3" style="text-align:center;color:var(--text-muted);padding:40px;">暂无数据</td></tr>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest result card
|
||||||
|
if (list.length > 0) {
|
||||||
|
const latest = list[0];
|
||||||
|
$("#latestCard").show();
|
||||||
|
$("#latestPeriod").text(
|
||||||
|
(latest.name || "") + " 第" + (latest.expect || "") + "期",
|
||||||
|
);
|
||||||
|
$("#latestDate").text(
|
||||||
|
latest.date ||
|
||||||
|
(latest.createTime ? latest.createTime.substring(0, 10) : ""),
|
||||||
|
);
|
||||||
|
$("#latestBalls").html(parseOpenCode(latest.openCode, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
const ballsHtml = parseOpenCode(item.openCode, false);
|
||||||
|
const date =
|
||||||
|
item.date ||
|
||||||
|
(item.createTime ? item.createTime.substring(0, 10) : "--");
|
||||||
|
$body.append(
|
||||||
|
"<tr>" +
|
||||||
|
"<td>" +
|
||||||
|
(item.expect || "") +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
date +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
ballsHtml +
|
||||||
|
"</td>" +
|
||||||
|
"</tr>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse openCode format "01,02,03+07" to display red/blue balls.
|
||||||
|
// Red/blue splitting follows the API data itself: numbers after "+" are blue.
|
||||||
|
function parseOpenCode(openCode, isLarge) {
|
||||||
|
if (!openCode)
|
||||||
|
return '<span style="color:var(--text-muted);">--</span>';
|
||||||
|
|
||||||
|
const parts = String(openCode).split("+");
|
||||||
|
const reds = splitCodes(parts[0]);
|
||||||
|
let blues = [];
|
||||||
|
for (let p = 1; p < parts.length; p++) {
|
||||||
|
blues = blues.concat(splitCodes(parts[p]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = "";
|
||||||
|
const sizeStyle = isLarge
|
||||||
|
? ' style="width:40px;height:40px;font-size:16px;"'
|
||||||
|
: "";
|
||||||
|
$.each(reds, function (i, num) {
|
||||||
|
html += '<span class="red-q"' + sizeStyle + ">" + escapeHtml(num) + "</span>";
|
||||||
|
});
|
||||||
|
$.each(blues, function (i, num) {
|
||||||
|
html += '<span class="bule-q"' + sizeStyle + ">" + escapeHtml(num) + "</span>";
|
||||||
|
});
|
||||||
|
return html || '<span style="color:var(--text-muted);">--</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitCodes(value) {
|
||||||
|
return String(value || "")
|
||||||
|
.split(/[,,\s]+/)
|
||||||
|
.map(function (s) {
|
||||||
|
return s.trim();
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderLotteryTabs().then(loadResults);
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>彩先知 - 快乐8走势图</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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>快乐8走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">快乐8走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="40" class="zone-g1">1-40</td>
|
||||||
|
<td colspan="40" class="zone-g2">41-80</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var NUM_MAX = 80;
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var i = 1; i <= NUM_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse openCode like "01,05,12,18,23,27,30,35,38,42,45,48,50,55,58,62,65,68,72,75"
|
||||||
|
function parseCode(code) {
|
||||||
|
return code.split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var nums = parseCode(item.openCode);
|
||||||
|
var hitSet = {};
|
||||||
|
nums.forEach(function (n) {
|
||||||
|
hitSet[n] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
for (var i = 1; i <= NUM_MAX; i++) {
|
||||||
|
if (hitSet[i]) {
|
||||||
|
var cls = i <= 40 ? "hit-num" : "hit-num g2";
|
||||||
|
html +=
|
||||||
|
'<td><span class="' +
|
||||||
|
cls +
|
||||||
|
'">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcStats(data, maxNum, getNums) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var nums = getNums(data[r]);
|
||||||
|
if (nums.indexOf(i) >= 0) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var stats = calcStats(data, NUM_MAX, function (d) {
|
||||||
|
return parseCode(d.openCode);
|
||||||
|
});
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var html = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
html +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var i = 1; i <= NUM_MAX; i++)
|
||||||
|
html += "<td>" + stats[keys[li]][i] + "</td>";
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "kl8" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title id="page-title">彩先知 - 登录</title>
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../utils/AuthPageUtil.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/auth.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="auth-container">
|
||||||
|
<div class="auth-card">
|
||||||
|
<div class="auth-header">
|
||||||
|
<a class="auth-logo" href="index.html" aria-label="返回首页">
|
||||||
|
<img src="../images/cxz-logo.png" alt="彩先知" />
|
||||||
|
</a>
|
||||||
|
<div class="auth-subtitle">CaiXianZhi - 欢迎登录</div>
|
||||||
|
</div>
|
||||||
|
<div class="auth-body">
|
||||||
|
<form id="loginForm" autocomplete="off">
|
||||||
|
<div class="form-group" id="phoneContainer">
|
||||||
|
<label for="phoneInput">手机号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="phoneNumber"
|
||||||
|
id="phoneInput"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
class="form-input"
|
||||||
|
maxlength="11"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="phoneError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="passwordContainer">
|
||||||
|
<label for="passwordInput">密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
id="passwordInput"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
class="form-input"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="passwordError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="captchaGroup">
|
||||||
|
<label for="captchaInput">验证码</label>
|
||||||
|
<div class="captcha-row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="captcha"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
class="form-input"
|
||||||
|
id="captchaInput"
|
||||||
|
maxlength="6"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="captcha-img-box"
|
||||||
|
id="captchaContainer"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
<img id="captchaImage" src="" alt="验证码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="captcha-refresh-link"
|
||||||
|
id="captchaRefreshLink"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
看不清?换一张
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="captchaError"></div>
|
||||||
|
<input type="hidden" name="captchaId" id="captchaId" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="auth-submit-btn" id="loginButton">
|
||||||
|
登 录
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="auth-agreement">
|
||||||
|
<input type="checkbox" id="agreementCheckbox" />
|
||||||
|
<span>已阅读并同意</span>
|
||||||
|
<a href="yonghuxieyi.html" target="_blank">《彩先知用户协议》</a>
|
||||||
|
<a href="yinsixieyi.html" target="_blank">《彩先知隐私政策》</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="auth-links">
|
||||||
|
<a href="reg.html">立即注册</a>
|
||||||
|
<a href="repwd.html">忘记密码</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div class="loading-overlay" id="loadingOverlay">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../public/js/jquery.js"></script>
|
||||||
|
<script src="../public/js/md5.js"></script>
|
||||||
|
<script>
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
const $ = layui.$;
|
||||||
|
let layerInstance = null;
|
||||||
|
let currentCaptchaId = "";
|
||||||
|
let currentVerifyType = "captcha";
|
||||||
|
let currentSlideUuid = "";
|
||||||
|
let currentSlideX = 0;
|
||||||
|
|
||||||
|
function showError(field, message) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.text(message)
|
||||||
|
.show();
|
||||||
|
$("#" + containerId).addClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearError(field) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.hide()
|
||||||
|
.text("");
|
||||||
|
$("#" + containerId).removeClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadVerifyConfig() {
|
||||||
|
return AuthPageUtil.loadVerifyType().then(function (type) {
|
||||||
|
currentVerifyType = type;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCaptcha() {
|
||||||
|
currentCaptchaId = "";
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
$("#captchaId").val("");
|
||||||
|
$("#captchaInput").val("");
|
||||||
|
$("#captchaGroup").removeClass("is-slide-mode");
|
||||||
|
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#captchaInput").show();
|
||||||
|
$("#captchaRefreshLink").show().text("看不清?换一张");
|
||||||
|
$("#captchaContainer")
|
||||||
|
.attr("onclick", "refreshCaptcha()")
|
||||||
|
.html('<img id="captchaImage" src="" alt="验证码" />');
|
||||||
|
$("#captchaImage").attr("src", ApiClient.transparentGif());
|
||||||
|
|
||||||
|
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);
|
||||||
|
$("#captchaImage").attr(
|
||||||
|
"src",
|
||||||
|
res.data.img || res.data.image || "",
|
||||||
|
);
|
||||||
|
clearError("captcha");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layerInstance.msg(
|
||||||
|
"获取验证码失败:" + ((res && res.msg) || "未知错误"),
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layerInstance.msg("网络错误,无法获取验证码", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeSlideCaptcha(result) {
|
||||||
|
const data = result || {};
|
||||||
|
const nested = data.data || {};
|
||||||
|
currentSlideUuid =
|
||||||
|
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
|
||||||
|
currentSlideX =
|
||||||
|
Number(data.slideX || data.x || nested.slideX || nested.x || 0) || 0;
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
layerInstance.msg("滑动验证未返回凭证,请重试", { icon: 2 });
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#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>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSlideCaptcha() {
|
||||||
|
AuthPageUtil.loadSlideCaptchaScript()
|
||||||
|
.then(function (SlideCaptcha) {
|
||||||
|
SlideCaptcha.open({
|
||||||
|
title: "登录安全验证",
|
||||||
|
subtitle: "拖动滑块完成验证后继续登录",
|
||||||
|
apiBase: ApiClient.baseUrl || "",
|
||||||
|
onSuccess: completeSlideCaptcha,
|
||||||
|
onCancel: function () {
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
},
|
||||||
|
onError: function (error) {
|
||||||
|
layerInstance.msg(
|
||||||
|
(error && error.message) || "滑动验证失败,请重试",
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
layerInstance.msg(error.message || "滑动验证组件加载失败", {
|
||||||
|
icon: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSlideCaptchaEntry() {
|
||||||
|
$("#captchaInput").hide();
|
||||||
|
$("#captchaRefreshLink").hide();
|
||||||
|
$("#captchaGroup").addClass("is-slide-mode");
|
||||||
|
$("#captchaContainer")
|
||||||
|
.removeAttr("onclick")
|
||||||
|
.html(
|
||||||
|
'<div class="slide-verify-card" role="button" tabindex="0"><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>',
|
||||||
|
);
|
||||||
|
$(".slide-verify-card")
|
||||||
|
.off("click keydown")
|
||||||
|
.on("click", openSlideCaptcha)
|
||||||
|
.on("keydown", function (event) {
|
||||||
|
if (event.key === "Enter" || event.key === " ") {
|
||||||
|
event.preventDefault();
|
||||||
|
openSlideCaptcha();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePhone(show) {
|
||||||
|
const value = $("#phoneInput").val().trim();
|
||||||
|
if (!AuthPageUtil.isPhone(value)) {
|
||||||
|
if (show) showError("phone", "请输入正确的手机号");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("phone");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassword(show) {
|
||||||
|
if (!AuthPageUtil.isPassword($("#passwordInput").val())) {
|
||||||
|
if (show) showError("password", "密码长度应为6-20位");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("password");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVerifyParams(show) {
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
if (show) layerInstance.msg("请先完成滑动验证", { icon: 2 });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
verifyType: "slide",
|
||||||
|
slideUuid: currentSlideUuid,
|
||||||
|
slideX: currentSlideX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const code = $("#captchaInput").val().trim();
|
||||||
|
if (!code || !currentCaptchaId) {
|
||||||
|
if (show) showError("captcha", "请填写有效验证码");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
clearError("captcha");
|
||||||
|
return { verifyType: "captcha", code, uuid: currentCaptchaId };
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
if (!validatePhone(true) || !validatePassword(true)) return false;
|
||||||
|
if (!getVerifyParams(true)) return false;
|
||||||
|
if (!$("#agreementCheckbox").prop("checked")) {
|
||||||
|
layerInstance.msg("请阅读并同意用户协议和隐私政策", { icon: 2 });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitLogin() {
|
||||||
|
const payload = Object.assign(
|
||||||
|
{
|
||||||
|
grantType: "password",
|
||||||
|
clientId: ApiClient.clientId,
|
||||||
|
client_id: ApiClient.clientId,
|
||||||
|
phoneNumber: $("#phoneInput").val().trim(),
|
||||||
|
password: hex_md5($("#passwordInput").val()),
|
||||||
|
deviceType: "WEB",
|
||||||
|
},
|
||||||
|
getVerifyParams(false) || {},
|
||||||
|
);
|
||||||
|
const $button = $("#loginButton");
|
||||||
|
$("#loadingOverlay").show();
|
||||||
|
$button.prop("disabled", true).text("登录中...");
|
||||||
|
ApiClient.post(ApiClient.API.authLogin, payload, {
|
||||||
|
publicRequest: true,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res) && res.data) {
|
||||||
|
localStorage.setItem(
|
||||||
|
"token",
|
||||||
|
JSON.stringify(
|
||||||
|
res.data.token || res.data.access_token || res.data,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
layerInstance.msg(
|
||||||
|
"登录成功,即将跳转到首页",
|
||||||
|
{ icon: 1, time: 1200 },
|
||||||
|
function () {
|
||||||
|
window.location.href = "index.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layerInstance.msg(
|
||||||
|
(res && res.msg) || "登录失败,请检查手机号或密码",
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
refreshCaptcha();
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
layerInstance.msg(
|
||||||
|
"登录请求失败:" + (error.message || "网络错误"),
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
refreshCaptcha();
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
$("#loadingOverlay").hide();
|
||||||
|
$button.prop("disabled", false).text("登 录");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
layerInstance = layui.layer;
|
||||||
|
loadVerifyConfig().then(refreshCaptcha);
|
||||||
|
$("#loginForm").on("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (validateForm()) submitLogin();
|
||||||
|
});
|
||||||
|
$("#phoneInput").on("blur", function () {
|
||||||
|
validatePhone(true);
|
||||||
|
});
|
||||||
|
$("#passwordInput").on("blur", function () {
|
||||||
|
validatePassword(true);
|
||||||
|
});
|
||||||
|
$("#captchaInput").on("input", function () {
|
||||||
|
clearError("captcha");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,619 @@
|
|||||||
|
<!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/mianfei.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged" style="display: none">
|
||||||
|
<a href="usercenter.html" class="topbar__profile">
|
||||||
|
<img
|
||||||
|
id="userAvatar"
|
||||||
|
src="../public/img/userimg.png"
|
||||||
|
alt=""
|
||||||
|
class="topbar__avatar"
|
||||||
|
/>
|
||||||
|
<div class="topbar__meta">
|
||||||
|
<span id="userName" class="topbar__uname">用户</span>
|
||||||
|
<span id="userLevel" class="topbar__ubadge">会员</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<button class="topbar__btn topbar__btn--logout" onclick="logout()">
|
||||||
|
退出登录
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main -->
|
||||||
|
<main class="cxz-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="mianfeilist.html?id=1">免费推荐</a><span class="sep">></span>
|
||||||
|
<span>文章详情</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Card -->
|
||||||
|
<div class="cxz-article-card">
|
||||||
|
<div class="cxz-article-header">
|
||||||
|
<h1 class="cxz-article-title" id="articleTitle">加载中...</h1>
|
||||||
|
<div class="cxz-article-meta">
|
||||||
|
<span>作者:<span class="author" id="articleAuthor">--</span></span>
|
||||||
|
<span id="articleTime">--</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-article-body" id="articleContent">
|
||||||
|
<p style="text-align: center; color: var(--text-muted)">加载中...</p>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-article-actions">
|
||||||
|
<button class="cxz-action-btn" id="btnLike" onclick="toggleLike()">
|
||||||
|
<i class="layui-icon layui-icon-praise"></i>
|
||||||
|
<span id="likeText">点赞</span>(<span id="likeCount">0</span>)
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="cxz-action-btn"
|
||||||
|
id="btnCollect"
|
||||||
|
onclick="toggleCollect()"
|
||||||
|
>
|
||||||
|
<i class="layui-icon layui-icon-star-fill"></i>
|
||||||
|
<span id="collectText">收藏</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Prev/Next Navigation -->
|
||||||
|
<div class="cxz-article-nav">
|
||||||
|
<a class="cxz-nav-item" id="prevArticle" href="javascript:void(0)">
|
||||||
|
<div class="cxz-nav-label">上一篇</div>
|
||||||
|
<div class="cxz-nav-title" id="prevTitle">没有了</div>
|
||||||
|
</a>
|
||||||
|
<a class="cxz-nav-item" id="nextArticle" href="javascript:void(0)">
|
||||||
|
<div class="cxz-nav-label">下一篇</div>
|
||||||
|
<div class="cxz-nav-title" id="nextTitle">没有了</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Comment Section -->
|
||||||
|
<div class="cxz-comment-section">
|
||||||
|
<div class="cxz-comment-header">
|
||||||
|
<i class="layui-icon layui-icon-dialogue"></i>
|
||||||
|
<span>评论(<span id="commentCount">0</span>)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Comment Input -->
|
||||||
|
<div class="cxz-comment-input-box">
|
||||||
|
<textarea
|
||||||
|
class="cxz-comment-textarea"
|
||||||
|
id="commentInput"
|
||||||
|
placeholder="请输入您的评论..."
|
||||||
|
></textarea>
|
||||||
|
<button class="cxz-comment-submit-btn" onclick="submitComment()">
|
||||||
|
发表评论
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Comment List -->
|
||||||
|
<div class="cxz-comment-list" id="commentList">
|
||||||
|
<div class="cxz-comment-empty">
|
||||||
|
<i class="layui-icon layui-icon-face-surprised"></i>
|
||||||
|
<span>暂无评论,快来抢沙发吧~</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-pagination" id="commentPager"></div>
|
||||||
|
</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.$;
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const pathMatch = window.location.pathname.match(/\/mianfei\/([^/]+)\.html$/);
|
||||||
|
const articleId = urlParams.get("id") || (pathMatch ? decodeURIComponent(pathMatch[1]) : "");
|
||||||
|
let isLiked = false;
|
||||||
|
let isCollected = false;
|
||||||
|
let articleData = null;
|
||||||
|
let commentPage = 1;
|
||||||
|
const commentPageSize = 10;
|
||||||
|
let likeBusy = false;
|
||||||
|
let collectBusy = false;
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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.get(ApiClient.API.homeNav).then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) return;
|
||||||
|
var list = ApiClient.asArray(ApiClient.pickData(res, []));
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.find(".topbar__nav-link").not(":first").remove();
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
if (item.type && item.type !== "lottery") return;
|
||||||
|
var code = item.code || item.suoxie || "";
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
code +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name || "") +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prevent prev/next navigation when no valid href
|
||||||
|
$("#prevArticle, #nextArticle").on("click", function (e) {
|
||||||
|
var href = $(this).attr("href");
|
||||||
|
if (!href || href === "javascript:void(0)" || href === "") {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// === Load Article ===
|
||||||
|
function loadArticle() {
|
||||||
|
var token = localStorage.getItem("token");
|
||||||
|
var opts = token ? { headers: CommonUtil.authHeaders() } : {};
|
||||||
|
|
||||||
|
ApiClient.get(ApiClient.API.freeArticleDetail(articleId), null, opts)
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res) && ApiClient.pickData(res, null)) {
|
||||||
|
articleData = ApiClient.pickData(res, {});
|
||||||
|
renderArticle(articleData);
|
||||||
|
loadRelatedArticles();
|
||||||
|
} else {
|
||||||
|
layui.layer.msg("文章不存在或已删除", { icon: 2 });
|
||||||
|
$("#articleTitle").text("文章不存在");
|
||||||
|
$("#articleContent").html(
|
||||||
|
'<p style="text-align:center;color:var(--text-muted);">文章不存在或已删除</p>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layui.layer.msg("加载失败,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArticle(data) {
|
||||||
|
$("#articleTitle").text(data.title || "无标题");
|
||||||
|
$("#articleAuthor").text(data.issuer || data.nickName || data.author || data.createUserName || "佚名");
|
||||||
|
$("#articleTime").text(data.updateTime || data.createTime || data.publishTime || "--");
|
||||||
|
$("#articleContent").html(scopeArticleContent(data.content || ""));
|
||||||
|
document.title = "彩先知 - " + (data.title || "免费文章详情");
|
||||||
|
|
||||||
|
renderArticleNav(data.prev || data.previous || data.prevArticle, data.next || data.nextArticle);
|
||||||
|
|
||||||
|
isLiked = isTruthyState(data.isLike ?? data.liked ?? data.isLiked);
|
||||||
|
updateLikeButton(data);
|
||||||
|
|
||||||
|
isCollected = isTruthyState(data.isCollect ?? data.collected ?? data.isCollected);
|
||||||
|
updateCollectButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scopeArticleContent(content) {
|
||||||
|
var html = String(content || "");
|
||||||
|
if (!html.trim()) {
|
||||||
|
return '<p class="cxz-content-empty">暂无内容</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var scopedStyles = [];
|
||||||
|
html = html.replace(/<style[^>]*>([\s\S]*?)<\/style>/gi, function (_, css) {
|
||||||
|
scopedStyles.push(prefixContentCss(css));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleHtml = scopedStyles.length
|
||||||
|
? '<style data-cxz-content-style>' + scopedStyles.join("\n") + "</style>"
|
||||||
|
: "";
|
||||||
|
return styleHtml + '<div class="cxz-content-inner">' + html + "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefixContentCss(css) {
|
||||||
|
return String(css || "").replace(/(^|})(\s*)([^@{}][^{}]*)\{/g, function (match, close, space, selectorText) {
|
||||||
|
var selectors = selectorText
|
||||||
|
.split(",")
|
||||||
|
.map(function (selector) {
|
||||||
|
selector = selector.trim();
|
||||||
|
if (!selector) return "";
|
||||||
|
if (
|
||||||
|
selector.indexOf("#articleContent") === 0 ||
|
||||||
|
selector.indexOf(".cxz-article-body") === 0
|
||||||
|
) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (/^(html|body)$/i.test(selector)) return "#articleContent";
|
||||||
|
if (/^(html|body)\b/i.test(selector)) {
|
||||||
|
return selector.replace(/^(html|body)\b/i, "#articleContent");
|
||||||
|
}
|
||||||
|
return "#articleContent " + selector;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(", ");
|
||||||
|
return close + space + selectors + " {";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTruthyState(value) {
|
||||||
|
return (
|
||||||
|
value === true ||
|
||||||
|
value === 1 ||
|
||||||
|
value === "1" ||
|
||||||
|
value === 0 ||
|
||||||
|
value === "0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function articleLinkOf(item) {
|
||||||
|
var id = item && (item.id || item.articleId || item.freeArticleId);
|
||||||
|
return CommonUtil.freeArticleHref(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyNavItem($item, $title, item, emptyText) {
|
||||||
|
if (item && (item.id || item.articleId || item.freeArticleId)) {
|
||||||
|
$item.attr("href", articleLinkOf(item)).removeClass("is-disabled").css("opacity", "");
|
||||||
|
$title.text(item.title || emptyText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$item.attr("href", "javascript:void(0)").addClass("is-disabled").css("opacity", "");
|
||||||
|
$title.text("没有了");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArticleNav(prev, next) {
|
||||||
|
applyNavItem($("#prevArticle"), $("#prevTitle"), prev, "上一篇");
|
||||||
|
applyNavItem($("#nextArticle"), $("#nextTitle"), next, "下一篇");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRelatedArticles() {
|
||||||
|
ApiClient.get(ApiClient.API.freeArticleRelated(articleId))
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) return;
|
||||||
|
var data = ApiClient.pickData(res, {}) || {};
|
||||||
|
var prev = data.prev || data.previous || data.prevArticle;
|
||||||
|
var next = data.next || data.nextArticle;
|
||||||
|
var rows = ApiClient.asArray(data);
|
||||||
|
if (!prev && rows[0]) prev = rows[0];
|
||||||
|
if (!next && rows[1]) next = rows[1];
|
||||||
|
if (prev || next) renderArticleNav(prev, next);
|
||||||
|
})
|
||||||
|
.catch(function () {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLikeButton(data) {
|
||||||
|
var count = data.likeCount || 0;
|
||||||
|
$("#likeCount").text(count);
|
||||||
|
if (isLiked) {
|
||||||
|
$("#btnLike").addClass("liked");
|
||||||
|
$("#likeText").text("已点赞");
|
||||||
|
} else {
|
||||||
|
$("#btnLike").removeClass("liked");
|
||||||
|
$("#likeText").text("点赞");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCollectButton() {
|
||||||
|
if (isCollected) {
|
||||||
|
$("#btnCollect").addClass("collected");
|
||||||
|
$("#collectText").text("已收藏");
|
||||||
|
} else {
|
||||||
|
$("#btnCollect").removeClass("collected");
|
||||||
|
$("#collectText").text("收藏");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Like ===
|
||||||
|
function toggleLike() {
|
||||||
|
if (likeBusy) return;
|
||||||
|
var token = localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
layui.layer.confirm(
|
||||||
|
"点赞需要先登录,是否前往登录?",
|
||||||
|
{ icon: 3, title: "提示" },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
window.location.href = "login.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var wasLiked = isLiked;
|
||||||
|
likeBusy = true;
|
||||||
|
$("#btnLike").prop("disabled", true);
|
||||||
|
ApiClient.post(ApiClient.API.freeArticleLike(articleId), {}, { headers: CommonUtil.authHeaders() })
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res)) {
|
||||||
|
loadArticle();
|
||||||
|
layui.layer.msg(wasLiked ? "已取消点赞" : "点赞成功", {
|
||||||
|
icon: 1,
|
||||||
|
time: 1500,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "操作失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
likeBusy = false;
|
||||||
|
$("#btnLike").prop("disabled", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Collect ===
|
||||||
|
function toggleCollect() {
|
||||||
|
if (collectBusy) return;
|
||||||
|
var token = localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
layui.layer.confirm(
|
||||||
|
"收藏需要先登录,是否前往登录?",
|
||||||
|
{ icon: 3, title: "提示" },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
window.location.href = "login.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var wasCollected = isCollected;
|
||||||
|
collectBusy = true;
|
||||||
|
$("#btnCollect").prop("disabled", true);
|
||||||
|
ApiClient.post(ApiClient.API.freeArticleCollect(articleId), {}, { headers: CommonUtil.authHeaders() })
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res)) {
|
||||||
|
loadArticle();
|
||||||
|
layui.layer.msg(wasCollected ? "已取消收藏" : "收藏成功", {
|
||||||
|
icon: 1,
|
||||||
|
time: 1500,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "操作失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
collectBusy = false;
|
||||||
|
$("#btnCollect").prop("disabled", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Comments ===
|
||||||
|
function loadComments(pageNum) {
|
||||||
|
if (pageNum) commentPage = pageNum;
|
||||||
|
ApiClient.get(ApiClient.API.freeArticleComments(articleId), {
|
||||||
|
pageNum: commentPage,
|
||||||
|
pageSize: commentPageSize,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res) && ApiClient.pickData(res, null)) {
|
||||||
|
var data = ApiClient.pickData(res, {}) || {};
|
||||||
|
var list = ApiClient.asArray(data);
|
||||||
|
var total = data.totalRow || data.total || data.count || list.length || 0;
|
||||||
|
renderComments(list);
|
||||||
|
$("#commentCount").text(total);
|
||||||
|
renderCommentPager(total);
|
||||||
|
} else {
|
||||||
|
renderCommentEmpty();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
renderCommentEmpty("加载失败");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderComments(list) {
|
||||||
|
var $container = $("#commentList");
|
||||||
|
$container.empty();
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
renderCommentEmpty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
var avatarHtml;
|
||||||
|
if (item.avatar) {
|
||||||
|
avatarHtml =
|
||||||
|
'<img class="cxz-comment-avatar" src="' +
|
||||||
|
escapeHtml(item.avatar) +
|
||||||
|
'" />';
|
||||||
|
} else {
|
||||||
|
var initial = (item.nickName || item.nickname || item.userName || "匿").charAt(0);
|
||||||
|
avatarHtml =
|
||||||
|
'<div class="cxz-comment-avatar-placeholder">' +
|
||||||
|
escapeHtml(initial) +
|
||||||
|
"</div>";
|
||||||
|
}
|
||||||
|
var name = escapeHtml(item.nickName || item.nickname || item.userName || "匿名用户");
|
||||||
|
var text = escapeHtml(item.comment || item.content || "");
|
||||||
|
var time = item.createTime || item.commentTime || item.updateTime || "--";
|
||||||
|
if (time && time.length > 16) time = time.substring(0, 16);
|
||||||
|
|
||||||
|
$container.append(
|
||||||
|
'<div class="cxz-comment-item">' +
|
||||||
|
avatarHtml +
|
||||||
|
'<div class="cxz-comment-body">' +
|
||||||
|
'<div class="cxz-comment-name">' +
|
||||||
|
name +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="cxz-comment-text">' +
|
||||||
|
text +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="cxz-comment-time">' +
|
||||||
|
time +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCommentEmpty(msg) {
|
||||||
|
$("#commentList").html(
|
||||||
|
'<div class="cxz-comment-empty">' +
|
||||||
|
'<i class="layui-icon layui-icon-face-surprised"></i>' +
|
||||||
|
"<span>" +
|
||||||
|
(msg || "暂无评论,快来抢沙发吧~") +
|
||||||
|
"</span>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCommentPager(total) {
|
||||||
|
if (total <= 0) {
|
||||||
|
$("#commentPager").empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "commentPager",
|
||||||
|
count: total,
|
||||||
|
limit: commentPageSize,
|
||||||
|
curr: commentPage,
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) {
|
||||||
|
commentPage = obj.curr;
|
||||||
|
loadComments();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitComment() {
|
||||||
|
var content = $("#commentInput").val().trim();
|
||||||
|
if (!content) {
|
||||||
|
layui.layer.msg("请输入评论内容", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var token = localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
layui.layer.confirm(
|
||||||
|
"发表评论需要先登录,是否前往登录?",
|
||||||
|
{ icon: 3, title: "提示" },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
window.location.href = "login.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $btn = $(".cxz-comment-submit-btn");
|
||||||
|
$btn.text("提交中...").prop("disabled", true);
|
||||||
|
|
||||||
|
ApiClient.post(ApiClient.API.freeArticleComment(articleId), { comment: content }, { headers: CommonUtil.authHeaders() })
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res)) {
|
||||||
|
layui.layer.msg("评论成功", { icon: 1, time: 1500 });
|
||||||
|
$("#commentInput").val("");
|
||||||
|
commentPage = 1;
|
||||||
|
loadComments();
|
||||||
|
} else {
|
||||||
|
layui.layer.msg(res.msg || "评论失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
$btn.text("发表评论").prop("disabled", false);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layui.layer.msg("网络错误,请重试", { icon: 2 });
|
||||||
|
$btn.text("发表评论").prop("disabled", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(str) {
|
||||||
|
if (!str) return "";
|
||||||
|
return String(str)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Init ===
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
if (articleId) {
|
||||||
|
loadArticle();
|
||||||
|
loadComments();
|
||||||
|
} else {
|
||||||
|
layui.layer.msg("文章ID不存在", { icon: 2 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
<!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/mianfei.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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<span>免费推荐</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Lottery Tabs -->
|
||||||
|
<div class="cxz-lottery-tabs" id="lotteryTabs"></div>
|
||||||
|
|
||||||
|
<div class="cxz-section-header">
|
||||||
|
<div class="cxz-section-title" id="listTitle">免费推荐</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-article-list" id="articleList">
|
||||||
|
<div class="cxz-article-item">
|
||||||
|
<span style="color: var(--text-muted)">加载中...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="pagination"></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.$;
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
let menuId = urlParams.get("id") || "";
|
||||||
|
let currentPage = 1;
|
||||||
|
const pageSize = 15;
|
||||||
|
let lotteryMenus = [];
|
||||||
|
|
||||||
|
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 || "用户");
|
||||||
|
$("#userAvatar").attr(
|
||||||
|
"src",
|
||||||
|
data.avatar || "../public/img/userimg.png",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(str) {
|
||||||
|
if (!str) return "";
|
||||||
|
return String(str)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLotteryMenus(list) {
|
||||||
|
return ApiClient.asArray(list).filter(function (item) {
|
||||||
|
return item && (!item.type || item.type === "lottery");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveCurrentMenuId() {
|
||||||
|
if (!lotteryMenus.length) return;
|
||||||
|
if (
|
||||||
|
menuId &&
|
||||||
|
lotteryMenus.some(function (item) {
|
||||||
|
return String(item.id) === String(menuId);
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuId = String((lotteryMenus[0] && lotteryMenus[0].id) || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLotteryTabs() {
|
||||||
|
return ApiClient.get(ApiClient.API.homeNav)
|
||||||
|
.then(function (res) {
|
||||||
|
lotteryMenus = normalizeLotteryMenus(ApiClient.pickData(res, []));
|
||||||
|
resolveCurrentMenuId();
|
||||||
|
const $tabs = $("#lotteryTabs");
|
||||||
|
$tabs.empty();
|
||||||
|
$.each(lotteryMenus, function (_, item) {
|
||||||
|
const id = item.id || "";
|
||||||
|
$tabs.append(
|
||||||
|
'<a href="mianfeilist.html?id=' +
|
||||||
|
encodeURIComponent(id) +
|
||||||
|
'" class="cxz-lottery-tab" data-id="' +
|
||||||
|
escapeHtml(id) +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(item.name || "") +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
highlightTab();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
lotteryMenus = [];
|
||||||
|
$("#lotteryTabs").empty();
|
||||||
|
$("#listTitle").text("免费推荐");
|
||||||
|
document.title = "彩先知 - 免费推荐";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight active tab
|
||||||
|
function highlightTab() {
|
||||||
|
$(".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);
|
||||||
|
});
|
||||||
|
const name = (currentMenu && currentMenu.name) || "免费推荐";
|
||||||
|
$("#listTitle").text(name + " - 免费推荐");
|
||||||
|
document.title = "彩先知 - " + name + "免费推荐";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load articles
|
||||||
|
function loadArticles() {
|
||||||
|
if (!menuId) {
|
||||||
|
$("#articleList").html(
|
||||||
|
'<div class="cxz-article-item"><span style="color:var(--text-muted);">暂无数据</span></div>',
|
||||||
|
);
|
||||||
|
renderPagination(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApiClient.get("/api/web/free-article/list", {
|
||||||
|
menuId: menuId,
|
||||||
|
pageNum: currentPage,
|
||||||
|
pageSize: pageSize,
|
||||||
|
}).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);
|
||||||
|
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>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArticles(list) {
|
||||||
|
const $container = $("#articleList");
|
||||||
|
$container.empty();
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
$container.html(
|
||||||
|
'<div class="cxz-article-item"><span style="color:var(--text-muted);">暂无数据</span></div>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
let displayDate = "";
|
||||||
|
if (item.createTime) displayDate = item.createTime.substring(0, 10);
|
||||||
|
$container.append(
|
||||||
|
'<div class="cxz-article-item">' +
|
||||||
|
'<a href="' +
|
||||||
|
CommonUtil.freeArticleHref(item.id || "") +
|
||||||
|
'" target="_blank">' +
|
||||||
|
escapeHtml(item.title || "无标题") +
|
||||||
|
"</a>" +
|
||||||
|
'<span class="cxz-article-date">' +
|
||||||
|
escapeHtml(displayDate) +
|
||||||
|
"</span>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(total) {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "pagination",
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPage,
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) {
|
||||||
|
currentPage = obj.curr;
|
||||||
|
loadArticles();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderLotteryTabs().then(loadArticles);
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,750 @@
|
|||||||
|
<!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/mianfei.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/publish.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/mianfeishoucang.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged sc-hidden">
|
||||||
|
<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">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<span>我的收藏</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Summary Cards (also act as tab switcher) -->
|
||||||
|
<div class="sc-stats">
|
||||||
|
<div
|
||||||
|
class="sc-stat-card active"
|
||||||
|
data-tab="free"
|
||||||
|
onclick="switchTab('free')"
|
||||||
|
>
|
||||||
|
<div class="sc-stat-icon gold">
|
||||||
|
<i class="layui-icon layui-icon-star-fill"></i>
|
||||||
|
</div>
|
||||||
|
<div class="sc-stat-info">
|
||||||
|
<div class="sc-stat-value" id="statFree">0</div>
|
||||||
|
<div class="sc-stat-label">免费文章收藏</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sc-stat-card" data-tab="paid" onclick="switchTab('paid')">
|
||||||
|
<div class="sc-stat-icon orange">
|
||||||
|
<i class="layui-icon layui-icon-rmb"></i>
|
||||||
|
</div>
|
||||||
|
<div class="sc-stat-info">
|
||||||
|
<div class="sc-stat-value" id="statPaid">0</div>
|
||||||
|
<div class="sc-stat-label">付费文章收藏</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="sc-stat-card"
|
||||||
|
data-tab="expert"
|
||||||
|
onclick="switchTab('expert')"
|
||||||
|
>
|
||||||
|
<div class="sc-stat-icon blue">
|
||||||
|
<i class="layui-icon layui-icon-friends"></i>
|
||||||
|
</div>
|
||||||
|
<div class="sc-stat-info">
|
||||||
|
<div class="sc-stat-value" id="statExpert">0</div>
|
||||||
|
<div class="sc-stat-label">专家收藏</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Panel: Free Article Collection -->
|
||||||
|
<div class="sc-panel active" id="panelFree">
|
||||||
|
<div class="cxz-collect-grid" id="freeGrid"></div>
|
||||||
|
<div class="cxz-empty sc-hidden" id="freeEmpty">
|
||||||
|
<div class="cxz-empty-icon">
|
||||||
|
<i class="layui-icon layui-icon-star-fill sc-empty-icon-symbol"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-empty-text">暂无免费文章收藏</div>
|
||||||
|
<a href="mianfeilist.html" class="cxz-empty-action">去浏览文章</a>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="freePager"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Panel: Paid Article Collection -->
|
||||||
|
<div class="sc-panel" id="panelPaid">
|
||||||
|
<div class="sc-paid-table" id="paidList"></div>
|
||||||
|
<div class="cxz-empty sc-hidden" id="paidEmpty">
|
||||||
|
<div class="cxz-empty-icon">
|
||||||
|
<i class="layui-icon layui-icon-rmb sc-empty-icon-symbol"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-empty-text">暂无付费文章收藏</div>
|
||||||
|
<a href="cai.html" class="cxz-empty-action">去浏览预测</a>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="paidPager"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Panel: Expert Collection -->
|
||||||
|
<div class="sc-panel" id="panelExpert">
|
||||||
|
<div class="sc-expert-grid" id="expertGrid"></div>
|
||||||
|
<div class="cxz-empty sc-hidden" id="expertEmpty">
|
||||||
|
<div class="cxz-empty-icon">
|
||||||
|
<i class="layui-icon layui-icon-friends sc-empty-icon-symbol"></i>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-empty-text">暂无专家收藏</div>
|
||||||
|
<a href="cai.html" class="cxz-empty-action">去浏览专家</a>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-pagination" id="expertPager"></div>
|
||||||
|
</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"
|
||||||
|
class="site-footer__record"
|
||||||
|
>工信部备案号</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.$;
|
||||||
|
const pageSize = 12;
|
||||||
|
let currentTab = getInitialTab();
|
||||||
|
let freePage = 1;
|
||||||
|
let paidPage = 1;
|
||||||
|
let expertPage = 1;
|
||||||
|
|
||||||
|
const collectTabs = {
|
||||||
|
free: {
|
||||||
|
stat: "#statFree",
|
||||||
|
panel: "#panelFree",
|
||||||
|
grid: "#freeGrid",
|
||||||
|
empty: "#freeEmpty",
|
||||||
|
pager: "freePager",
|
||||||
|
endpoint: getApiPath("mineFreeCollectList", "/api/web/mine/free-collect/list"),
|
||||||
|
cancelText: "确定要取消收藏该免费文章吗?",
|
||||||
|
},
|
||||||
|
paid: {
|
||||||
|
stat: "#statPaid",
|
||||||
|
panel: "#panelPaid",
|
||||||
|
grid: "#paidList",
|
||||||
|
empty: "#paidEmpty",
|
||||||
|
pager: "paidPager",
|
||||||
|
endpoint: getApiPath("minePayCollectList", "/api/web/mine/pay-collect/list"),
|
||||||
|
cancelText: "确定要取消收藏该付费文章吗?",
|
||||||
|
},
|
||||||
|
expert: {
|
||||||
|
stat: "#statExpert",
|
||||||
|
panel: "#panelExpert",
|
||||||
|
grid: "#expertGrid",
|
||||||
|
empty: "#expertEmpty",
|
||||||
|
pager: "expertPager",
|
||||||
|
endpoint: getApiPath("mineExpertCollectList", "/api/web/mine/expert-collect/list"),
|
||||||
|
cancelText: "确定要取消收藏该专家吗?",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function getApiPath(key, fallback) {
|
||||||
|
return ApiClient.API && ApiClient.API[key] ? ApiClient.API[key] : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
if (!CommonUtil.getAuthToken()) {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
$("#userName").text(data.nickName || data.nickname || data.userName || "用户");
|
||||||
|
$("#userLevel").text(data.isExpert === "1" || data.expertStatus ? "专家" : "会员");
|
||||||
|
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 (!ApiClient.isSuccess(res) || !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=' +
|
||||||
|
encodeURIComponent(item.suoxie || item.code || item.id || "") +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
escapeHtml(item.name || item.menuName || "彩种") +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
function switchTab(tab) {
|
||||||
|
if (!collectTabs[tab]) return;
|
||||||
|
currentTab = tab;
|
||||||
|
syncTabToUrl(tab);
|
||||||
|
$(".sc-stat-card").removeClass("active");
|
||||||
|
$('.sc-stat-card[data-tab="' + tab + '"]').addClass("active");
|
||||||
|
$(".sc-panel").removeClass("active");
|
||||||
|
$(collectTabs[tab].panel).addClass("active");
|
||||||
|
loadCurrentTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitialTab() {
|
||||||
|
const tab = new URLSearchParams(window.location.search).get("tab");
|
||||||
|
return tab === "paid" || tab === "expert" ? tab : "free";
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncTabToUrl(tab) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
if (tab === "free") {
|
||||||
|
url.searchParams.delete("tab");
|
||||||
|
} else {
|
||||||
|
url.searchParams.set("tab", tab);
|
||||||
|
}
|
||||||
|
window.history.replaceState(null, "", url.pathname + url.search + url.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyActiveTab() {
|
||||||
|
$(".sc-stat-card").removeClass("active");
|
||||||
|
$('.sc-stat-card[data-tab="' + currentTab + '"]').addClass("active");
|
||||||
|
$(".sc-panel").removeClass("active");
|
||||||
|
$(collectTabs[currentTab].panel).addClass("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCurrentTab() {
|
||||||
|
if (currentTab === "free") loadFreeArticles();
|
||||||
|
else if (currentTab === "paid") loadPaidArticles();
|
||||||
|
else loadExperts();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCollectStats() {
|
||||||
|
Object.keys(collectTabs).forEach(function (tab) {
|
||||||
|
const config = collectTabs[tab];
|
||||||
|
safeGet(config.endpoint, {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 1,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) return;
|
||||||
|
const pageData = normalizePageData(res);
|
||||||
|
$(config.stat).text(pageData.total);
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.warn("获取收藏数量失败:", tab, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCollectPage(tab, page) {
|
||||||
|
const config = collectTabs[tab];
|
||||||
|
setPanelLoading(tab);
|
||||||
|
|
||||||
|
return safeGet(config.endpoint, {
|
||||||
|
pageNum: page,
|
||||||
|
pageSize: pageSize,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) {
|
||||||
|
throw new Error(res && res.msg ? res.msg : "获取收藏列表失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageData = normalizePageData(res);
|
||||||
|
$(config.stat).text(pageData.total);
|
||||||
|
return pageData;
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.error("获取收藏列表失败:", error);
|
||||||
|
$(config.stat).text("0");
|
||||||
|
showEmpty(tab, true);
|
||||||
|
layui.layer.msg(error.message || "获取收藏列表失败", { icon: 2 });
|
||||||
|
return { records: [], total: 0 };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeGet(url, params) {
|
||||||
|
if (!url) {
|
||||||
|
return Promise.reject(new Error("缺少接口地址"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ApiClient.get(url, params);
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePageData(res) {
|
||||||
|
const data = res.data && typeof res.data === "object" ? res.data : res;
|
||||||
|
const records = ApiClient.asArray(
|
||||||
|
data.records || data.rows || data.list || res.rows || data,
|
||||||
|
);
|
||||||
|
const total = Number(data.total || data.totalRow || res.total || records.length || 0);
|
||||||
|
return { records: records, total: total };
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFreeArticles() {
|
||||||
|
loadCollectPage("free", freePage).then(function (pageData) {
|
||||||
|
renderFreeArticles(pageData.records);
|
||||||
|
renderPager("free", pageData.total, freePage, function (page) {
|
||||||
|
freePage = page;
|
||||||
|
loadFreeArticles();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFreeArticles(list) {
|
||||||
|
const $grid = $("#freeGrid");
|
||||||
|
$grid.empty();
|
||||||
|
showEmpty("free", !list.length);
|
||||||
|
if (!list.length) return;
|
||||||
|
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
const articleId = getArticleId(item);
|
||||||
|
const title = getField(item, ["title", "articleTitle", "name"], "未命名文章");
|
||||||
|
const author = CommonUtil.getFreeArticleIssuer
|
||||||
|
? CommonUtil.getFreeArticleIssuer(item)
|
||||||
|
: getField(item, ["issuer", "author", "authorName", "nickName", "nickname"], "--");
|
||||||
|
const displayDate = formatTime(getField(item, ["collectTime", "createTime", "createdTime"], ""));
|
||||||
|
const href = buildFreeArticleHref(item, articleId);
|
||||||
|
|
||||||
|
$grid.append(
|
||||||
|
'<div class="cxz-collect-card" data-article-id="' +
|
||||||
|
escapeAttr(articleId) +
|
||||||
|
'">' +
|
||||||
|
'<div class="cxz-card-body">' +
|
||||||
|
'<div class="cxz-card-title"><a href="' +
|
||||||
|
escapeAttr(href) +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(title) +
|
||||||
|
"</a></div>" +
|
||||||
|
'<div class="cxz-card-meta">' +
|
||||||
|
"<span>" +
|
||||||
|
escapeHtml(author || "--") +
|
||||||
|
"</span>" +
|
||||||
|
"<span>" +
|
||||||
|
escapeHtml(displayDate || "--") +
|
||||||
|
"</span>" +
|
||||||
|
'<button class="cxz-card-remove" type="button" onclick="removeCollect(this, \'free\', \''
|
||||||
|
+ escapeJs(articleId) +
|
||||||
|
'\')">取消收藏</button>' +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPaidArticles() {
|
||||||
|
loadCollectPage("paid", paidPage).then(function (pageData) {
|
||||||
|
renderPaidArticles(pageData.records);
|
||||||
|
renderPager("paid", pageData.total, paidPage, function (page) {
|
||||||
|
paidPage = page;
|
||||||
|
loadPaidArticles();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPaidArticles(list) {
|
||||||
|
const $list = $("#paidList");
|
||||||
|
$list.empty();
|
||||||
|
showEmpty("paid", !list.length);
|
||||||
|
if (!list.length) return;
|
||||||
|
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
const articleId = getArticleId(item);
|
||||||
|
const expertId = getField(item, ["expertId", "createBy", "userId"], "");
|
||||||
|
const expertName = getField(item, ["expertName", "nickName", "nickname", "authorName"], "专家");
|
||||||
|
const avatar = getField(item, ["avatar", "headImg", "headImage"], "");
|
||||||
|
const title = getField(item, ["title", "articleTitle", "name"], "未命名方案");
|
||||||
|
const issue = getField(item, ["issue", "expect", "period"], "--");
|
||||||
|
const price = getField(item, ["price", "amount", "points", "score"], 0);
|
||||||
|
const collectTime = formatTime(getField(item, ["collectTime", "createTime", "createdTime"], ""));
|
||||||
|
const href = buildPayArticleHref(item);
|
||||||
|
const avatarHtml = avatar
|
||||||
|
? '<img class="sc-expert-avatar" src="' + escapeAttr(avatar) + '" />'
|
||||||
|
: '<div class="sc-expert-avatar-fallback">' + escapeHtml(String(expertName).charAt(0) || "专") + "</div>";
|
||||||
|
|
||||||
|
$list.append(
|
||||||
|
'<div class="sc-paid-row" data-article-id="' +
|
||||||
|
escapeAttr(articleId) +
|
||||||
|
'">' +
|
||||||
|
'<a class="sc-expert-cell" href="' +
|
||||||
|
escapeAttr(buildExpertHref(item, expertId, getField(item, ["accountType"], 1))) +
|
||||||
|
'">' +
|
||||||
|
avatarHtml +
|
||||||
|
'<span class="sc-expert-name">' +
|
||||||
|
escapeHtml(expertName) +
|
||||||
|
"</span></a>" +
|
||||||
|
'<span class="sc-paid-period">第' +
|
||||||
|
escapeHtml(issue) +
|
||||||
|
"期</span>" +
|
||||||
|
'<span class="sc-paid-title"><a href="' +
|
||||||
|
escapeAttr(href) +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(title) +
|
||||||
|
"</a></span>" +
|
||||||
|
'<span class="sc-paid-price">' +
|
||||||
|
escapeHtml(price) +
|
||||||
|
"积分</span>" +
|
||||||
|
'<span class="sc-paid-time">' +
|
||||||
|
escapeHtml(collectTime || "--") +
|
||||||
|
"</span>" +
|
||||||
|
'<a class="sc-paid-view" href="' +
|
||||||
|
escapeAttr(href) +
|
||||||
|
'">查看</a>' +
|
||||||
|
'<button class="sc-paid-remove" type="button" onclick="removeCollect(this, \'paid\', \''
|
||||||
|
+ escapeJs(articleId) +
|
||||||
|
'\')">取消收藏</button>' +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadExperts() {
|
||||||
|
loadCollectPage("expert", expertPage).then(function (pageData) {
|
||||||
|
renderExperts(pageData.records);
|
||||||
|
renderPager("expert", pageData.total, expertPage, function (page) {
|
||||||
|
expertPage = page;
|
||||||
|
loadExperts();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderExperts(list) {
|
||||||
|
const $grid = $("#expertGrid");
|
||||||
|
$grid.empty();
|
||||||
|
showEmpty("expert", !list.length);
|
||||||
|
if (!list.length) return;
|
||||||
|
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
const expertId = getField(item, ["expertId", "id", "userId", "createBy"], "");
|
||||||
|
const accountType = getField(item, ["accountType"], 1);
|
||||||
|
const name = getField(item, ["expertName", "name", "nickName", "nickname"], "未知专家");
|
||||||
|
const avatar = getField(item, ["avatar", "headImg", "headImage"], "");
|
||||||
|
const collectTime = formatTime(getField(item, ["collectTime", "createTime", "createdTime"], ""));
|
||||||
|
const typeText = isTruthy(getField(item, ["regularExpert", "isRegularExpert"], false))
|
||||||
|
? "正式专家"
|
||||||
|
: "实习专家";
|
||||||
|
const href = buildExpertHref(item, expertId, accountType);
|
||||||
|
const avatarHtml = avatar
|
||||||
|
? '<img class="sc-expert-card-avatar" src="' + escapeAttr(avatar) + '" />'
|
||||||
|
: '<div class="sc-expert-card-avatar-fallback">' + escapeHtml(String(name).charAt(0) || "专") + "</div>";
|
||||||
|
|
||||||
|
$grid.append(
|
||||||
|
'<div class="sc-expert-card" data-expert-id="' +
|
||||||
|
escapeAttr(expertId) +
|
||||||
|
'">' +
|
||||||
|
avatarHtml +
|
||||||
|
'<div class="sc-expert-card-name">' +
|
||||||
|
escapeHtml(name) +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="sc-expert-card-type">' +
|
||||||
|
escapeHtml(typeText) +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="sc-expert-card-stats">' +
|
||||||
|
'<div class="sc-expert-card-stat"><div class="val">' +
|
||||||
|
escapeHtml(collectTime ? collectTime.slice(0, 10) : "--") +
|
||||||
|
'</div><div class="lbl">收藏时间</div></div>' +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="sc-expert-card-actions">' +
|
||||||
|
'<a class="sc-paid-view" href="' +
|
||||||
|
escapeAttr(href) +
|
||||||
|
'">查看</a>' +
|
||||||
|
'<button class="sc-paid-remove" type="button" onclick="removeCollect(this, \'expert\', \''
|
||||||
|
+ escapeJs(expertId) +
|
||||||
|
"\', \'" +
|
||||||
|
escapeJs(accountType) +
|
||||||
|
'\')">取消收藏</button>' +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCollect(btn, type, id, accountType) {
|
||||||
|
if (!id) {
|
||||||
|
layui.layer.msg("缺少收藏对象ID,暂不能操作", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = collectTabs[type] || collectTabs[currentTab];
|
||||||
|
layui.layer.confirm(
|
||||||
|
config.cancelText,
|
||||||
|
{ icon: 3, title: "提示" },
|
||||||
|
function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
getCancelRequest(type, id, accountType).then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res)) {
|
||||||
|
layui.layer.msg("已取消收藏", { icon: 1 });
|
||||||
|
removeCard(btn, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layui.layer.msg(res.msg || "取消收藏失败", { icon: 2 });
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.error("取消收藏失败:", error);
|
||||||
|
layui.layer.msg("网络异常,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCancelRequest(type, id, accountType) {
|
||||||
|
if (type === "expert") {
|
||||||
|
const url = ApiClient.API && ApiClient.API.expertCollect
|
||||||
|
? ApiClient.API.expertCollect(id, accountType || 1)
|
||||||
|
: "/api/web/pay-article/expert-collect?" +
|
||||||
|
new URLSearchParams({
|
||||||
|
expertId: String(id || ""),
|
||||||
|
accountType: String(accountType || 1),
|
||||||
|
}).toString();
|
||||||
|
return ApiClient.post(url, {});
|
||||||
|
}
|
||||||
|
if (type === "paid") {
|
||||||
|
const url = ApiClient.API && ApiClient.API.payArticleCollect
|
||||||
|
? ApiClient.API.payArticleCollect(id)
|
||||||
|
: "/api/web/pay-article/article-collect/" + encodeURIComponent(id);
|
||||||
|
return ApiClient.post(url, {});
|
||||||
|
}
|
||||||
|
const url = ApiClient.API && ApiClient.API.freeArticleCollect
|
||||||
|
? ApiClient.API.freeArticleCollect(id)
|
||||||
|
: "/api/web/free-article/" + encodeURIComponent(id) + "/collect";
|
||||||
|
return ApiClient.post(url, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCard(btn, type) {
|
||||||
|
const selector = type === "expert" ? ".sc-expert-card" : type === "paid" ? ".sc-paid-row" : ".cxz-collect-card";
|
||||||
|
const $card = $(btn).closest(selector);
|
||||||
|
$card.addClass("removing");
|
||||||
|
setTimeout(function () {
|
||||||
|
$card.remove();
|
||||||
|
const config = collectTabs[type];
|
||||||
|
const left = $(config.grid).find(selector).length;
|
||||||
|
const total = Math.max(0, Number($(config.stat).text()) - 1);
|
||||||
|
$(config.stat).text(total);
|
||||||
|
if (left === 0) loadCurrentTab();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPanelLoading(tab) {
|
||||||
|
const config = collectTabs[tab];
|
||||||
|
$(config.grid)
|
||||||
|
.empty()
|
||||||
|
.html('<div class="sc-loading">正在加载收藏数据...</div>');
|
||||||
|
$(config.empty).addClass("sc-hidden").hide();
|
||||||
|
$("#" + config.pager).empty().hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEmpty(tab, isEmpty) {
|
||||||
|
const config = collectTabs[tab];
|
||||||
|
if (isEmpty) {
|
||||||
|
$(config.grid).empty();
|
||||||
|
$(config.empty).removeClass("sc-hidden").css("display", "flex");
|
||||||
|
} else {
|
||||||
|
$(config.empty).addClass("sc-hidden").hide();
|
||||||
|
}
|
||||||
|
$("#" + config.pager).toggle(!isEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPager(tab, total, curr, onJump) {
|
||||||
|
const config = collectTabs[tab];
|
||||||
|
const $pager = $("#" + config.pager);
|
||||||
|
if (!total || total <= pageSize) {
|
||||||
|
$pager.empty().hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pager.show();
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: config.pager,
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: curr,
|
||||||
|
layout: ["prev", "page", "next"],
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) onJump(obj.curr);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArticleId(item) {
|
||||||
|
return getField(item, ["articleId", "payArticleId", "freeArticleId", "id", "collectArticleId"], "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFreeArticleHref(item, articleId) {
|
||||||
|
return safeHref(
|
||||||
|
getField(item, ["url", "link"], "") ||
|
||||||
|
CommonUtil.freeArticleHref(articleId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPayArticleHref(item) {
|
||||||
|
const expertId = getField(item, ["expertId", "createBy", "userId"], "");
|
||||||
|
const articleId = getArticleId(item);
|
||||||
|
const code = getField(item, ["code", "lotteryCode", "menuCode"], "");
|
||||||
|
const menuId = getField(item, ["menuId", "parentId", "lotteryId"], "");
|
||||||
|
const accountType = getField(item, ["accountType"], 1);
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (expertId) params.set("expertId", expertId);
|
||||||
|
if (articleId) params.set("articleId", articleId);
|
||||||
|
if (code) params.set("code", code);
|
||||||
|
if (menuId) params.set("menuId", menuId);
|
||||||
|
params.set("accountType", accountType || 1);
|
||||||
|
return params.toString() ? siteHref("/caiinfo.html?" + params.toString()) : "#";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildExpertHref(item, expertId, accountType) {
|
||||||
|
const code = getField(item, ["code", "lotteryCode", "menuCode"], "");
|
||||||
|
const menuId = getField(item, ["menuId", "parentId", "lotteryId"], "");
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (expertId) params.set("expertId", expertId);
|
||||||
|
if (code) params.set("code", code);
|
||||||
|
if (menuId) params.set("menuId", menuId);
|
||||||
|
params.set("accountType", accountType || 1);
|
||||||
|
return siteHref("/caiinfo.html?" + params.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
function siteHref(path) {
|
||||||
|
if (CommonUtil.siteHref) return CommonUtil.siteHref(path);
|
||||||
|
const cleanPath = String(path || "");
|
||||||
|
if (/^https?:\/\//i.test(cleanPath) || cleanPath.indexOf("../") === 0) return cleanPath;
|
||||||
|
return cleanPath.charAt(0) === "/" ? "." + cleanPath : cleanPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeHref(value) {
|
||||||
|
if (CommonUtil.safeHref) return CommonUtil.safeHref(value);
|
||||||
|
const href = String(value || "#").trim();
|
||||||
|
if (!href || /^javascript:/i.test(href)) return "#";
|
||||||
|
return href;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getField(item, keys, fallback) {
|
||||||
|
for (let i = 0; i < keys.length; i += 1) {
|
||||||
|
const value = item && item[keys[i]];
|
||||||
|
if (value !== undefined && value !== null && value !== "") return value;
|
||||||
|
}
|
||||||
|
return fallback || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(value) {
|
||||||
|
if (!value) return "";
|
||||||
|
if (typeof DateUtil !== "undefined" && DateUtil.formatDateTimeToYMDHM) {
|
||||||
|
return DateUtil.formatDateTimeToYMDHM(value);
|
||||||
|
}
|
||||||
|
return String(value).slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTruthy(value) {
|
||||||
|
return value === true || value === 1 || value === "1" || String(value).toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return CommonUtil.escapeHtml(String(value == null ? "" : value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeAttr(value) {
|
||||||
|
return escapeHtml(value).replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeJs(value) {
|
||||||
|
return String(value == null ? "" : value).replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
currentTab = getInitialTab();
|
||||||
|
checkLogin();
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
renderNav();
|
||||||
|
applyActiveTab();
|
||||||
|
refreshCollectStats();
|
||||||
|
loadCurrentTab();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,409 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>排列三走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">排列三走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="3" rowspan="2" class="zone-type">类型</td>
|
||||||
|
<td colspan="10" class="zone-hundred">百位</td>
|
||||||
|
<td colspan="10" class="zone-ten">十位</td>
|
||||||
|
<td colspan="10" class="zone-unit">个位</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var g = 0; g < 3; g++) {
|
||||||
|
for (var i = 0; i <= 9; i++) html += "<td>" + i + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(code) {
|
||||||
|
var nums = code.split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
hundred: nums[0] || 0,
|
||||||
|
ten: nums[1] || 0,
|
||||||
|
unit: nums[2] || 0,
|
||||||
|
nums: nums,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType(h, t, u) {
|
||||||
|
if (h === t && t === u) return "baozi";
|
||||||
|
if (h === t || t === u || h === u) return "zu3";
|
||||||
|
return "zu6";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var parsed = parseCode(item.openCode);
|
||||||
|
var type = getType(parsed.hundred, parsed.ten, parsed.unit);
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
var typeNames = ["baozi", "zu3", "zu6"];
|
||||||
|
var typeLabels = ["豹子", "组三", "组六"];
|
||||||
|
for (var ti = 0; ti < 3; ti++) {
|
||||||
|
if (type === typeNames[ti]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="type-' +
|
||||||
|
typeNames[ti] +
|
||||||
|
'">' +
|
||||||
|
typeLabels[ti] +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="type-empty">' +
|
||||||
|
typeLabels[ti] +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.hundred === i)
|
||||||
|
html += '<td><span class="hit-hundred">' + i + "</span></td>";
|
||||||
|
else html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.ten === i)
|
||||||
|
html += '<td><span class="hit-ten">' + i + "</span></td>";
|
||||||
|
else html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (parsed.unit === i)
|
||||||
|
html += '<td><span class="hit-unit">' + i + "</span></td>";
|
||||||
|
else html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcPosStats(data, getVal) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
if (getVal(data[r]) === i) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcTypeStats(data, typeName) {
|
||||||
|
var count = 0,
|
||||||
|
maxOmit = 0,
|
||||||
|
currOmit = 0,
|
||||||
|
maxConsec = 0,
|
||||||
|
avgOmit = 0;
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var p = parseCode(data[r].openCode);
|
||||||
|
var t = getType(p.hundred, p.ten, p.unit);
|
||||||
|
if (t === typeName) {
|
||||||
|
count++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: mo,
|
||||||
|
currOmit: omit,
|
||||||
|
maxConsec: mc,
|
||||||
|
avgOmit: oc > 0 ? (totalOmit / oc).toFixed(1) : data.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var hs = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).hundred;
|
||||||
|
});
|
||||||
|
var ts = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).ten;
|
||||||
|
});
|
||||||
|
var us = calcPosStats(data, function (d) {
|
||||||
|
return parseCode(d.openCode).unit;
|
||||||
|
});
|
||||||
|
var bz = calcTypeStats(data, "baozi");
|
||||||
|
var z3 = calcTypeStats(data, "zu3");
|
||||||
|
var z6 = calcTypeStats(data, "zu6");
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var typeStats = [bz, z3, z6];
|
||||||
|
var stats = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var ti = 0; ti < 3; ti++)
|
||||||
|
stats += "<td>" + typeStats[ti][keys[li]] + "</td>";
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + hs[keys[li]][i] + "</td>";
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + ts[keys[li]][i] + "</td>";
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + us[keys[li]][i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "pl3" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>排列五走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">排列五走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="10" class="zone-p1">万位</td>
|
||||||
|
<td colspan="10" class="zone-p2">千位</td>
|
||||||
|
<td colspan="10" class="zone-p3">百位</td>
|
||||||
|
<td colspan="10" class="zone-p4">十位</td>
|
||||||
|
<td colspan="10" class="zone-p5">个位</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var POS_COUNT = 5;
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
var posNames = ["万位", "千位", "百位", "十位", "个位"];
|
||||||
|
var hitClasses = [
|
||||||
|
"hit-pos1",
|
||||||
|
"hit-pos2",
|
||||||
|
"hit-pos3",
|
||||||
|
"hit-pos4",
|
||||||
|
"hit-pos5",
|
||||||
|
];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var g = 0; g < POS_COUNT; g++) {
|
||||||
|
for (var i = 0; i <= 9; i++) html += "<td>" + i + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(code) {
|
||||||
|
return code.split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var nums = parseCode(item.openCode);
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
for (var p = 0; p < POS_COUNT; p++) {
|
||||||
|
var val = nums[p] !== undefined ? nums[p] : -1;
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
if (val === i) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="' +
|
||||||
|
hitClasses[p] +
|
||||||
|
'">' +
|
||||||
|
i +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcPosStats(data, posIdx) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= 9; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var nums = parseCode(data[r].openCode);
|
||||||
|
if (nums[posIdx] === i) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var posStats = [];
|
||||||
|
for (var p = 0; p < POS_COUNT; p++)
|
||||||
|
posStats.push(calcPosStats(data, p));
|
||||||
|
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var stats = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var p = 0; p < POS_COUNT; p++) {
|
||||||
|
for (var i = 0; i <= 9; i++)
|
||||||
|
stats += "<td>" + posStats[p][keys[li]][i] + "</td>";
|
||||||
|
}
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "pl5" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>七乐彩走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">七乐彩走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="10" class="zone-z1">一区(01-10)</td>
|
||||||
|
<td colspan="10" class="zone-z2">二区(11-20)</td>
|
||||||
|
<td colspan="10" class="zone-z3">三区(21-30)</td>
|
||||||
|
<td colspan="1" class="zone-sp">特别号</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var MAIN_MAX = 30;
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var i = 1; i <= MAIN_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
// Special number column
|
||||||
|
html += "<td>特</td>";
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse openCode like "01,05,12,18,23,27,30+08"
|
||||||
|
function parseCode(code) {
|
||||||
|
var parts = code.split("+");
|
||||||
|
var mains = parts[0].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
var specials = parts[1]
|
||||||
|
? parts[1].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
return { mains: mains, specials: specials };
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var parsed = parseCode(item.openCode);
|
||||||
|
var mainSet = {},
|
||||||
|
specialSet = {};
|
||||||
|
parsed.mains.forEach(function (n) {
|
||||||
|
mainSet[n] = true;
|
||||||
|
});
|
||||||
|
parsed.specials.forEach(function (n) {
|
||||||
|
specialSet[n] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
for (var i = 1; i <= MAIN_MAX; i++) {
|
||||||
|
if (mainSet[i]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-main">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Show special number
|
||||||
|
if (parsed.specials.length > 0) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-special">' +
|
||||||
|
(parsed.specials[0] < 10
|
||||||
|
? "0" + parsed.specials[0]
|
||||||
|
: parsed.specials[0]) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html += "<td>-</td>";
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcStats(data, maxNum, getNums) {
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= maxNum; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var nums = getNums(data[r]);
|
||||||
|
if (nums.indexOf(i) >= 0) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var ms = calcStats(data, MAIN_MAX, function (d) {
|
||||||
|
return parseCode(d.openCode).mains;
|
||||||
|
});
|
||||||
|
// Special number stats (1-30 range for special)
|
||||||
|
var ss = calcStats(data, MAIN_MAX, function (d) {
|
||||||
|
return parseCode(d.openCode).specials;
|
||||||
|
});
|
||||||
|
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var stats = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var i = 1; i <= MAIN_MAX; i++)
|
||||||
|
stats += "<td>" + ms[keys[li]][i] + "</td>";
|
||||||
|
// Special column stats
|
||||||
|
stats += "<td>-</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "qlc" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>七星彩走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">七星彩走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第一位</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第二位</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第三位</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第四位</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第五位</td>
|
||||||
|
<td colspan="10" class="zone-0to9">第六位</td>
|
||||||
|
<td colspan="15" class="zone-last">第七位</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var POS_COUNT = 7;
|
||||||
|
var LAST_MAX = 14; // Last position 0-14
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
var hitClasses = [
|
||||||
|
"hit-p1",
|
||||||
|
"hit-p2",
|
||||||
|
"hit-p3",
|
||||||
|
"hit-p4",
|
||||||
|
"hit-p5",
|
||||||
|
"hit-p6",
|
||||||
|
"hit-p7",
|
||||||
|
];
|
||||||
|
var posMaxes = [9, 9, 9, 9, 9, 9, LAST_MAX]; // max value for each position
|
||||||
|
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var p = 0; p < POS_COUNT; p++) {
|
||||||
|
var max = posMaxes[p];
|
||||||
|
for (var i = 0; i <= max; i++) html += "<td>" + i + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(code) {
|
||||||
|
var nums = code.split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
return nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var nums = parseCode(item.openCode);
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html += '<td class="col-code">' + item.openCode + "</td>";
|
||||||
|
|
||||||
|
for (var p = 0; p < POS_COUNT; p++) {
|
||||||
|
var max = posMaxes[p];
|
||||||
|
var val = nums[p] !== undefined ? nums[p] : -1;
|
||||||
|
for (var i = 0; i <= max; i++) {
|
||||||
|
if (val === i) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="' +
|
||||||
|
hitClasses[p] +
|
||||||
|
'">' +
|
||||||
|
i +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html += '<td><span class="miss-num">' + i + "</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcPosStats(data, posIdx) {
|
||||||
|
var max = posMaxes[posIdx];
|
||||||
|
var count = {},
|
||||||
|
maxOmit = {},
|
||||||
|
currOmit = {},
|
||||||
|
maxConsec = {},
|
||||||
|
avgOmit = {};
|
||||||
|
for (var i = 0; i <= max; i++) {
|
||||||
|
count[i] = 0;
|
||||||
|
maxOmit[i] = 0;
|
||||||
|
currOmit[i] = 0;
|
||||||
|
maxConsec[i] = 0;
|
||||||
|
avgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i <= max; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
mo = 0,
|
||||||
|
consec = 0,
|
||||||
|
mc = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
oc = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var nums = parseCode(data[r].openCode);
|
||||||
|
if (nums[posIdx] === i) {
|
||||||
|
count[i]++;
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
oc++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > mc) mc = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > mo) mo = omit;
|
||||||
|
currOmit[i] = omit;
|
||||||
|
maxOmit[i] = mo;
|
||||||
|
maxConsec[i] = mc;
|
||||||
|
avgOmit[i] = oc > 0 ? (totalOmit / oc).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
count: count,
|
||||||
|
maxOmit: maxOmit,
|
||||||
|
currOmit: currOmit,
|
||||||
|
maxConsec: maxConsec,
|
||||||
|
avgOmit: avgOmit,
|
||||||
|
max: max,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStats(data) {
|
||||||
|
var posStats = [];
|
||||||
|
for (var p = 0; p < POS_COUNT; p++)
|
||||||
|
posStats.push(calcPosStats(data, p));
|
||||||
|
|
||||||
|
var labels = [
|
||||||
|
"出现次数",
|
||||||
|
"最大遗漏",
|
||||||
|
"平均遗漏",
|
||||||
|
"最大连出",
|
||||||
|
"当前遗漏",
|
||||||
|
];
|
||||||
|
var keys = ["count", "maxOmit", "avgOmit", "maxConsec", "currOmit"];
|
||||||
|
var stats = "";
|
||||||
|
for (var li = 0; li < labels.length; li++) {
|
||||||
|
var cls = li % 2 === 0 ? "stat-row" : "stat-row alt";
|
||||||
|
stats +=
|
||||||
|
'<tr class="' +
|
||||||
|
cls +
|
||||||
|
'"><td colspan="2" class="stat-label">' +
|
||||||
|
labels[li] +
|
||||||
|
"</td>";
|
||||||
|
for (var p = 0; p < POS_COUNT; p++) {
|
||||||
|
for (var i = 0; i <= posStats[p].max; i++)
|
||||||
|
stats += "<td>" + posStats[p][keys[li]][i] + "</td>";
|
||||||
|
}
|
||||||
|
stats += "</tr>";
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "qxc" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,520 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title id="page-title">彩先知 - 注册</title>
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../utils/AuthPageUtil.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/auth.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="auth-container">
|
||||||
|
<div class="auth-card">
|
||||||
|
<div class="auth-header">
|
||||||
|
<a class="auth-logo" href="index.html" aria-label="返回首页">
|
||||||
|
<img src="../images/cxz-logo.png" alt="彩先知" />
|
||||||
|
</a>
|
||||||
|
<div class="auth-subtitle">CaiXianZhi - 新用户注册</div>
|
||||||
|
</div>
|
||||||
|
<div class="auth-body">
|
||||||
|
<form id="registerForm" autocomplete="off">
|
||||||
|
<div class="form-group" id="nicknameContainer">
|
||||||
|
<label for="nickname">昵称</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="nickname"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入昵称(2-20个字符)"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="nicknameError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="phoneContainer">
|
||||||
|
<label for="phone">手机号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="phone"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
maxlength="11"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="phoneError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="captchaGroup">
|
||||||
|
<label for="captchaInput">滑动验证</label>
|
||||||
|
<div class="captcha-row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="captchaInput"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
maxlength="6"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="captcha-img-box"
|
||||||
|
id="captchaContainer"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
<img id="captchaImage" src="" alt="验证码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="captcha-refresh-link"
|
||||||
|
id="captchaRefreshLink"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
看不清?换一张
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="captchaError"></div>
|
||||||
|
<input type="hidden" id="captchaId" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="smsCodeContainer">
|
||||||
|
<label for="smsCode">短信验证码</label>
|
||||||
|
<div class="auth-sms-row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="smsCode"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入短信验证码"
|
||||||
|
maxlength="6"
|
||||||
|
/>
|
||||||
|
<button type="button" class="auth-sms-button" id="sendSmsBtn">
|
||||||
|
获取验证码
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="smsCodeError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="passwordContainer">
|
||||||
|
<label for="password">密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入密码(6-20位)"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="passwordError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="confirmPasswordContainer">
|
||||||
|
<label for="confirmPassword">确认密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="confirmPassword"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请再次输入密码"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="confirmPasswordError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="auth-submit-btn" id="registerBtn">
|
||||||
|
确认注册
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="auth-agreement">
|
||||||
|
<input type="checkbox" id="agreementCheckbox" />
|
||||||
|
<span>已阅读并同意</span>
|
||||||
|
<a href="yonghuxieyi.html" target="_blank">《彩先知用户协议》</a>
|
||||||
|
<a href="yinsixieyi.html" target="_blank">《彩先知隐私政策》</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="auth-links">
|
||||||
|
<a href="login.html">已有账号?立即登录</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="../public/js/jquery.js"></script>
|
||||||
|
<script src="../public/js/md5.js"></script>
|
||||||
|
<script>
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
const $ = layui.$;
|
||||||
|
let layerInstance = null;
|
||||||
|
let currentCaptchaId = "";
|
||||||
|
let currentVerifyType = "captcha";
|
||||||
|
let currentSlideUuid = "";
|
||||||
|
let currentSlideX = 0;
|
||||||
|
let pendingSmsAfterVerify = false;
|
||||||
|
let referralPreviewData = null;
|
||||||
|
|
||||||
|
function showError(field, message) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.text(message)
|
||||||
|
.show();
|
||||||
|
$("#" + containerId).addClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearError(field) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.hide()
|
||||||
|
.text("");
|
||||||
|
$("#" + containerId).removeClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadVerifyConfig() {
|
||||||
|
return AuthPageUtil.loadVerifyType().then(function (type) {
|
||||||
|
currentVerifyType = type;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCaptcha() {
|
||||||
|
currentCaptchaId = "";
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
$("#captchaId").val("");
|
||||||
|
$("#captchaInput").val("");
|
||||||
|
$("#captchaGroup").removeClass("is-slide-mode");
|
||||||
|
$("#sendSmsBtn").prop("disabled", currentVerifyType === "slide");
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#captchaInput").show();
|
||||||
|
$("#captchaRefreshLink").show().text("看不清?换一张");
|
||||||
|
$("#captchaContainer")
|
||||||
|
.attr("onclick", "refreshCaptcha()")
|
||||||
|
.html('<img id="captchaImage" src="" alt="验证码" />');
|
||||||
|
$("#captchaImage").attr("src", ApiClient.transparentGif());
|
||||||
|
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);
|
||||||
|
$("#captchaImage").attr(
|
||||||
|
"src",
|
||||||
|
res.data.img || res.data.image || "",
|
||||||
|
);
|
||||||
|
clearError("captcha");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layerInstance.msg(
|
||||||
|
"获取验证码失败:" + ((res && res.msg) || "未知错误"),
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layerInstance.msg("网络错误,无法获取验证码", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeSlideCaptcha(result) {
|
||||||
|
const data = result || {};
|
||||||
|
const nested = data.data || {};
|
||||||
|
currentSlideUuid =
|
||||||
|
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
|
||||||
|
currentSlideX =
|
||||||
|
Number(data.slideX || data.x || nested.slideX || nested.x || 0) || 0;
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
layerInstance.msg("滑动验证未返回凭证,请重试", { icon: 2 });
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#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);
|
||||||
|
if (pendingSmsAfterVerify) {
|
||||||
|
pendingSmsAfterVerify = false;
|
||||||
|
sendSmsCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSlideCaptcha() {
|
||||||
|
AuthPageUtil.loadSlideCaptchaScript()
|
||||||
|
.then(function (SlideCaptcha) {
|
||||||
|
SlideCaptcha.open({
|
||||||
|
title: "注册安全验证",
|
||||||
|
subtitle: "拖动滑块完成验证后继续注册",
|
||||||
|
apiBase: ApiClient.baseUrl || "",
|
||||||
|
onSuccess: completeSlideCaptcha,
|
||||||
|
onCancel: function () {
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
},
|
||||||
|
onError: function (error) {
|
||||||
|
layerInstance.msg(
|
||||||
|
(error && error.message) || "滑动验证失败,请重试",
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
layerInstance.msg(error.message || "滑动验证组件加载失败", {
|
||||||
|
icon: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSlideCaptchaEntry() {
|
||||||
|
$("#captchaInput").hide();
|
||||||
|
$("#captchaRefreshLink").hide();
|
||||||
|
$("#captchaGroup").addClass("is-slide-mode");
|
||||||
|
$("#sendSmsBtn").prop("disabled", true);
|
||||||
|
$("#captchaContainer")
|
||||||
|
.removeAttr("onclick")
|
||||||
|
.html(
|
||||||
|
'<div class="slide-verify-card" role="button" tabindex="0"><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>',
|
||||||
|
);
|
||||||
|
$(".slide-verify-card")
|
||||||
|
.off("click keydown")
|
||||||
|
.on("click", openSlideCaptcha)
|
||||||
|
.on("keydown", function (event) {
|
||||||
|
if (event.key === "Enter" || event.key === " ") {
|
||||||
|
event.preventDefault();
|
||||||
|
openSlideCaptcha();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateNickname(show) {
|
||||||
|
const value = $("#nickname").val().trim();
|
||||||
|
if (value.length < 2 || value.length > 20) {
|
||||||
|
if (show) showError("nickname", "昵称长度应为2-20个字符");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("nickname");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePhone(show) {
|
||||||
|
const value = $("#phone").val().trim();
|
||||||
|
if (!AuthPageUtil.isPhone(value)) {
|
||||||
|
if (show) showError("phone", "请输入正确的手机号");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("phone");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateSmsCode(show) {
|
||||||
|
const value = $("#smsCode").val().trim();
|
||||||
|
if (!/^\d{4,6}$/.test(value)) {
|
||||||
|
if (show) showError("smsCode", "请输入4-6位短信验证码");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("smsCode");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassword(show) {
|
||||||
|
if (!AuthPageUtil.isPassword($("#password").val())) {
|
||||||
|
if (show) showError("password", "密码长度应为6-20位");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("password");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateConfirmPassword(show) {
|
||||||
|
if ($("#confirmPassword").val() !== $("#password").val()) {
|
||||||
|
if (show) showError("confirmPassword", "两次输入的密码不一致");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("confirmPassword");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVerifyParams(show) {
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
if (show) layerInstance.msg("请先完成滑动验证", { icon: 2 });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
verifyType: "slide",
|
||||||
|
slideUuid: currentSlideUuid,
|
||||||
|
slideX: currentSlideX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const code = $("#captchaInput").val().trim();
|
||||||
|
if (!code || !currentCaptchaId) {
|
||||||
|
if (show) showError("captcha", "请填写有效验证码");
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.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();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
$("#sendSmsBtn").prop("disabled", false);
|
||||||
|
layerInstance.msg("网络异常,短信发送失败", { icon: 2 });
|
||||||
|
refreshCaptcha();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
if (
|
||||||
|
!validateNickname(true) ||
|
||||||
|
!validatePhone(true) ||
|
||||||
|
!validateSmsCode(true) ||
|
||||||
|
!validatePassword(true) ||
|
||||||
|
!validateConfirmPassword(true)
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (!getVerifyParams(true)) return false;
|
||||||
|
if (!$("#agreementCheckbox").prop("checked")) {
|
||||||
|
layerInstance.msg("请阅读并同意用户协议和隐私政策", { icon: 2 });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRegisterData() {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const referrerId =
|
||||||
|
(referralPreviewData &&
|
||||||
|
(referralPreviewData.referrerId ||
|
||||||
|
referralPreviewData.userId ||
|
||||||
|
referralPreviewData.id)) ||
|
||||||
|
params.get("referrerId") ||
|
||||||
|
params.get("pid") ||
|
||||||
|
0;
|
||||||
|
return Object.assign(
|
||||||
|
{
|
||||||
|
phoneNumber: $("#phone").val().trim(),
|
||||||
|
password: hex_md5($("#password").val()),
|
||||||
|
smsCode: $("#smsCode").val().trim(),
|
||||||
|
nickname: $("#nickname").val().trim(),
|
||||||
|
referrerId: referrerId,
|
||||||
|
},
|
||||||
|
getVerifyParams(false) || {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadReferralBindPreview() {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const inviteCode =
|
||||||
|
params.get("inviteCode") || params.get("referralCode") || "";
|
||||||
|
if (!inviteCode) return;
|
||||||
|
ApiClient.get(
|
||||||
|
ApiClient.API.referralBindPreview,
|
||||||
|
{ inviteCode: inviteCode },
|
||||||
|
{ publicRequest: true },
|
||||||
|
)
|
||||||
|
.then(function (res) {
|
||||||
|
if (!ApiClient.isSuccess(res)) return;
|
||||||
|
referralPreviewData = ApiClient.pickData(res, {}) || {};
|
||||||
|
const name =
|
||||||
|
referralPreviewData.nickname ||
|
||||||
|
referralPreviewData.nickName ||
|
||||||
|
referralPreviewData.userName ||
|
||||||
|
"";
|
||||||
|
if (name)
|
||||||
|
layerInstance.msg("已识别推荐人:" + name, {
|
||||||
|
icon: 1,
|
||||||
|
time: 1500,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
referralPreviewData = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function register() {
|
||||||
|
$("#registerBtn").prop("disabled", true).text("注册中...");
|
||||||
|
ApiClient.post(ApiClient.API.authRegister, buildRegisterData(), {
|
||||||
|
publicRequest: true,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (ApiClient.isSuccess(res)) {
|
||||||
|
layerInstance.msg(
|
||||||
|
"注册成功,即将前往登录",
|
||||||
|
{ icon: 1, time: 1200 },
|
||||||
|
function () {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layerInstance.msg((res && res.msg) || "注册失败,请稍后重试", {
|
||||||
|
icon: 2,
|
||||||
|
});
|
||||||
|
refreshCaptcha();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layerInstance.msg("网络异常,注册失败", { icon: 2 });
|
||||||
|
refreshCaptcha();
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
$("#registerBtn").prop("disabled", false).text("确认注册");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
layerInstance = layui.layer;
|
||||||
|
loadVerifyConfig().then(refreshCaptcha);
|
||||||
|
loadReferralBindPreview();
|
||||||
|
$("#sendSmsBtn").on("click", sendSmsCode);
|
||||||
|
$("#registerForm").on("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (validateForm()) register();
|
||||||
|
});
|
||||||
|
$("#nickname").on("blur", function () {
|
||||||
|
validateNickname(true);
|
||||||
|
});
|
||||||
|
$("#phone").on("blur", function () {
|
||||||
|
validatePhone(true);
|
||||||
|
});
|
||||||
|
$("#smsCode").on("blur", function () {
|
||||||
|
validateSmsCode(true);
|
||||||
|
});
|
||||||
|
$("#password").on("blur", function () {
|
||||||
|
validatePassword(true);
|
||||||
|
});
|
||||||
|
$("#confirmPassword").on("blur", function () {
|
||||||
|
validateConfirmPassword(true);
|
||||||
|
});
|
||||||
|
$("#captchaInput").on("input", function () {
|
||||||
|
clearError("captcha");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title id="page-title">彩先知 - 找回密码</title>
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../utils/AuthPageUtil.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/auth.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="auth-container">
|
||||||
|
<div class="auth-card">
|
||||||
|
<div class="auth-header">
|
||||||
|
<a class="auth-logo" href="index.html" aria-label="返回首页">
|
||||||
|
<img src="../images/cxz-logo.png" alt="彩先知" />
|
||||||
|
</a>
|
||||||
|
<div class="auth-subtitle">CaiXianZhi - 找回密码</div>
|
||||||
|
</div>
|
||||||
|
<div class="auth-body">
|
||||||
|
<form id="resetPasswordForm" autocomplete="off">
|
||||||
|
<div class="form-group" id="phoneContainer">
|
||||||
|
<label for="phone">手机号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="phone"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
maxlength="11"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="phoneError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="captchaGroup">
|
||||||
|
<label for="captchaInput">滑动验证</label>
|
||||||
|
<div class="captcha-row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="captchaInput"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
maxlength="6"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="captcha-img-box"
|
||||||
|
id="captchaContainer"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
<img id="captchaImage" src="" alt="验证码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="captcha-refresh-link"
|
||||||
|
id="captchaRefreshLink"
|
||||||
|
onclick="refreshCaptcha()"
|
||||||
|
>
|
||||||
|
看不清?换一张
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="captchaError"></div>
|
||||||
|
<input type="hidden" id="captchaId" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="smsCodeContainer">
|
||||||
|
<label for="smsCode">短信验证码</label>
|
||||||
|
<div class="auth-sms-row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="smsCode"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入短信验证码"
|
||||||
|
maxlength="6"
|
||||||
|
/>
|
||||||
|
<button type="button" class="auth-sms-button" id="sendSmsBtn">
|
||||||
|
获取验证码
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="smsCodeError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="passwordContainer">
|
||||||
|
<label for="password">新密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请输入新密码(6-20位)"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="passwordError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="confirmPasswordContainer">
|
||||||
|
<label for="confirmPassword">确认密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="confirmPassword"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="请再次输入新密码"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
<div class="error-message" id="confirmPasswordError"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="auth-submit-btn" id="resetBtn">
|
||||||
|
确认重置
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="auth-links">
|
||||||
|
<a href="login.html">想起密码?返回登录</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="../public/js/jquery.js"></script>
|
||||||
|
<script src="../public/js/md5.js"></script>
|
||||||
|
<script>
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
const $ = layui.$;
|
||||||
|
let layerInstance = null;
|
||||||
|
let currentCaptchaId = "";
|
||||||
|
let currentVerifyType = "captcha";
|
||||||
|
let currentSlideUuid = "";
|
||||||
|
let currentSlideX = 0;
|
||||||
|
let pendingSmsAfterVerify = false;
|
||||||
|
|
||||||
|
function showError(field, message) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.text(message)
|
||||||
|
.show();
|
||||||
|
$("#" + containerId).addClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearError(field) {
|
||||||
|
const containerId =
|
||||||
|
field === "captcha" ? "captchaGroup" : field + "Container";
|
||||||
|
$("#" + field + "Error")
|
||||||
|
.hide()
|
||||||
|
.text("");
|
||||||
|
$("#" + containerId).removeClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadVerifyConfig() {
|
||||||
|
return AuthPageUtil.loadVerifyType().then(function (type) {
|
||||||
|
currentVerifyType = type;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCaptcha() {
|
||||||
|
currentCaptchaId = "";
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
$("#captchaId").val("");
|
||||||
|
$("#captchaInput").val("");
|
||||||
|
$("#captchaGroup").removeClass("is-slide-mode");
|
||||||
|
$("#sendSmsBtn").prop("disabled", currentVerifyType === "slide");
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#captchaInput").show();
|
||||||
|
$("#captchaRefreshLink").show().text("看不清?换一张");
|
||||||
|
$("#captchaContainer")
|
||||||
|
.attr("onclick", "refreshCaptcha()")
|
||||||
|
.html('<img id="captchaImage" src="" alt="验证码" />');
|
||||||
|
$("#captchaImage").attr("src", ApiClient.transparentGif());
|
||||||
|
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);
|
||||||
|
$("#captchaImage").attr(
|
||||||
|
"src",
|
||||||
|
res.data.img || res.data.image || "",
|
||||||
|
);
|
||||||
|
clearError("captcha");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layerInstance.msg(
|
||||||
|
"获取验证码失败:" + ((res && res.msg) || "未知错误"),
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
layerInstance.msg("网络错误,无法获取验证码", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeSlideCaptcha(result) {
|
||||||
|
const data = result || {};
|
||||||
|
const nested = data.data || {};
|
||||||
|
currentSlideUuid =
|
||||||
|
data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || "";
|
||||||
|
currentSlideX =
|
||||||
|
Number(data.slideX || data.x || nested.slideX || nested.x || 0) || 0;
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
layerInstance.msg("滑动验证未返回凭证,请重试", { icon: 2 });
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#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);
|
||||||
|
if (pendingSmsAfterVerify) {
|
||||||
|
pendingSmsAfterVerify = false;
|
||||||
|
sendSmsCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSlideCaptcha() {
|
||||||
|
AuthPageUtil.loadSlideCaptchaScript()
|
||||||
|
.then(function (SlideCaptcha) {
|
||||||
|
SlideCaptcha.open({
|
||||||
|
title: "找回密码安全验证",
|
||||||
|
subtitle: "拖动滑块完成验证后继续重置",
|
||||||
|
apiBase: ApiClient.baseUrl || "",
|
||||||
|
onSuccess: completeSlideCaptcha,
|
||||||
|
onCancel: function () {
|
||||||
|
currentSlideUuid = "";
|
||||||
|
currentSlideX = 0;
|
||||||
|
},
|
||||||
|
onError: function (error) {
|
||||||
|
layerInstance.msg(
|
||||||
|
(error && error.message) || "滑动验证失败,请重试",
|
||||||
|
{ icon: 2 },
|
||||||
|
);
|
||||||
|
renderSlideCaptchaEntry();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
layerInstance.msg(error.message || "滑动验证组件加载失败", {
|
||||||
|
icon: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSlideCaptchaEntry() {
|
||||||
|
$("#captchaInput").hide();
|
||||||
|
$("#captchaRefreshLink").hide();
|
||||||
|
$("#captchaGroup").addClass("is-slide-mode");
|
||||||
|
$("#sendSmsBtn").prop("disabled", true);
|
||||||
|
$("#captchaContainer")
|
||||||
|
.removeAttr("onclick")
|
||||||
|
.html(
|
||||||
|
'<div class="slide-verify-card" role="button" tabindex="0"><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>',
|
||||||
|
);
|
||||||
|
$(".slide-verify-card")
|
||||||
|
.off("click keydown")
|
||||||
|
.on("click", openSlideCaptcha)
|
||||||
|
.on("keydown", function (event) {
|
||||||
|
if (event.key === "Enter" || event.key === " ") {
|
||||||
|
event.preventDefault();
|
||||||
|
openSlideCaptcha();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePhone(show) {
|
||||||
|
const value = $("#phone").val().trim();
|
||||||
|
if (!AuthPageUtil.isPhone(value)) {
|
||||||
|
if (show) showError("phone", "请输入正确的手机号");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("phone");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateSmsCode(show) {
|
||||||
|
const value = $("#smsCode").val().trim();
|
||||||
|
if (!/^\d{4,6}$/.test(value)) {
|
||||||
|
if (show) showError("smsCode", "请输入4-6位短信验证码");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("smsCode");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassword(show) {
|
||||||
|
if (!AuthPageUtil.isPassword($("#password").val())) {
|
||||||
|
if (show) showError("password", "密码长度应为6-20位");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("password");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateConfirmPassword(show) {
|
||||||
|
if ($("#confirmPassword").val() !== $("#password").val()) {
|
||||||
|
if (show) showError("confirmPassword", "两次输入的密码不一致");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearError("confirmPassword");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVerifyParams(show) {
|
||||||
|
if (currentVerifyType === "slide") {
|
||||||
|
if (!currentSlideUuid) {
|
||||||
|
if (show) layerInstance.msg("请先完成滑动验证", { icon: 2 });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
verifyType: "slide",
|
||||||
|
slideUuid: currentSlideUuid,
|
||||||
|
slideX: currentSlideX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const code = $("#captchaInput").val().trim();
|
||||||
|
if (!code || !currentCaptchaId) {
|
||||||
|
if (show) showError("captcha", "请填写有效验证码");
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.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();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
$("#sendSmsBtn").prop("disabled", false);
|
||||||
|
layerInstance.msg("网络异常,短信发送失败", { icon: 2 });
|
||||||
|
refreshCaptcha();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
if (
|
||||||
|
!validatePhone(true) ||
|
||||||
|
!validateSmsCode(true) ||
|
||||||
|
!validatePassword(true) ||
|
||||||
|
!validateConfirmPassword(true)
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (!getVerifyParams(true)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildResetData() {
|
||||||
|
return Object.assign(
|
||||||
|
{
|
||||||
|
phoneNumber: $("#phone").val().trim(),
|
||||||
|
smsCode: $("#smsCode").val().trim(),
|
||||||
|
password: hex_md5($("#password").val()),
|
||||||
|
},
|
||||||
|
getVerifyParams(false) || {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitResetPassword() {
|
||||||
|
const payload = buildResetData();
|
||||||
|
console.warn(
|
||||||
|
"找回密码提交参数已准备好,但最新接口文档暂未提供提交接口:",
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
layerInstance.alert(
|
||||||
|
"最新接口文档暂未提供找回密码提交接口。页面流程、短信验证码和验证参数已按参考项目准备好,等后端补接口后即可接入提交。",
|
||||||
|
{ title: "暂不能提交" },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
layerInstance = layui.layer;
|
||||||
|
loadVerifyConfig().then(refreshCaptcha);
|
||||||
|
$("#sendSmsBtn").on("click", sendSmsCode);
|
||||||
|
$("#resetPasswordForm").on("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (validateForm()) submitResetPassword();
|
||||||
|
});
|
||||||
|
$("#phone").on("blur", function () {
|
||||||
|
validatePhone(true);
|
||||||
|
});
|
||||||
|
$("#smsCode").on("blur", function () {
|
||||||
|
validateSmsCode(true);
|
||||||
|
});
|
||||||
|
$("#password").on("blur", function () {
|
||||||
|
validatePassword(true);
|
||||||
|
});
|
||||||
|
$("#confirmPassword").on("blur", function () {
|
||||||
|
validateConfirmPassword(true);
|
||||||
|
});
|
||||||
|
$("#captchaInput").on("input", function () {
|
||||||
|
clearError("captcha");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,424 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<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/trend.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>
|
||||||
|
|
||||||
|
<div class="breadcrumb-bar">
|
||||||
|
<a href="javascript:history.back();"
|
||||||
|
><i class="layui-icon layui-icon-left"></i> 返回</a
|
||||||
|
>
|
||||||
|
<span>/</span>
|
||||||
|
<span>双色球走势图</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-title-bar">
|
||||||
|
<div class="page-title">双色球走势图</div>
|
||||||
|
<div class="qishu">
|
||||||
|
<div class="qishu-but active" data-count="30">30期</div>
|
||||||
|
<div class="qishu-but" data-count="60">60期</div>
|
||||||
|
<div class="qishu-but" data-count="100">100期</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table class="trend-table" border="1" id="trend-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="col-issue">期号</td>
|
||||||
|
<td rowspan="2" class="col-code">开奖号</td>
|
||||||
|
<td colspan="33" class="zone-red-header">红球</td>
|
||||||
|
<td colspan="16" class="zone-blue-header">蓝球</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="header-row"></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="data-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
CommonUtil.loadPageConfig();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var RED_MAX = 33,
|
||||||
|
BLUE_MAX = 16;
|
||||||
|
var currentCount = 30;
|
||||||
|
var allData = [];
|
||||||
|
|
||||||
|
// Build header row
|
||||||
|
function buildHeader() {
|
||||||
|
var html = "";
|
||||||
|
for (var i = 1; i <= RED_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++) {
|
||||||
|
html += "<td>" + (i < 10 ? "0" + i : i) + "</td>";
|
||||||
|
}
|
||||||
|
$("#header-row").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse openCode like "01,10,11,16,24,26+03"
|
||||||
|
function parseCode(code) {
|
||||||
|
var parts = code.split("+");
|
||||||
|
var reds = parts[0].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
});
|
||||||
|
var blues = parts[1]
|
||||||
|
? parts[1].split(",").map(function (n) {
|
||||||
|
return parseInt(n);
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
return { reds: reds, blues: blues };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render data rows
|
||||||
|
function renderData(count) {
|
||||||
|
var data = allData.slice(0, count);
|
||||||
|
var html = "";
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var item = data[r];
|
||||||
|
var parsed = parseCode(item.openCode);
|
||||||
|
var redSet = {};
|
||||||
|
var blueSet = {};
|
||||||
|
parsed.reds.forEach(function (n) {
|
||||||
|
redSet[n] = true;
|
||||||
|
});
|
||||||
|
parsed.blues.forEach(function (n) {
|
||||||
|
blueSet[n] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += "<tr>";
|
||||||
|
html += '<td class="col-issue">' + item.issue + "</td>";
|
||||||
|
html +=
|
||||||
|
'<td class="col-code">' +
|
||||||
|
item.openCode.replace(/\+/g, "+") +
|
||||||
|
"</td>";
|
||||||
|
|
||||||
|
for (var i = 1; i <= RED_MAX; i++) {
|
||||||
|
if (redSet[i]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-red">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++) {
|
||||||
|
if (blueSet[i]) {
|
||||||
|
html +=
|
||||||
|
'<td><span class="hit-blue">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
} else {
|
||||||
|
html +=
|
||||||
|
'<td><span class="miss-num">' +
|
||||||
|
(i < 10 ? "0" + i : i) +
|
||||||
|
"</span></td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statistics
|
||||||
|
html += buildStats(data);
|
||||||
|
$("#data-body").html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build statistics rows
|
||||||
|
function buildStats(data) {
|
||||||
|
var redCount = {},
|
||||||
|
blueCount = {};
|
||||||
|
var redMaxOmit = {},
|
||||||
|
blueMaxOmit = {};
|
||||||
|
var redCurrOmit = {},
|
||||||
|
blueCurrOmit = {};
|
||||||
|
var redMaxConsec = {},
|
||||||
|
blueMaxConsec = {};
|
||||||
|
var redAvgOmit = {},
|
||||||
|
blueAvgOmit = {};
|
||||||
|
|
||||||
|
for (var i = 1; i <= RED_MAX; i++) {
|
||||||
|
redCount[i] = 0;
|
||||||
|
redMaxOmit[i] = 0;
|
||||||
|
redCurrOmit[i] = 0;
|
||||||
|
redMaxConsec[i] = 0;
|
||||||
|
redAvgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++) {
|
||||||
|
blueCount[i] = 0;
|
||||||
|
blueMaxOmit[i] = 0;
|
||||||
|
blueCurrOmit[i] = 0;
|
||||||
|
blueMaxConsec[i] = 0;
|
||||||
|
blueAvgOmit[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate occurrence count, max omission, current omission, max consecutive, avg omission
|
||||||
|
for (var i = 1; i <= RED_MAX; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
maxOmit = 0,
|
||||||
|
consec = 0,
|
||||||
|
maxConsec = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
omitCount = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var parsed = parseCode(data[r].openCode);
|
||||||
|
if (parsed.reds.indexOf(i) >= 0) {
|
||||||
|
redCount[i]++;
|
||||||
|
if (omit > maxOmit) maxOmit = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
omitCount++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > maxConsec) maxConsec = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > maxOmit) maxOmit = omit;
|
||||||
|
redCurrOmit[i] = omit;
|
||||||
|
redMaxOmit[i] = maxOmit;
|
||||||
|
redMaxConsec[i] = maxConsec;
|
||||||
|
redAvgOmit[i] =
|
||||||
|
omitCount > 0 ? (totalOmit / omitCount).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++) {
|
||||||
|
var omit = 0,
|
||||||
|
maxOmit = 0,
|
||||||
|
consec = 0,
|
||||||
|
maxConsec = 0,
|
||||||
|
totalOmit = 0,
|
||||||
|
omitCount = 0;
|
||||||
|
for (var r = 0; r < data.length; r++) {
|
||||||
|
var parsed = parseCode(data[r].openCode);
|
||||||
|
if (parsed.blues.indexOf(i) >= 0) {
|
||||||
|
blueCount[i]++;
|
||||||
|
if (omit > maxOmit) maxOmit = omit;
|
||||||
|
totalOmit += omit;
|
||||||
|
omitCount++;
|
||||||
|
omit = 0;
|
||||||
|
consec++;
|
||||||
|
if (consec > maxConsec) maxConsec = consec;
|
||||||
|
} else {
|
||||||
|
omit++;
|
||||||
|
consec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (omit > maxOmit) maxOmit = omit;
|
||||||
|
blueCurrOmit[i] = omit;
|
||||||
|
blueMaxOmit[i] = maxOmit;
|
||||||
|
blueMaxConsec[i] = maxConsec;
|
||||||
|
blueAvgOmit[i] =
|
||||||
|
omitCount > 0 ? (totalOmit / omitCount).toFixed(1) : data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var stats = "";
|
||||||
|
// Occurrence count row
|
||||||
|
stats +=
|
||||||
|
'<tr class="stat-row"><td colspan="2" class="stat-label">出现次数</td>';
|
||||||
|
for (var i = 1; i <= RED_MAX; i++)
|
||||||
|
stats += "<td>" + redCount[i] + "</td>";
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++)
|
||||||
|
stats += "<td>" + blueCount[i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
|
||||||
|
// Max omission row
|
||||||
|
stats +=
|
||||||
|
'<tr class="stat-row alt"><td colspan="2" class="stat-label">最大遗漏</td>';
|
||||||
|
for (var i = 1; i <= RED_MAX; i++)
|
||||||
|
stats += "<td>" + redMaxOmit[i] + "</td>";
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++)
|
||||||
|
stats += "<td>" + blueMaxOmit[i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
|
||||||
|
// Avg omission row
|
||||||
|
stats +=
|
||||||
|
'<tr class="stat-row"><td colspan="2" class="stat-label">平均遗漏</td>';
|
||||||
|
for (var i = 1; i <= RED_MAX; i++)
|
||||||
|
stats += "<td>" + redAvgOmit[i] + "</td>";
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++)
|
||||||
|
stats += "<td>" + blueAvgOmit[i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
|
||||||
|
// Max consecutive row
|
||||||
|
stats +=
|
||||||
|
'<tr class="stat-row alt"><td colspan="2" class="stat-label">最大连出</td>';
|
||||||
|
for (var i = 1; i <= RED_MAX; i++)
|
||||||
|
stats += "<td>" + redMaxConsec[i] + "</td>";
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++)
|
||||||
|
stats += "<td>" + blueMaxConsec[i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
|
||||||
|
// Current omission row
|
||||||
|
stats +=
|
||||||
|
'<tr class="stat-row"><td colspan="2" class="stat-label">当前遗漏</td>';
|
||||||
|
for (var i = 1; i <= RED_MAX; i++)
|
||||||
|
stats += "<td>" + redCurrOmit[i] + "</td>";
|
||||||
|
for (var i = 1; i <= BLUE_MAX; i++)
|
||||||
|
stats += "<td>" + blueCurrOmit[i] + "</td>";
|
||||||
|
stats += "</tr>";
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load data from API
|
||||||
|
function loadData() {
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/lotteryResult/getList",
|
||||||
|
{ suoxie: "ssq" },
|
||||||
|
function (res) {
|
||||||
|
if (res && res.data) {
|
||||||
|
allData = res.data;
|
||||||
|
renderData(currentCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period count buttons
|
||||||
|
$(document).on("click", ".qishu-but", function () {
|
||||||
|
$(".qishu-but").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
currentCount = parseInt($(this).data("count"));
|
||||||
|
renderData(currentCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
buildHeader();
|
||||||
|
loadData();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,818 @@
|
|||||||
|
<!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/publish.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/tixian.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img src="../images/home-logo.png" alt="彩先知" class="topbar__logo" />
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary">免费注册</a>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged tx-hidden">
|
||||||
|
<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 class="cxz-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<span>提现</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tx-balance-grid">
|
||||||
|
<div class="tx-balance-card">
|
||||||
|
<div class="tx-balance-icon account">
|
||||||
|
<i class="layui-icon layui-icon-rmb"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-info">
|
||||||
|
<div class="tx-balance-label">账户余额</div>
|
||||||
|
<div class="tx-balance-value" id="accountBalance">0.00<span class="unit">元</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-card">
|
||||||
|
<div class="tx-balance-icon sales">
|
||||||
|
<i class="layui-icon layui-icon-group"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-info">
|
||||||
|
<div class="tx-balance-label">销售余额</div>
|
||||||
|
<div class="tx-balance-value" id="salesBalance">0.00<span class="unit">元</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-card">
|
||||||
|
<div class="tx-balance-icon expert">
|
||||||
|
<i class="layui-icon layui-icon-star-fill"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-info">
|
||||||
|
<div class="tx-balance-label">专家余额</div>
|
||||||
|
<div class="tx-balance-value" id="expertBalance">0.00<span class="unit">元</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-card">
|
||||||
|
<div class="tx-balance-icon withdrawable">
|
||||||
|
<i class="layui-icon layui-icon-ok-circle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-info">
|
||||||
|
<div class="tx-balance-label">可提现金额</div>
|
||||||
|
<div class="tx-balance-value" id="withdrawableAmount">0.00<span class="unit">元</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-card">
|
||||||
|
<div class="tx-balance-icon frozen">
|
||||||
|
<i class="layui-icon layui-icon-password"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tx-balance-info">
|
||||||
|
<div class="tx-balance-label">冻结金额</div>
|
||||||
|
<div class="tx-balance-value" id="frozenAmount">0.00<span class="unit">元</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="publish-tab-bar tx-tab-bar">
|
||||||
|
<div class="publish-tab-item active" data-tab="withdraw" onclick="switchTab('withdraw')">提现</div>
|
||||||
|
<div class="publish-tab-item" data-tab="transfer" onclick="switchTab('transfer')">余额转入</div>
|
||||||
|
<a href="tixianlist.html" class="publish-tab-item">提现记录</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tx-panel active" id="panelWithdraw">
|
||||||
|
<div class="cxz-form-card">
|
||||||
|
<div class="cxz-form-title">申请提现</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">提现来源 <span class="required">*</span></label>
|
||||||
|
<input id="withdrawSource" type="hidden" value="sales" />
|
||||||
|
<div class="tx-choice-grid" id="withdrawSourceCards"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">可提现金额</label>
|
||||||
|
<div class="tx-available" id="withdrawAvailableAmount">0.00 元</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">提现金额 <span class="required">*</span></label>
|
||||||
|
<div class="tx-amount-row">
|
||||||
|
<input class="cxz-form-input" id="withdrawAmount" type="number" min="1" step="0.01" placeholder="请输入提现金额" />
|
||||||
|
<button class="tx-all-btn" id="withdrawAll" type="button">全部</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">提现方式 <span class="required">*</span></label>
|
||||||
|
<input id="withdrawMethod" type="hidden" value="alipay" />
|
||||||
|
<input id="receiveAccountId" type="hidden" />
|
||||||
|
<div class="tx-method-grid" id="withdrawMethodCards"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<div class="tx-account-head">
|
||||||
|
<label class="cxz-form-label tx-label-tight">收款账户 <span class="required">*</span></label>
|
||||||
|
<button class="tx-link-btn" type="button" onclick="openAddAccount()">新增收款账户</button>
|
||||||
|
</div>
|
||||||
|
<div class="tx-account-grid" id="receiveAccountCards"></div>
|
||||||
|
<div class="tx-add-panel" id="addAccountPanel"></div>
|
||||||
|
<div class="tx-note" id="withdrawHint">请选择或新增对应提现方式的收款账户。</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="cxz-submit-btn" id="withdrawSubmitBtn" onclick="submitWithdraw()">确认提现</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tx-panel" id="panelTransfer">
|
||||||
|
<div class="cxz-form-card">
|
||||||
|
<div class="cxz-form-title">余额转入</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">转出来源 <span class="required">*</span></label>
|
||||||
|
<input id="transferSource" type="hidden" value="sales" />
|
||||||
|
<div class="tx-choice-grid" id="transferSourceCards"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">可转余额</label>
|
||||||
|
<div class="tx-available" id="transferAvailableAmount">0.00 元</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cxz-form-group">
|
||||||
|
<label class="cxz-form-label">转入金额 <span class="required">*</span></label>
|
||||||
|
<div class="tx-amount-row">
|
||||||
|
<input class="cxz-form-input" id="transferAmount" type="number" min="1" step="0.01" placeholder="请输入转入账户余额的金额" />
|
||||||
|
<button class="tx-all-btn" id="transferAll" type="button">全部</button>
|
||||||
|
</div>
|
||||||
|
<div class="tx-note">转入账户余额后,可用于购买付费文章、专家预测或其他站内服务。</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="cxz-submit-btn" id="transferSubmitBtn" onclick="submitTransfer()">确认转入</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div class="tx-modal-mask" id="receiveAccountEditMask">
|
||||||
|
<div class="tx-modal">
|
||||||
|
<div class="tx-modal-head">
|
||||||
|
<div class="tx-modal-title">编辑收款账户</div>
|
||||||
|
<button class="tx-modal-close" type="button" onclick="closeReceiveAccountEdit()">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="tx-modal-body">
|
||||||
|
<div id="receiveAccountEditBody"></div>
|
||||||
|
<div class="tx-modal-actions">
|
||||||
|
<button class="tx-secondary-btn" type="button" onclick="closeReceiveAccountEdit()">取消</button>
|
||||||
|
<button class="tx-small-btn" type="button" onclick="saveReceiveAccountEdit()">保存修改</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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" class="tx-beian-link" href="https://beian.miit.gov.cn/" target="_blank">工信部备案号</a>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<button class="gotop" id="backTop" type="button" onclick="window.scrollTo({ top: 0, behavior: 'smooth' })">↑</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
let receiveAccounts = [];
|
||||||
|
let editingReceiveAccountId = "";
|
||||||
|
let userBalances = { account: 0, sales: 0, expert: 0, withdrawable: 0, frozen: 0 };
|
||||||
|
|
||||||
|
const walletSourceOptions = [
|
||||||
|
{ value: "sales", title: "销售余额", desc: "销售返佣可提现或转入账户余额" },
|
||||||
|
{ value: "expert", title: "专家余额", desc: "专家收益可提现或转入账户余额" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const withdrawMethodOptions = [
|
||||||
|
{ value: "alipay", title: "支付宝", desc: "支持支付宝账号或收款二维码" },
|
||||||
|
{ value: "wechat_qr", title: "微信", desc: "使用微信收款二维码" },
|
||||||
|
{ value: "bank", title: "银行卡", desc: "绑定银行卡收款" },
|
||||||
|
];
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSuccess(res) {
|
||||||
|
return ApiClient.isSuccess ? ApiClient.isSuccess(res) : res && (res.code === 0 || res.code === 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickData(res) {
|
||||||
|
return ApiClient.pickData ? ApiClient.pickData(res) : res && res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function asArray(value) {
|
||||||
|
return ApiClient.asArray ? ApiClient.asArray(value) : Array.isArray(value) ? value : value ? [value] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return String(value == null ? "" : value)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function fieldValue(item, keys) {
|
||||||
|
for (let i = 0; i < keys.length; i += 1) {
|
||||||
|
const value = item && item[keys[i]];
|
||||||
|
if (value !== undefined && value !== null && value !== "") return value;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function money(value) {
|
||||||
|
const number = Number(value || 0);
|
||||||
|
return Number.isFinite(number) ? number.toFixed(2) : "0.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeReceiveType(type) {
|
||||||
|
const value = String(type || "").toLowerCase();
|
||||||
|
if (value === "wechat") return "wechat_qr";
|
||||||
|
if (value === "alipay_qr" || value === "alipay_qrcode") return "alipay";
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccountId(item) {
|
||||||
|
return fieldValue(item, ["id", "receiveAccountId", "accountId"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccountById(id) {
|
||||||
|
return receiveAccounts.find((item) => String(getAccountId(item)) === String(id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSourceAmount(source) {
|
||||||
|
return Number(userBalances[source] || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQrcodeUrl(item) {
|
||||||
|
return fieldValue(item, ["qrcodeUrl", "qrCodeUrl", "ossUrl", "url", "fileUrl"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQrcodeFileId(item) {
|
||||||
|
return fieldValue(item, ["qrCodeFileId", "qrcodeFileId", "qrcodeOssId", "ossId", "fileId"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasQrcode(item) {
|
||||||
|
return Boolean(getQrcodeUrl(item) || getQrcodeFileId(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReceiveTypeText(type) {
|
||||||
|
const value = normalizeReceiveType(type);
|
||||||
|
if (value === "bank") return "银行卡";
|
||||||
|
if (value === "wechat_qr") return "微信";
|
||||||
|
return "支付宝";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReceiveAccountText(item) {
|
||||||
|
const type = normalizeReceiveType(item.receiveType || item.withdrawType);
|
||||||
|
if (type === "bank") {
|
||||||
|
return [item.bankName, fieldValue(item, ["bankCardNo", "bankAccount", "accountNo"])].filter(Boolean).join(" ");
|
||||||
|
}
|
||||||
|
if (type === "wechat_qr") {
|
||||||
|
return fieldValue(item, ["wechatAccount", "account", "accountNo", "receiveAccount"]) || (hasQrcode(item) ? "已保存微信收款码" : "微信收款账户");
|
||||||
|
}
|
||||||
|
return fieldValue(item, ["alipayAccount", "account", "accountNo", "receiveAccount"]) || (hasQrcode(item) ? "已保存支付宝收款码" : "支付宝收款账户");
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
const token = CommonUtil.getAuthToken ? CommonUtil.getAuthToken() : localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#notLoggedInBox").addClass("tx-hidden");
|
||||||
|
$("#loggedInBox").removeClass("tx-hidden");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
$("#userName").text(data.nickName || data.nickname || "用户");
|
||||||
|
$("#userLevel").text(data.isExpert === "1" ? "专家" : "会员");
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").removeClass("tx-hidden");
|
||||||
|
$("#loggedInBox").addClass("tx-hidden");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
loadWalletOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.get(ApiClient.API.homeNav).then(function (res) {
|
||||||
|
if (!isSuccess(res) || !res.data) return;
|
||||||
|
const $nav = $("#navLotteryItems").empty();
|
||||||
|
$.each(asArray(pickData(res)), function (_, item) {
|
||||||
|
if (item.type && item.type !== "lottery") return;
|
||||||
|
const code = item.code || item.suoxie || "";
|
||||||
|
if (!code) return;
|
||||||
|
$nav.append('<a href="cai.html?id=' + encodeURIComponent(code) + '" class="topbar__nav-link">' + escapeHtml(item.name || item.lotteryName || code) + "</a>");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadWalletOverview() {
|
||||||
|
ApiClient.get(ApiClient.API.walletOverview).then(function (res) {
|
||||||
|
if (!isSuccess(res)) return;
|
||||||
|
const data = pickData(res) || {};
|
||||||
|
userBalances.account = Number(fieldValue(data, ["accountBalance", "balance", "accountAmount"]));
|
||||||
|
userBalances.sales = Number(fieldValue(data, ["salesBalance", "saleBalance", "distributionBalance", "commissionBalance"]));
|
||||||
|
userBalances.expert = Number(fieldValue(data, ["expertBalance", "expertCommission", "expertAmount"]));
|
||||||
|
userBalances.withdrawable = Number(fieldValue(data, ["withdrawableAmount", "availableWithdrawAmount", "availableAmount"])) || userBalances.sales + userBalances.expert;
|
||||||
|
userBalances.frozen = Number(fieldValue(data, ["frozenAmount", "freezeAmount", "frozenBalance"]));
|
||||||
|
$("#accountBalance").html(money(userBalances.account) + '<span class="unit">元</span>');
|
||||||
|
$("#salesBalance").html(money(userBalances.sales) + '<span class="unit">元</span>');
|
||||||
|
$("#expertBalance").html(money(userBalances.expert) + '<span class="unit">元</span>');
|
||||||
|
$("#withdrawableAmount").html(money(userBalances.withdrawable) + '<span class="unit">元</span>');
|
||||||
|
$("#frozenAmount").html(money(userBalances.frozen) + '<span class="unit">元</span>');
|
||||||
|
updateAvailableAmounts();
|
||||||
|
renderWalletSourceCards();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadReceiveAccounts(selectedId) {
|
||||||
|
return ApiClient.get(ApiClient.API.walletReceiveAccountList)
|
||||||
|
.then(function (res) {
|
||||||
|
const data = pickData(res);
|
||||||
|
receiveAccounts = isSuccess(res) ? asArray((data && (data.records || data.rows || data.list)) || data) : [];
|
||||||
|
renderReceiveAccounts(selectedId);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
receiveAccounts = [];
|
||||||
|
renderReceiveAccounts();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTab(tab) {
|
||||||
|
$(".publish-tab-item[data-tab]").removeClass("active");
|
||||||
|
$('.publish-tab-item[data-tab="' + tab + '"]').addClass("active");
|
||||||
|
$(".tx-panel").removeClass("active");
|
||||||
|
if (tab === "withdraw") $("#panelWithdraw").addClass("active");
|
||||||
|
if (tab === "transfer") $("#panelTransfer").addClass("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWalletSourceCards() {
|
||||||
|
renderSourceCards("#withdrawSourceCards", "#withdrawSource", function () {
|
||||||
|
updateAvailableAmounts();
|
||||||
|
});
|
||||||
|
renderSourceCards("#transferSourceCards", "#transferSource", function () {
|
||||||
|
updateAvailableAmounts();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSourceCards(containerSelector, inputSelector, onChange) {
|
||||||
|
const $container = $(containerSelector).empty();
|
||||||
|
const selectedValue = $(inputSelector).val();
|
||||||
|
$.each(walletSourceOptions, function (_, item) {
|
||||||
|
const selected = selectedValue === item.value ? " selected" : "";
|
||||||
|
const $card = $(
|
||||||
|
'<div class="tx-choice-card' + selected + '" data-value="' + item.value + '">' +
|
||||||
|
'<div class="tx-choice-title">' + escapeHtml(item.title) + '</div>' +
|
||||||
|
'<div class="tx-choice-desc">' + escapeHtml(item.desc) + ":" + money(getSourceAmount(item.value)) + " 元</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
$card.on("click", function () {
|
||||||
|
$(inputSelector).val(item.value);
|
||||||
|
renderSourceCards(containerSelector, inputSelector, onChange);
|
||||||
|
if (onChange) onChange();
|
||||||
|
});
|
||||||
|
$container.append($card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAvailableAmounts() {
|
||||||
|
$("#withdrawAvailableAmount").text(money(getSourceAmount($("#withdrawSource").val())) + " 元");
|
||||||
|
$("#transferAvailableAmount").text(money(getSourceAmount($("#transferSource").val())) + " 元");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderMethodCards() {
|
||||||
|
const $container = $("#withdrawMethodCards").empty();
|
||||||
|
const selectedMethod = $("#withdrawMethod").val();
|
||||||
|
$.each(withdrawMethodOptions, function (_, item) {
|
||||||
|
const selected = selectedMethod === item.value ? " selected" : "";
|
||||||
|
const $card = $(
|
||||||
|
'<div class="tx-method-card' + selected + '" data-method="' + item.value + '">' +
|
||||||
|
'<div class="tx-method-title">' + escapeHtml(item.title) + '</div>' +
|
||||||
|
'<div class="tx-method-desc">' + escapeHtml(item.desc) + "</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
$card.on("click", function () {
|
||||||
|
$("#withdrawMethod").val(item.value);
|
||||||
|
$("#receiveAccountId").val("");
|
||||||
|
$("#addAccountPanel").removeClass("show").empty();
|
||||||
|
renderMethodCards();
|
||||||
|
renderReceiveAccounts();
|
||||||
|
});
|
||||||
|
$container.append($card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderReceiveAccounts(selectedId) {
|
||||||
|
const method = $("#withdrawMethod").val();
|
||||||
|
const $wrap = $("#receiveAccountCards").empty();
|
||||||
|
const list = receiveAccounts.filter((item) => normalizeReceiveType(item.receiveType || item.withdrawType) === method);
|
||||||
|
if (selectedId) $("#receiveAccountId").val(selectedId);
|
||||||
|
if (!list.length) {
|
||||||
|
$wrap.html('<div class="tx-empty">当前提现方式暂无收款账户,请先新增。</div>');
|
||||||
|
$("#withdrawHint").text("新增收款账户并保存后,就可以选择它提交提现。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (_, item) {
|
||||||
|
const id = getAccountId(item);
|
||||||
|
const current = $("#receiveAccountId").val();
|
||||||
|
const selected = String(current) === String(id) || (!current && item.isDefault == 1);
|
||||||
|
if (selected) $("#receiveAccountId").val(id);
|
||||||
|
const defaultTag = item.isDefault == 1 ? "<em>默认</em>" : "";
|
||||||
|
const $card = $(
|
||||||
|
'<div class="tx-account-card' + (selected ? " selected" : "") + '" data-id="' + escapeHtml(id) + '">' +
|
||||||
|
'<div class="tx-account-title">' + escapeHtml(item.realName || item.name || getReceiveTypeText(method)) + defaultTag + '</div>' +
|
||||||
|
'<div class="tx-account-desc">' + escapeHtml(getReceiveTypeText(method) + ":" + getReceiveAccountText(item)) + '</div>' +
|
||||||
|
'<div class="tx-account-actions">' +
|
||||||
|
'<span data-action="edit">编辑</span>' +
|
||||||
|
(item.isDefault == 1 ? "" : '<span data-action="default">设默认</span>') +
|
||||||
|
'<span data-action="delete">删除</span>' +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
);
|
||||||
|
$card.on("click", function () {
|
||||||
|
$("#receiveAccountId").val(id);
|
||||||
|
renderReceiveAccounts();
|
||||||
|
});
|
||||||
|
$card.find("[data-action]").on("click", function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const action = $(this).data("action");
|
||||||
|
if (action === "edit") openReceiveAccountEdit(id);
|
||||||
|
if (action === "default") setDefaultReceiveAccount(id);
|
||||||
|
if (action === "delete") deleteReceiveAccount(id);
|
||||||
|
});
|
||||||
|
$wrap.append($card);
|
||||||
|
});
|
||||||
|
$("#withdrawHint").text("请选择已维护的收款账户;需要变更信息时可直接编辑。");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUploadHtml(scope, label, existingUrl) {
|
||||||
|
return (
|
||||||
|
'<div class="tx-upload-box">' +
|
||||||
|
'<input id="' + scope + 'Qrcode" class="tx-qrcode-file tx-hidden" type="file" accept="image/*" />' +
|
||||||
|
'<button class="tx-secondary-btn" type="button" data-upload-trigger="' + scope + '">' + escapeHtml(label) + '</button>' +
|
||||||
|
'<span class="tx-upload-name" id="' + scope + 'UploadName">' + (existingUrl ? "已保存收款码,可重新选择图片" : "未选择图片") + '</span>' +
|
||||||
|
'<img id="' + scope + 'QrcodePreview" class="tx-qrcode-preview' + (existingUrl ? " is-visible" : "") + '" ' + (existingUrl ? 'src="' + escapeHtml(existingUrl) + '"' : "") + " />" +
|
||||||
|
"</div>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAddAccount() {
|
||||||
|
const method = $("#withdrawMethod").val();
|
||||||
|
const $currentPanel = $("#addAccountPanel");
|
||||||
|
if ($currentPanel.hasClass("show") && $currentPanel.attr("data-method") === method) {
|
||||||
|
$currentPanel.removeClass("show").empty().removeAttr("data-method").removeData("method");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const $panel = $("#addAccountPanel").addClass("show").attr("data-method", method).data("method", method);
|
||||||
|
let html = "";
|
||||||
|
if (method === "alipay") {
|
||||||
|
html += '<div class="tx-bind-mode" data-bind-type="account"><button class="active" type="button" data-bind-type="account">支付宝账号</button><button type="button" data-bind-type="qrcode">收款二维码</button></div>';
|
||||||
|
}
|
||||||
|
html += '<div class="tx-add-grid">';
|
||||||
|
html += '<input class="cxz-form-input" id="addRealName" placeholder="请输入真实姓名" />';
|
||||||
|
if (method === "bank") {
|
||||||
|
html += '<input class="cxz-form-input" id="addBankName" placeholder="请输入开户银行" />';
|
||||||
|
html += '<input class="cxz-form-input full" id="addAccountNo" placeholder="请输入银行卡号" />';
|
||||||
|
} else if (method === "wechat_qr") {
|
||||||
|
html += renderUploadHtml("add", "选择微信收款码", "");
|
||||||
|
} else {
|
||||||
|
html += '<input class="cxz-form-input" id="addAccountNo" placeholder="请输入支付宝账号" />';
|
||||||
|
html += '<div class="tx-alipay-qrcode full tx-hidden">' + renderUploadHtml("add", "选择支付宝收款码", "") + '</div>';
|
||||||
|
}
|
||||||
|
html += '<label class="tx-check-row full"><input id="addIsDefault" type="checkbox" /> 设为默认收款账户</label>';
|
||||||
|
html += "</div>";
|
||||||
|
html += '<div class="tx-note">保存成功后会自动加入收款账户列表,并用于本次提现选择。</div>';
|
||||||
|
html += '<button class="cxz-submit-btn tx-save-account-btn" type="button" onclick="saveReceiveAccountAdd()">保存收款账户</button>';
|
||||||
|
$panel.html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyAlipayBindMode($panel, bindType) {
|
||||||
|
$panel.find(".tx-bind-mode").attr("data-bind-type", bindType);
|
||||||
|
$panel.find(".tx-bind-mode button").removeClass("active");
|
||||||
|
$panel.find('.tx-bind-mode button[data-bind-type="' + bindType + '"]').addClass("active");
|
||||||
|
$panel.find("#addAccountNo").toggleClass("tx-hidden", bindType !== "account");
|
||||||
|
$panel.find(".tx-alipay-qrcode").toggleClass("tx-hidden", bindType !== "qrcode");
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadQrcode(scope, method) {
|
||||||
|
const input = $("#" + scope + "Qrcode")[0];
|
||||||
|
const file = input && input.files && input.files[0];
|
||||||
|
if (!file) return Promise.resolve({});
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
formData.append("receiveType", method);
|
||||||
|
return ApiClient.post(ApiClient.API.walletReceiveAccountUploadQrcode, formData).then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "收款码上传失败");
|
||||||
|
const data = pickData(res) || {};
|
||||||
|
const qrCodeFileId = fieldValue(data, ["qrCodeFileId", "qrcodeFileId", "fileId", "ossId", "id"]) || fieldValue(res, ["qrCodeFileId", "qrcodeFileId", "fileId", "ossId", "id"]);
|
||||||
|
if (!qrCodeFileId) throw new Error("收款码上传成功,但未返回二维码文件ID");
|
||||||
|
return { qrCodeFileId: qrCodeFileId };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendQrcodePayload(payload, uploadData) {
|
||||||
|
if (uploadData && uploadData.qrCodeFileId) payload.qrCodeFileId = uploadData.qrCodeFileId;
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAddPayload(uploadData) {
|
||||||
|
const method = $("#addAccountPanel").attr("data-method") || $("#withdrawMethod").val();
|
||||||
|
const realName = $("#addRealName").val().trim();
|
||||||
|
const account = String($("#addAccountNo").val() || "").trim();
|
||||||
|
if (!realName) throw new Error("请输入真实姓名");
|
||||||
|
const payload = {
|
||||||
|
receiveType: method,
|
||||||
|
realName: realName,
|
||||||
|
isDefault: $("#addIsDefault").prop("checked") || receiveAccounts.length === 0 ? 1 : 0,
|
||||||
|
};
|
||||||
|
if (method === "bank") {
|
||||||
|
const bankName = $("#addBankName").val().trim();
|
||||||
|
if (!bankName) throw new Error("请输入开户银行");
|
||||||
|
if (!account) throw new Error("请输入银行卡号");
|
||||||
|
payload.bankName = bankName;
|
||||||
|
payload.bankCardNo = account;
|
||||||
|
} else if (method === "wechat_qr") {
|
||||||
|
appendQrcodePayload(payload, uploadData);
|
||||||
|
if (!payload.qrCodeFileId) throw new Error("请上传微信收款码");
|
||||||
|
} else {
|
||||||
|
const bindType = $("#addAccountPanel .tx-bind-mode").attr("data-bind-type") || "account";
|
||||||
|
if (bindType === "qrcode") {
|
||||||
|
appendQrcodePayload(payload, uploadData);
|
||||||
|
if (!payload.qrCodeFileId) throw new Error("请上传支付宝收款码");
|
||||||
|
} else {
|
||||||
|
if (!account) throw new Error("请输入支付宝账号");
|
||||||
|
payload.alipayAccount = account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveReceiveAccountAdd() {
|
||||||
|
const method = $("#addAccountPanel").attr("data-method") || $("#withdrawMethod").val();
|
||||||
|
uploadQrcode("add", method)
|
||||||
|
.then(function (uploadData) {
|
||||||
|
return ApiClient.post(ApiClient.API.walletReceiveAccount, buildAddPayload(uploadData));
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "保存失败");
|
||||||
|
const data = pickData(res) || {};
|
||||||
|
const createdId = fieldValue(data, ["id", "receiveAccountId", "accountId"]);
|
||||||
|
layui.layer.msg("收款账户已保存", { icon: 1 });
|
||||||
|
$("#addAccountPanel").removeClass("show").empty();
|
||||||
|
return loadReceiveAccounts(createdId);
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layui.layer.msg(err.message || "保存失败", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openReceiveAccountEdit(id) {
|
||||||
|
const item = getAccountById(id);
|
||||||
|
if (!item) return;
|
||||||
|
editingReceiveAccountId = id;
|
||||||
|
const method = normalizeReceiveType(item.receiveType || item.withdrawType);
|
||||||
|
let html = '<div class="tx-add-grid" data-edit-method="' + method + '">';
|
||||||
|
html += '<input class="cxz-form-input" id="editRealName" placeholder="请输入真实姓名" value="' + escapeHtml(item.realName || item.name || "") + '" />';
|
||||||
|
if (method === "bank") {
|
||||||
|
html += '<input class="cxz-form-input" id="editBankName" placeholder="请输入开户银行" value="' + escapeHtml(item.bankName || "") + '" />';
|
||||||
|
html += '<input class="cxz-form-input full" id="editAccountNo" placeholder="请输入银行卡号" value="' + escapeHtml(fieldValue(item, ["bankCardNo", "bankAccount", "accountNo"])) + '" />';
|
||||||
|
} else if (method === "wechat_qr") {
|
||||||
|
html += renderUploadHtml("edit", "更换微信收款码", getQrcodeUrl(item));
|
||||||
|
} else {
|
||||||
|
const isQrcode = hasQrcode(item) && !fieldValue(item, ["alipayAccount", "account", "accountNo", "receiveAccount"]);
|
||||||
|
html += '<div class="full"><div class="tx-bind-mode" data-bind-type="' + (isQrcode ? "qrcode" : "account") + '"><button class="' + (isQrcode ? "" : "active") + '" type="button" data-bind-type="account">支付宝账号</button><button class="' + (isQrcode ? "active" : "") + '" type="button" data-bind-type="qrcode">收款二维码</button></div></div>';
|
||||||
|
html += '<input class="cxz-form-input' + (isQrcode ? " tx-hidden" : "") + '" id="editAccountNo" placeholder="请输入支付宝账号" value="' + escapeHtml(fieldValue(item, ["alipayAccount", "account", "accountNo", "receiveAccount"])) + '" />';
|
||||||
|
html += '<div class="tx-alipay-qrcode full' + (isQrcode ? "" : " tx-hidden") + '">' + renderUploadHtml("edit", "更换支付宝收款码", getQrcodeUrl(item)) + '</div>';
|
||||||
|
}
|
||||||
|
html += '<label class="tx-check-row full"><input id="editIsDefault" type="checkbox" ' + (item.isDefault == 1 ? "checked" : "") + " /> 设为默认收款账户</label>";
|
||||||
|
html += "</div>";
|
||||||
|
$("#receiveAccountEditBody").html(html);
|
||||||
|
$("#receiveAccountEditMask").addClass("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeReceiveAccountEdit() {
|
||||||
|
editingReceiveAccountId = "";
|
||||||
|
$("#receiveAccountEditBody").empty();
|
||||||
|
$("#receiveAccountEditMask").removeClass("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEditPayload(uploadData) {
|
||||||
|
const item = getAccountById(editingReceiveAccountId);
|
||||||
|
const method = normalizeReceiveType(item.receiveType || item.withdrawType);
|
||||||
|
const realName = $("#editRealName").val().trim();
|
||||||
|
const account = String($("#editAccountNo").val() || "").trim();
|
||||||
|
if (!realName) throw new Error("请输入真实姓名");
|
||||||
|
const payload = {
|
||||||
|
receiveType: method,
|
||||||
|
realName: realName,
|
||||||
|
isDefault: $("#editIsDefault").prop("checked") ? 1 : 0,
|
||||||
|
};
|
||||||
|
if (method === "bank") {
|
||||||
|
const bankName = $("#editBankName").val().trim();
|
||||||
|
if (!bankName) throw new Error("请输入开户银行");
|
||||||
|
if (!account) throw new Error("请输入银行卡号");
|
||||||
|
payload.bankName = bankName;
|
||||||
|
payload.bankCardNo = account;
|
||||||
|
} else if (method === "wechat_qr") {
|
||||||
|
appendQrcodePayload(payload, uploadData);
|
||||||
|
if (!payload.qrCodeFileId && getQrcodeFileId(item)) payload.qrCodeFileId = getQrcodeFileId(item);
|
||||||
|
} else {
|
||||||
|
const bindType = $("#receiveAccountEditBody .tx-bind-mode").attr("data-bind-type") || "account";
|
||||||
|
if (bindType === "qrcode") {
|
||||||
|
appendQrcodePayload(payload, uploadData);
|
||||||
|
if (!payload.qrCodeFileId && getQrcodeFileId(item)) payload.qrCodeFileId = getQrcodeFileId(item);
|
||||||
|
if (!payload.qrCodeFileId) throw new Error("请上传支付宝收款码");
|
||||||
|
} else {
|
||||||
|
if (!account) throw new Error("请输入支付宝账号");
|
||||||
|
payload.alipayAccount = account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveReceiveAccountEdit() {
|
||||||
|
if (!editingReceiveAccountId) return;
|
||||||
|
const item = getAccountById(editingReceiveAccountId);
|
||||||
|
const method = normalizeReceiveType(item.receiveType || item.withdrawType);
|
||||||
|
uploadQrcode("edit", method)
|
||||||
|
.then(function (uploadData) {
|
||||||
|
return ApiClient.put(ApiClient.API.walletReceiveAccountUpdate(editingReceiveAccountId), buildEditPayload(uploadData));
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "保存失败");
|
||||||
|
layui.layer.msg("收款账户已更新", { icon: 1 });
|
||||||
|
const selectedId = editingReceiveAccountId;
|
||||||
|
closeReceiveAccountEdit();
|
||||||
|
return loadReceiveAccounts(selectedId);
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layui.layer.msg(err.message || "保存失败", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefaultReceiveAccount(id) {
|
||||||
|
ApiClient.put(ApiClient.API.walletReceiveAccountDefault(id)).then(function (res) {
|
||||||
|
if (!isSuccess(res)) return layui.layer.msg(res.msg || "设置失败", { icon: 2 });
|
||||||
|
layui.layer.msg("默认收款账户已更新", { icon: 1 });
|
||||||
|
loadReceiveAccounts(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteReceiveAccount(id) {
|
||||||
|
layui.layer.confirm("确认删除这个收款账户?", function (index) {
|
||||||
|
layui.layer.close(index);
|
||||||
|
ApiClient.delete(ApiClient.API.walletReceiveAccountDelete(id)).then(function (res) {
|
||||||
|
if (!isSuccess(res)) return layui.layer.msg(res.msg || "删除失败", { icon: 2 });
|
||||||
|
layui.layer.msg("已删除", { icon: 1 });
|
||||||
|
if (String($("#receiveAccountId").val()) === String(id)) $("#receiveAccountId").val("");
|
||||||
|
loadReceiveAccounts();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitWithdraw() {
|
||||||
|
const amount = Number($("#withdrawAmount").val());
|
||||||
|
const sourceWallet = $("#withdrawSource").val();
|
||||||
|
const method = $("#withdrawMethod").val();
|
||||||
|
const receiveAccountId = $("#receiveAccountId").val();
|
||||||
|
if (!amount || amount <= 0) return layui.layer.msg("请输入有效的提现金额", { icon: 2 });
|
||||||
|
if (amount > getSourceAmount(sourceWallet)) return layui.layer.msg("提现金额不能超过可提现余额", { icon: 2 });
|
||||||
|
if (!receiveAccountId) return layui.layer.msg("请选择收款账户", { icon: 2 });
|
||||||
|
const $btn = $("#withdrawSubmitBtn").text("提交中...").prop("disabled", true);
|
||||||
|
ApiClient.post(ApiClient.API.walletWithdraw, {
|
||||||
|
sourceWallet: sourceWallet,
|
||||||
|
withdrawType: method,
|
||||||
|
amount: amount,
|
||||||
|
receiveAccountId: receiveAccountId,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "提现失败");
|
||||||
|
layui.layer.msg("提现申请已提交,请等待审核", { icon: 1 });
|
||||||
|
$("#withdrawAmount").val("");
|
||||||
|
loadWalletOverview();
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layui.layer.msg(err.message || "提现失败", { icon: 2 });
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
$btn.text("确认提现").prop("disabled", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitTransfer() {
|
||||||
|
const amount = Number($("#transferAmount").val());
|
||||||
|
const sourceWallet = $("#transferSource").val();
|
||||||
|
if (!amount || amount <= 0) return layui.layer.msg("请输入有效的转入金额", { icon: 2 });
|
||||||
|
if (amount > getSourceAmount(sourceWallet)) return layui.layer.msg("转入金额不能超过可转余额", { icon: 2 });
|
||||||
|
const $btn = $("#transferSubmitBtn").text("转入中...").prop("disabled", true);
|
||||||
|
ApiClient.post(ApiClient.API.walletTransferToAccount, {
|
||||||
|
sourceWallet: sourceWallet,
|
||||||
|
amount: amount,
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "操作失败");
|
||||||
|
layui.layer.msg("余额转入成功", { icon: 1 });
|
||||||
|
$("#transferAmount").val("");
|
||||||
|
loadWalletOverview();
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layui.layer.msg(err.message || "操作失败", { icon: 2 });
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
$btn.text("确认转入").prop("disabled", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", "[data-upload-trigger]", function () {
|
||||||
|
$("#" + $(this).data("upload-trigger") + "Qrcode").trigger("click");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("change", ".tx-qrcode-file", function () {
|
||||||
|
const scope = this.id.replace("Qrcode", "");
|
||||||
|
const file = this.files && this.files[0];
|
||||||
|
$("#" + scope + "UploadName").text(file ? file.name : "未选择图片");
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (event) {
|
||||||
|
$("#" + scope + "QrcodePreview").attr("src", event.target.result).addClass("is-visible");
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", ".tx-bind-mode button", function () {
|
||||||
|
const $panel = $(this).closest("#addAccountPanel, #receiveAccountEditBody");
|
||||||
|
const bindType = $(this).data("bind-type");
|
||||||
|
$panel.find(".tx-bind-mode").attr("data-bind-type", bindType);
|
||||||
|
$panel.find(".tx-bind-mode button").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
$panel.find("#addAccountNo, #editAccountNo").toggleClass("tx-hidden", bindType !== "account");
|
||||||
|
$panel.find(".tx-alipay-qrcode").toggleClass("tx-hidden", bindType !== "qrcode");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#withdrawAll").on("click", function () {
|
||||||
|
$("#withdrawAmount").val(money(getSourceAmount($("#withdrawSource").val())));
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#transferAll").on("click", function () {
|
||||||
|
$("#transferAmount").val(money(getSourceAmount($("#transferSource").val())));
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#receiveAccountEditMask").on("click", function (event) {
|
||||||
|
if (event.target === this) closeReceiveAccountEdit();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320 ? $("#backTop").addClass("is-visible") : $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
renderWalletSourceCards();
|
||||||
|
renderMethodCards();
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadReceiveAccounts();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,450 @@
|
|||||||
|
<!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/publish.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/pagination.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/tixianlist.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img src="../images/home-logo.png" alt="彩先知" class="topbar__logo" />
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary">免费注册</a>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged tl-hidden">
|
||||||
|
<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 class="cxz-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<a href="tixian.html">提现</a><span class="sep">></span>
|
||||||
|
<span>提现记录</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="tl-card">
|
||||||
|
<div class="tl-header">
|
||||||
|
<div>
|
||||||
|
<div class="tl-title">提现记录</div>
|
||||||
|
<div class="tl-desc">查看销售余额、专家余额的提现申请进度和收款方式。</div>
|
||||||
|
</div>
|
||||||
|
<a class="tl-back-link" href="tixian.html">返回提现</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tl-filter-bar">
|
||||||
|
<div class="tl-filter-group">
|
||||||
|
<span>状态</span>
|
||||||
|
<div class="tl-segment" id="statusFilters"></div>
|
||||||
|
</div>
|
||||||
|
<div class="tl-filter-group">
|
||||||
|
<span>来源</span>
|
||||||
|
<div class="tl-segment" id="sourceFilters"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tl-summary">
|
||||||
|
<div class="tl-summary-item">
|
||||||
|
<span>记录总数</span>
|
||||||
|
<strong id="recordTotal">0</strong>
|
||||||
|
</div>
|
||||||
|
<div class="tl-summary-item">
|
||||||
|
<span>本页金额</span>
|
||||||
|
<strong id="pageAmount">0.00 元</strong>
|
||||||
|
</div>
|
||||||
|
<div class="tl-summary-item">
|
||||||
|
<span>当前筛选</span>
|
||||||
|
<strong id="filterSummary">全部状态 / 全部来源</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tl-table-wrap">
|
||||||
|
<table class="tl-table" id="withdrawTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>申请单号</th>
|
||||||
|
<th>提现来源</th>
|
||||||
|
<th>提现方式</th>
|
||||||
|
<th>金额</th>
|
||||||
|
<th>收款账户</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>申请时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
<div class="tl-empty" id="emptyState">
|
||||||
|
<div class="tl-empty-icon">¥</div>
|
||||||
|
<div class="tl-empty-title">暂无提现记录</div>
|
||||||
|
<div class="tl-empty-desc">当前筛选条件下还没有提现申请。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tl-pagination cxz-pagination" id="withdrawPagination"></div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<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" class="tl-beian-link" href="https://beian.miit.gov.cn/" target="_blank">工信部备案号</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.$;
|
||||||
|
const statusOptions = [
|
||||||
|
{ value: "", label: "全部" },
|
||||||
|
{ value: "reviewing", label: "审核中" },
|
||||||
|
{ value: "success", label: "成功" },
|
||||||
|
{ value: "failed", label: "失败" },
|
||||||
|
{ value: "cancelled", label: "取消" },
|
||||||
|
];
|
||||||
|
const sourceOptions = [
|
||||||
|
{ value: "", label: "全部" },
|
||||||
|
{ value: "sales", label: "销售余额" },
|
||||||
|
{ value: "expert", label: "专家余额" },
|
||||||
|
];
|
||||||
|
const statusTextMap = {
|
||||||
|
0: "审核中",
|
||||||
|
1: "成功",
|
||||||
|
2: "失败",
|
||||||
|
3: "取消",
|
||||||
|
reviewing: "审核中",
|
||||||
|
success: "成功",
|
||||||
|
failed: "失败",
|
||||||
|
cancelled: "取消",
|
||||||
|
};
|
||||||
|
const statusClassMap = {
|
||||||
|
0: "reviewing",
|
||||||
|
1: "success",
|
||||||
|
2: "failed",
|
||||||
|
3: "cancelled",
|
||||||
|
reviewing: "reviewing",
|
||||||
|
success: "success",
|
||||||
|
failed: "failed",
|
||||||
|
cancelled: "cancelled",
|
||||||
|
};
|
||||||
|
const sourceTextMap = {
|
||||||
|
sales: "销售余额",
|
||||||
|
expert: "专家余额",
|
||||||
|
};
|
||||||
|
const methodTextMap = {
|
||||||
|
alipay: "支付宝",
|
||||||
|
wechat: "微信收款码",
|
||||||
|
wechat_qr: "微信收款码",
|
||||||
|
bank: "银行卡",
|
||||||
|
bank_card: "银行卡",
|
||||||
|
};
|
||||||
|
|
||||||
|
let currentPage = 1;
|
||||||
|
let pageSize = 10;
|
||||||
|
let totalRow = 0;
|
||||||
|
let currentStatus = "";
|
||||||
|
let currentSource = "";
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSuccess(res) {
|
||||||
|
return ApiClient.isSuccess ? ApiClient.isSuccess(res) : res && (res.code === 0 || res.code === 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickData(res) {
|
||||||
|
return ApiClient.pickData ? ApiClient.pickData(res) : res && res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function asArray(value) {
|
||||||
|
return ApiClient.asArray ? ApiClient.asArray(value) : Array.isArray(value) ? value : value ? [value] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return String(value == null ? "" : value)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function fieldValue(item, keys) {
|
||||||
|
for (let i = 0; i < keys.length; i += 1) {
|
||||||
|
const value = item && item[keys[i]];
|
||||||
|
if (value !== undefined && value !== null && value !== "") return value;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function money(value) {
|
||||||
|
const number = Number(value || 0);
|
||||||
|
return Number.isFinite(number) ? number.toFixed(2) : "0.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
const token = CommonUtil.getAuthToken ? CommonUtil.getAuthToken() : localStorage.getItem("token");
|
||||||
|
if (!token) {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#notLoggedInBox").addClass("tl-hidden");
|
||||||
|
$("#loggedInBox").removeClass("tl-hidden");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
$("#userName").text(data.nickName || data.nickname || "用户");
|
||||||
|
$("#userLevel").text(data.isExpert === "1" ? "专家" : "会员");
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").removeClass("tl-hidden");
|
||||||
|
$("#loggedInBox").addClass("tl-hidden");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.get(ApiClient.API.homeNav).then(function (res) {
|
||||||
|
if (!isSuccess(res) || !res.data) return;
|
||||||
|
const $nav = $("#navLotteryItems").empty();
|
||||||
|
$.each(asArray(pickData(res)), function (_, item) {
|
||||||
|
if (item.type && item.type !== "lottery") return;
|
||||||
|
const code = item.code || item.suoxie || "";
|
||||||
|
if (!code) return;
|
||||||
|
$nav.append('<a href="cai.html?id=' + encodeURIComponent(code) + '" class="topbar__nav-link">' + escapeHtml(item.name || item.lotteryName || code) + "</a>");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFilters() {
|
||||||
|
renderSegment("#statusFilters", statusOptions, currentStatus, function (value) {
|
||||||
|
currentStatus = value;
|
||||||
|
currentPage = 1;
|
||||||
|
loadWithdrawList();
|
||||||
|
});
|
||||||
|
renderSegment("#sourceFilters", sourceOptions, currentSource, function (value) {
|
||||||
|
currentSource = value;
|
||||||
|
currentPage = 1;
|
||||||
|
loadWithdrawList();
|
||||||
|
});
|
||||||
|
updateFilterSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSegment(selector, options, selectedValue, onChange) {
|
||||||
|
const $wrap = $(selector).empty();
|
||||||
|
$.each(options, function (_, item) {
|
||||||
|
const $button = $('<button class="tl-segment-btn" type="button"></button>');
|
||||||
|
$button.text(item.label);
|
||||||
|
$button.toggleClass("active", item.value === selectedValue);
|
||||||
|
$button.on("click", function () {
|
||||||
|
onChange(item.value);
|
||||||
|
renderFilters();
|
||||||
|
});
|
||||||
|
$wrap.append($button);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFilterSummary() {
|
||||||
|
const statusLabel = statusOptions.find((item) => item.value === currentStatus)?.label || "全部";
|
||||||
|
const sourceLabel = sourceOptions.find((item) => item.value === currentSource)?.label || "全部";
|
||||||
|
$("#filterSummary").text(statusLabel + "状态 / " + sourceLabel + "来源");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecords(data, res) {
|
||||||
|
return asArray(data.records || data.rows || data.list || res.records || res.rows || res.list || data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTotal(data, records, res) {
|
||||||
|
return Number(data.total || data.totalRow || data.totalCount || data.count || res.total || res.totalRow || res.totalCount || res.count || records.length || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecordNo(item) {
|
||||||
|
return fieldValue(item, ["withdrawNo", "orderNo", "flowNo", "serialNo", "tradeNo", "id"]) || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAmount(item) {
|
||||||
|
return Number(fieldValue(item, ["amount", "withdrawAmount", "money", "applyAmount", "flowAmount"]) || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatus(item) {
|
||||||
|
return fieldValue(item, ["status", "withdrawStatus", "auditStatus"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusText(item) {
|
||||||
|
const status = getStatus(item);
|
||||||
|
return fieldValue(item, ["statusText", "withdrawStatusText", "auditStatusText"]) || statusTextMap[status] || statusTextMap[String(status)] || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusClass(item) {
|
||||||
|
const status = getStatus(item);
|
||||||
|
return statusClassMap[status] || statusClassMap[String(status)] || "normal";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSourceText(item) {
|
||||||
|
const source = fieldValue(item, ["sourceWallet", "walletType"]);
|
||||||
|
return fieldValue(item, ["sourceWalletText", "walletTypeText"]) || sourceTextMap[source] || source || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMethodText(item) {
|
||||||
|
const method = fieldValue(item, ["withdrawType", "receiveType", "paymentType"]);
|
||||||
|
return fieldValue(item, ["withdrawTypeText", "receiveTypeText", "paymentTypeText"]) || methodTextMap[method] || method || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReceiveAccountText(item) {
|
||||||
|
const direct = fieldValue(item, ["receiveAccountText", "receiveAccount", "accountNo", "alipayAccount", "bankCardNo"]);
|
||||||
|
if (direct && typeof direct !== "object") return direct;
|
||||||
|
const receiveAccount = item.receiveAccountInfo || item.receiveAccountVO || (typeof item.receiveAccount === "object" ? item.receiveAccount : {}) || {};
|
||||||
|
const method = fieldValue(item, ["withdrawType", "receiveType"]);
|
||||||
|
if (method === "bank") {
|
||||||
|
return [receiveAccount.bankName, receiveAccount.bankCardNo].filter(Boolean).join(" ") || "--";
|
||||||
|
}
|
||||||
|
return fieldValue(receiveAccount, ["alipayAccount", "wechatAccount", "accountNo", "realName"]) || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCreateTime(item) {
|
||||||
|
const time = fieldValue(item, ["createTime", "createdTime", "applyTime", "submitTime", "updateTime"]);
|
||||||
|
return DateUtil.formatDateTimeToYMDHM(time) || time || "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadWithdrawList() {
|
||||||
|
const params = {
|
||||||
|
pageNum: currentPage,
|
||||||
|
pageSize: pageSize,
|
||||||
|
};
|
||||||
|
if (currentStatus) params.status = currentStatus;
|
||||||
|
if (currentSource) params.sourceWallet = currentSource;
|
||||||
|
|
||||||
|
$("#withdrawTable").addClass("loading");
|
||||||
|
ApiClient.get(ApiClient.API.walletWithdrawList, params)
|
||||||
|
.then(function (res) {
|
||||||
|
if (!isSuccess(res)) throw new Error(res.msg || "获取提现记录失败");
|
||||||
|
const data = pickData(res) || res || {};
|
||||||
|
const records = getRecords(data, res);
|
||||||
|
totalRow = getTotal(data, records, res);
|
||||||
|
renderTable(records);
|
||||||
|
renderPagination();
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layui.layer.msg(err.message || "获取提现记录失败", { icon: 2 });
|
||||||
|
totalRow = 0;
|
||||||
|
renderTable([]);
|
||||||
|
renderPagination();
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
$("#withdrawTable").removeClass("loading");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTable(records) {
|
||||||
|
const $tbody = $("#withdrawTable tbody").empty();
|
||||||
|
let pageAmount = 0;
|
||||||
|
if (!records.length) {
|
||||||
|
$("#withdrawTable").addClass("tl-table-hidden");
|
||||||
|
$("#emptyState").addClass("show");
|
||||||
|
$(".tl-summary").addClass("is-hidden");
|
||||||
|
} else {
|
||||||
|
$("#withdrawTable").removeClass("tl-table-hidden");
|
||||||
|
$("#emptyState").removeClass("show");
|
||||||
|
$(".tl-summary").removeClass("is-hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(records, function (_, item) {
|
||||||
|
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>",
|
||||||
|
);
|
||||||
|
$tbody.append($row);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#recordTotal").text(totalRow);
|
||||||
|
$("#pageAmount").text(money(pageAmount) + " 元");
|
||||||
|
updateFilterSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination() {
|
||||||
|
if (totalRow <= 0) {
|
||||||
|
$("#withdrawPagination").empty().addClass("is-hidden");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#withdrawPagination").removeClass("is-hidden");
|
||||||
|
layui.use("laypage", function () {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: "withdrawPagination",
|
||||||
|
count: totalRow,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPage,
|
||||||
|
layout: ["prev", "page", "next"],
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (first) return;
|
||||||
|
currentPage = obj.curr;
|
||||||
|
loadWithdrawList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initFromUrl() {
|
||||||
|
const query = new URLSearchParams(window.location.search);
|
||||||
|
const status = query.get("status") || "";
|
||||||
|
const sourceWallet = query.get("sourceWallet") || "";
|
||||||
|
if (statusOptions.some((item) => item.value === status)) currentStatus = status;
|
||||||
|
if (sourceOptions.some((item) => item.value === sourceWallet)) currentSource = sourceWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320 ? $("#backTop").addClass("is-visible") : $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
initFromUrl();
|
||||||
|
renderFilters();
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadWithdrawList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,873 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title id="page-title">彩先知 - 推广赚钱</title>
|
||||||
|
<script src="../public/css/layui/layui.js"></script>
|
||||||
|
<script src="../config.js"></script>
|
||||||
|
<script src="../utils/ApiClient.js"></script>
|
||||||
|
<script src="../utils/DateUtil.js"></script>
|
||||||
|
<script src="../utils/CommonUtil.js"></script>
|
||||||
|
<script src="../public/js/qrcode.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="../public/css/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="../public/css/distribution.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems"></div>
|
||||||
|
<div class="topbar__user">
|
||||||
|
<div id="notLoggedInBox" class="topbar__guest">
|
||||||
|
<a href="login.html" class="topbar__btn topbar__btn--ghost">登录</a>
|
||||||
|
<a href="reg.html" class="topbar__btn topbar__btn--primary"
|
||||||
|
>免费注册</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="loggedInBox" class="topbar__logged" style="display: none">
|
||||||
|
<a href="usercenter.html" class="topbar__profile">
|
||||||
|
<img
|
||||||
|
id="userAvatar"
|
||||||
|
src="../public/img/userimg.png"
|
||||||
|
alt=""
|
||||||
|
class="topbar__avatar"
|
||||||
|
/>
|
||||||
|
<div class="topbar__meta">
|
||||||
|
<span id="userName" class="topbar__uname">用户</span>
|
||||||
|
<span id="userLevel" class="topbar__ubadge">会员</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<button class="topbar__btn topbar__btn--logout" onclick="logout()">
|
||||||
|
退出登录
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="cxz-main">
|
||||||
|
<div class="cxz-breadcrumb">
|
||||||
|
<a href="index.html">首页</a><span class="sep">></span>
|
||||||
|
<a href="usercenter.html">个人中心</a><span class="sep">></span>
|
||||||
|
<span>推广赚钱</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Banner -->
|
||||||
|
<div class="promo-banner">
|
||||||
|
<h2>推广赚<span>佣金</span></h2>
|
||||||
|
<p>
|
||||||
|
复制分享链接,邀请好友注册即可获得分销收益。一级分销返佣更高,多级返佣轻松赚钱!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats -->
|
||||||
|
<div class="stats-row">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">分销余额</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="salesBalance">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">累计返利</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="distIncome">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">邀请人数</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="totalSubordinates">0</span><span class="unit">人</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">待结算</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="pendingRebate">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">返利比例</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="rebateRate">--</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- QR Code & Link -->
|
||||||
|
<div class="promo-content">
|
||||||
|
<div class="qr-card">
|
||||||
|
<div class="qr-card-title">推广二维码</div>
|
||||||
|
<div class="qr-code-box">
|
||||||
|
<img id="promoQrImg" src="" alt="推广二维码" />
|
||||||
|
</div>
|
||||||
|
<div class="qr-card-tip">扫描二维码即可注册</div>
|
||||||
|
</div>
|
||||||
|
<div class="link-card">
|
||||||
|
<div class="link-card-title">推广链接</div>
|
||||||
|
<div class="link-input-wrap">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="link-input"
|
||||||
|
id="promoLink"
|
||||||
|
readonly
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
<button class="copy-btn" id="copyLinkBtn" onclick="copyPromoLink()">
|
||||||
|
复制链接
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="share-tips">
|
||||||
|
<h4>推广说明</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
通过您的推广链接注册的用户将成为您的<strong>一级下级</strong>
|
||||||
|
</li>
|
||||||
|
<li>一级下级消费您可获得<strong>高比例</strong>返佣</li>
|
||||||
|
<li>
|
||||||
|
一级下级的下级为您的<strong>二级下级</strong>,也可获得返佣
|
||||||
|
</li>
|
||||||
|
<li>推广收益可随时申请<strong>提现</strong></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Invite List Table -->
|
||||||
|
<div class="team-section">
|
||||||
|
<div class="team-section-title team-section-title--filter">
|
||||||
|
<span><i class="layui-icon layui-icon-group"></i> 邀请用户</span>
|
||||||
|
<div class="promo-filter" id="inviteFilter">
|
||||||
|
<button class="active" type="button" data-filter="all">全部</button>
|
||||||
|
<button type="button" data-filter="active">已消费</button>
|
||||||
|
<button type="button" data-filter="new">未消费</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="team-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>头像</th>
|
||||||
|
<th>用户名称</th>
|
||||||
|
<th>注册时间</th>
|
||||||
|
<th>消费金额</th>
|
||||||
|
<th>贡献返利</th>
|
||||||
|
<th>状态</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="inviteTableBody">
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colspan="6"
|
||||||
|
style="
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 40px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
加载中...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="cxz-pagination" id="invitePager"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rebate Flow Table -->
|
||||||
|
<div class="team-section">
|
||||||
|
<div class="team-section-title team-section-title--filter">
|
||||||
|
<span><i class="layui-icon layui-icon-rmb"></i> 返利流水</span>
|
||||||
|
<div class="promo-filter" id="rebateFilter">
|
||||||
|
<button class="active" type="button" data-filter="all">全部</button>
|
||||||
|
<button type="button" data-filter="pending">待结算</button>
|
||||||
|
<button type="button" data-filter="success">已结算</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="team-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>流水号</th>
|
||||||
|
<th>来源用户</th>
|
||||||
|
<th>返利金额</th>
|
||||||
|
<th>比例</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="rebateTableBody">
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colspan="6"
|
||||||
|
style="
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 40px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
加载中...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="cxz-pagination" id="rebatePager"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="promo-info-grid">
|
||||||
|
<div class="team-section promo-info-card">
|
||||||
|
<div class="team-section-title">
|
||||||
|
<i class="layui-icon layui-icon-about"></i> 绑定规则
|
||||||
|
</div>
|
||||||
|
<div class="promo-rule-list">
|
||||||
|
<div class="promo-rule-item">
|
||||||
|
<span>1</span>
|
||||||
|
<p>好友通过您的推广链接注册后,会自动绑定为邀请用户。</p>
|
||||||
|
</div>
|
||||||
|
<div class="promo-rule-item">
|
||||||
|
<span>2</span>
|
||||||
|
<p>好友购买付费内容后,会生成返利记录并等待结算。</p>
|
||||||
|
</div>
|
||||||
|
<div class="promo-rule-item">
|
||||||
|
<span>3</span>
|
||||||
|
<p>返利比例以当前平台配置为准,页面会展示接口返回的比例。</p>
|
||||||
|
</div>
|
||||||
|
<div class="promo-rule-item">
|
||||||
|
<span>4</span>
|
||||||
|
<p>已结算返利可进入提现页面处理,具体以钱包余额为准。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="team-section promo-info-card">
|
||||||
|
<div class="team-section-title">
|
||||||
|
<i class="layui-icon layui-icon-chart-screen"></i> 返利流程
|
||||||
|
</div>
|
||||||
|
<div class="promo-flow-list">
|
||||||
|
<div class="promo-flow-step"><strong>01</strong><span>分享链接</span></div>
|
||||||
|
<div class="promo-flow-step"><strong>02</strong><span>好友注册</span></div>
|
||||||
|
<div class="promo-flow-step"><strong>03</strong><span>购买付费文章</span></div>
|
||||||
|
<div class="promo-flow-step"><strong>04</strong><span>返利结算</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- QR Code Modal -->
|
||||||
|
<div class="cxz-dialog-overlay" id="qrDialog" style="display: none">
|
||||||
|
<div class="cxz-dialog-box">
|
||||||
|
<div class="cxz-dialog-header">
|
||||||
|
<div class="cxz-dialog-title">推广二维码</div>
|
||||||
|
<button class="cxz-dialog-close" onclick="closeQrDialog()">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="cxz-dialog-body" style="text-align: center; padding: 24px">
|
||||||
|
<div
|
||||||
|
id="qrCodeContainer"
|
||||||
|
style="
|
||||||
|
display: inline-block;
|
||||||
|
padding: 16px;
|
||||||
|
border: 2px dashed var(--border-light);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
<p
|
||||||
|
style="margin-top: 12px; font-size: 13px; color: var(--text-muted)"
|
||||||
|
>
|
||||||
|
长按或截图分享给好友
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="site-footer__inner">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="site-footer__logo"
|
||||||
|
/>
|
||||||
|
<p id="copyright-info">彩先知以开奖数据、免费文章、资讯推荐为核心</p>
|
||||||
|
<div class="site-footer__meta">
|
||||||
|
<a
|
||||||
|
id="beian"
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
style="font-size: 12px; color: rgba(255, 255, 255, 0.5)"
|
||||||
|
>工信部备案号</a
|
||||||
|
>
|
||||||
|
<span id="additional-info">本站仅供数据分析参考</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<button
|
||||||
|
class="gotop"
|
||||||
|
id="backTop"
|
||||||
|
type="button"
|
||||||
|
onclick="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const $ = layui.$;
|
||||||
|
let invitePage = 1;
|
||||||
|
let rebatePage = 1;
|
||||||
|
let inviteFilter = "all";
|
||||||
|
let rebateFilter = "all";
|
||||||
|
const pageSize = 10;
|
||||||
|
let promoSummary = {
|
||||||
|
salesBalance: 0,
|
||||||
|
totalSubordinates: 0,
|
||||||
|
distributionIncome: 0,
|
||||||
|
pendingRebate: 0,
|
||||||
|
rebateRate: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
$("#userName").text(data.nickName || "用户");
|
||||||
|
$("#userLevel").text(data.isExpert === "1" ? "专家" : "会员");
|
||||||
|
if (data.avatar) $("#userAvatar").attr("src", data.avatar);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$("#notLoggedInBox").show();
|
||||||
|
$("#loggedInBox").hide();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
window.location.href = "login.html";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNav() {
|
||||||
|
ApiClient.post("/api/web/menu/getFormatList", {}).then(function (res) {
|
||||||
|
if (res.code !== 0 || !res.data) return;
|
||||||
|
var $nav = $("#navLotteryItems");
|
||||||
|
$nav.find(".topbar__nav-link").not(":first").remove();
|
||||||
|
$.each(res.data, function (i, item) {
|
||||||
|
$nav.append(
|
||||||
|
'<a href="cai.html?id=' +
|
||||||
|
item.suoxie +
|
||||||
|
'" class="topbar__nav-link">' +
|
||||||
|
item.name +
|
||||||
|
"</a>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on("scroll", function () {
|
||||||
|
$(window).scrollTop() > 320
|
||||||
|
? $("#backTop").addClass("is-visible")
|
||||||
|
: $("#backTop").removeClass("is-visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
function isSuccess(res) {
|
||||||
|
return ApiClient.isSuccess
|
||||||
|
? ApiClient.isSuccess(res)
|
||||||
|
: res && (res.code === 0 || res.code === 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickData(res, fallback) {
|
||||||
|
if (ApiClient.pickData) return ApiClient.pickData(res, fallback);
|
||||||
|
return res && res.data !== undefined && res.data !== null
|
||||||
|
? res.data
|
||||||
|
: fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function asRows(data) {
|
||||||
|
if (ApiClient.asArray) return ApiClient.asArray(data);
|
||||||
|
if (Array.isArray(data)) return data;
|
||||||
|
if (!data || typeof data !== "object") return [];
|
||||||
|
return data.records || data.rows || data.list || data.items || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstDefined() {
|
||||||
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
|
var value = arguments[i];
|
||||||
|
if (value !== undefined && value !== null && value !== "") return value;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function numberValue(value, fallback) {
|
||||||
|
var n = Number(value);
|
||||||
|
return isNaN(n) ? fallback || 0 : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStats(data) {
|
||||||
|
data = data || {};
|
||||||
|
promoSummary.salesBalance = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
data.salesBalance,
|
||||||
|
data.rebateBalance,
|
||||||
|
data.availableRebate,
|
||||||
|
data.availableAmount,
|
||||||
|
data.canWithdrawAmount,
|
||||||
|
promoSummary.salesBalance,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
promoSummary.totalSubordinates = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
data.totalSubordinates,
|
||||||
|
data.inviteTotal,
|
||||||
|
data.inviteCount,
|
||||||
|
data.totalInvite,
|
||||||
|
promoSummary.totalSubordinates,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
promoSummary.distributionIncome = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
data.distributionIncome,
|
||||||
|
data.rebateTotal,
|
||||||
|
data.totalRebate,
|
||||||
|
data.totalAmount,
|
||||||
|
promoSummary.distributionIncome,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
promoSummary.pendingRebate = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
data.pendingRebate,
|
||||||
|
data.pendingAmount,
|
||||||
|
data.waitAmount,
|
||||||
|
data.unsettledAmount,
|
||||||
|
promoSummary.pendingRebate,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
promoSummary.rebateRate = firstDefined(
|
||||||
|
data.rebateRate,
|
||||||
|
data.rate,
|
||||||
|
data.rebateRatio,
|
||||||
|
promoSummary.rebateRate,
|
||||||
|
);
|
||||||
|
|
||||||
|
$("#salesBalance").text((promoSummary.salesBalance || 0).toFixed(2));
|
||||||
|
$("#totalSubordinates").text(promoSummary.totalSubordinates || 0);
|
||||||
|
$("#distIncome").text(
|
||||||
|
(promoSummary.distributionIncome || 0).toFixed(2),
|
||||||
|
);
|
||||||
|
$("#pendingRebate").text((promoSummary.pendingRebate || 0).toFixed(2));
|
||||||
|
$("#rebateRate").text(rateText(promoSummary.rebateRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
function rateText(value) {
|
||||||
|
if (value === undefined || value === null || value === "") return "--";
|
||||||
|
var n = Number(value);
|
||||||
|
if (isNaN(n)) return String(value);
|
||||||
|
return n > 0 && n < 1 ? Math.round(n * 100) + "%" : n + "%";
|
||||||
|
}
|
||||||
|
|
||||||
|
function totalOf(data, rows) {
|
||||||
|
return (
|
||||||
|
numberValue(
|
||||||
|
firstDefined(data.totalRow, data.total, data.totalCount, data.count),
|
||||||
|
0,
|
||||||
|
) || (rows ? rows.length : 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fullShareLink(url, code) {
|
||||||
|
if (url && /^https?:\/\//.test(url)) return url;
|
||||||
|
if (url) {
|
||||||
|
if (url.indexOf("/html/reg.html") >= 0) {
|
||||||
|
return ApiClient.baseUrl.replace(/\/$/, "") + "/" + url.replace(/^\//, "");
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
ApiClient.baseUrl.replace(/\/$/, "") +
|
||||||
|
"/html/reg.html?affUrl=" +
|
||||||
|
encodeURIComponent(url.replace(/^\//, ""))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
location.origin +
|
||||||
|
"/html/reg.html" +
|
||||||
|
(code ? "?inviteCode=" + encodeURIComponent(code) : "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load promotion info (link + QR code)
|
||||||
|
function loadPromoInfo() {
|
||||||
|
ApiClient.get(ApiClient.API.referralShareInfo)
|
||||||
|
.then(function (res) {
|
||||||
|
if (isSuccess(res)) {
|
||||||
|
var data = pickData(res, {}) || {};
|
||||||
|
// Build share link
|
||||||
|
var shareLink = fullShareLink(
|
||||||
|
firstDefined(
|
||||||
|
data.affUrl,
|
||||||
|
data.shareUrl,
|
||||||
|
data.shareLink,
|
||||||
|
data.inviteUrl,
|
||||||
|
data.promoteUrl,
|
||||||
|
data.referralUrl,
|
||||||
|
data.url,
|
||||||
|
),
|
||||||
|
firstDefined(
|
||||||
|
data.inviteCode,
|
||||||
|
data.referralCode,
|
||||||
|
data.affCode,
|
||||||
|
data.code,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$("#promoLink").val(shareLink);
|
||||||
|
|
||||||
|
// Generate QR code
|
||||||
|
if (shareLink) {
|
||||||
|
CommonUtil.generateQRCode(shareLink, "promoQrImg", {
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
colorDark: "#102b6a",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStats(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error("获取推广信息失败:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPromoSummary() {
|
||||||
|
if (!ApiClient.API.referralSummary) return;
|
||||||
|
ApiClient.get(ApiClient.API.referralSummary)
|
||||||
|
.then(function (res) {
|
||||||
|
if (isSuccess(res)) updateStats(pickData(res, {}) || {});
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error("获取推广统计失败:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy promo link
|
||||||
|
function copyPromoLink() {
|
||||||
|
var link = $("#promoLink").val();
|
||||||
|
if (!link) {
|
||||||
|
layui.layer.msg("推广链接为空", { icon: 2 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(link)
|
||||||
|
.then(function () {
|
||||||
|
layui.layer.msg("链接已复制到剪贴板!", { icon: 1, time: 1500 });
|
||||||
|
var $btn = $("#copyLinkBtn");
|
||||||
|
$btn
|
||||||
|
.text("已复制")
|
||||||
|
.css(
|
||||||
|
"background",
|
||||||
|
"linear-gradient(135deg, var(--green), #2ecc71)",
|
||||||
|
);
|
||||||
|
setTimeout(function () {
|
||||||
|
$btn.text("复制链接").css("background", "");
|
||||||
|
}, 2000);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
fallbackCopy(link);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fallbackCopy(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fallbackCopy(text) {
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.value = text;
|
||||||
|
document.body.appendChild(input);
|
||||||
|
input.select();
|
||||||
|
try {
|
||||||
|
document.execCommand("copy");
|
||||||
|
layui.layer.msg("链接已复制到剪贴板!", { icon: 1, time: 1500 });
|
||||||
|
} catch (e) {
|
||||||
|
layui.layer.msg("复制失败,请手动复制", { icon: 2 });
|
||||||
|
}
|
||||||
|
document.body.removeChild(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeQrDialog() {
|
||||||
|
$("#qrDialog").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function avatarCell(item, fallbackName) {
|
||||||
|
var avatar = firstDefined(item.avatar, item.avatarUrl, item.headImg);
|
||||||
|
if (avatar) {
|
||||||
|
return (
|
||||||
|
'<img src="' +
|
||||||
|
escapeHtml(avatar) +
|
||||||
|
'" style="width:32px;height:32px;border-radius:50%;object-fit:cover;border:2px solid rgba(253,185,51,0.4);" />'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
'<div style="width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,var(--primary),var(--primary-light));color:#fff;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;">' +
|
||||||
|
escapeHtml((fallbackName || "用").charAt(0)) +
|
||||||
|
"</div>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusLabel(label, type) {
|
||||||
|
return (
|
||||||
|
'<span class="promo-status ' +
|
||||||
|
type +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(label) +
|
||||||
|
"</span>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadInviteList() {
|
||||||
|
var params = { pageNum: invitePage, pageSize: pageSize };
|
||||||
|
if (inviteFilter === "active") params.consumed = true;
|
||||||
|
if (inviteFilter === "new") params.consumed = false;
|
||||||
|
ApiClient.get(ApiClient.API.referralInviteList, params)
|
||||||
|
.then(function (res) {
|
||||||
|
if (isSuccess(res)) {
|
||||||
|
var data = pickData(res, {}) || {};
|
||||||
|
var list = asRows(data);
|
||||||
|
renderInviteList(list);
|
||||||
|
renderPager("invitePager", totalOf(data, list), invitePage, function (page) {
|
||||||
|
invitePage = page;
|
||||||
|
loadInviteList();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
renderInviteList([]);
|
||||||
|
renderPager("invitePager", 0, 1, function () {});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error("请求邀请用户失败:", err);
|
||||||
|
$("#inviteTableBody").html(
|
||||||
|
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">加载失败,请重试</td></tr>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderInviteList(list) {
|
||||||
|
var $tbody = $("#inviteTableBody");
|
||||||
|
$tbody.empty();
|
||||||
|
if (!list || !list.length) {
|
||||||
|
$tbody.html(
|
||||||
|
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">暂无邀请用户</td></tr>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
var nickName = firstDefined(
|
||||||
|
item.nickName,
|
||||||
|
item.nickname,
|
||||||
|
item.userName,
|
||||||
|
item.username,
|
||||||
|
item.mobile,
|
||||||
|
item.phone,
|
||||||
|
"未知用户",
|
||||||
|
);
|
||||||
|
var registerTime = firstDefined(
|
||||||
|
item.registerTime,
|
||||||
|
item.regTime,
|
||||||
|
item.createTime,
|
||||||
|
item.createdAt,
|
||||||
|
);
|
||||||
|
var consumeAmount = numberValue(
|
||||||
|
firstDefined(item.consumeAmount, item.amount, item.totalAmount),
|
||||||
|
).toFixed(2);
|
||||||
|
var rebateAmount = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
item.rebateMoney,
|
||||||
|
item.rebateAmount,
|
||||||
|
item.commissionAmount,
|
||||||
|
item.rewardAmount,
|
||||||
|
),
|
||||||
|
).toFixed(2);
|
||||||
|
var consumed =
|
||||||
|
item.hasConsume === true ||
|
||||||
|
item.isConsumed === true ||
|
||||||
|
item.consumeFlag === 1 ||
|
||||||
|
item.consumeFlag === "1" ||
|
||||||
|
Number(consumeAmount) > 0;
|
||||||
|
$tbody.append(
|
||||||
|
"<tr>" +
|
||||||
|
"<td>" +
|
||||||
|
avatarCell(item, nickName) +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(nickName) +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(registerTime ? String(registerTime).substring(0, 10) : "--") +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
consumeAmount +
|
||||||
|
"元</td>" +
|
||||||
|
'<td style="color:var(--orange);font-weight:600;">' +
|
||||||
|
rebateAmount +
|
||||||
|
"元</td>" +
|
||||||
|
"<td>" +
|
||||||
|
(consumed
|
||||||
|
? statusLabel("已消费", "success")
|
||||||
|
: statusLabel("未消费", "pending")) +
|
||||||
|
"</td>" +
|
||||||
|
"</tr>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRebateList() {
|
||||||
|
var params = { pageNum: rebatePage, pageSize: pageSize };
|
||||||
|
if (rebateFilter === "pending") params.status = 0;
|
||||||
|
if (rebateFilter === "success") params.status = 1;
|
||||||
|
ApiClient.get(ApiClient.API.referralRebateList, params)
|
||||||
|
.then(function (res) {
|
||||||
|
if (isSuccess(res)) {
|
||||||
|
var data = pickData(res, {}) || {};
|
||||||
|
var list = asRows(data);
|
||||||
|
renderRebateList(list);
|
||||||
|
renderPager("rebatePager", totalOf(data, list), rebatePage, function (page) {
|
||||||
|
rebatePage = page;
|
||||||
|
loadRebateList();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
renderRebateList([]);
|
||||||
|
renderPager("rebatePager", 0, 1, function () {});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error("请求返利流水失败:", err);
|
||||||
|
$("#rebateTableBody").html(
|
||||||
|
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">加载失败,请重试</td></tr>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRebateList(list) {
|
||||||
|
var $tbody = $("#rebateTableBody");
|
||||||
|
$tbody.empty();
|
||||||
|
if (!list || !list.length) {
|
||||||
|
$tbody.html(
|
||||||
|
'<tr><td colspan="6" style="text-align:center;color:var(--text-muted);padding:40px;">暂无返利流水</td></tr>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.each(list, function (i, item) {
|
||||||
|
var flowNo = firstDefined(item.flowNo, item.orderNo, item.id, item.rebateNo, "--");
|
||||||
|
var sourceUser = firstDefined(
|
||||||
|
item.sourceUserName,
|
||||||
|
item.inviteUserName,
|
||||||
|
item.nickName,
|
||||||
|
item.nickname,
|
||||||
|
item.mobile,
|
||||||
|
"未知用户",
|
||||||
|
);
|
||||||
|
var amount = numberValue(
|
||||||
|
firstDefined(
|
||||||
|
item.rebateMoney,
|
||||||
|
item.rebateAmount,
|
||||||
|
item.commissionAmount,
|
||||||
|
item.rewardAmount,
|
||||||
|
item.amount,
|
||||||
|
),
|
||||||
|
).toFixed(2);
|
||||||
|
var rate = rateText(firstDefined(item.rebateRate, item.rate, item.ratio));
|
||||||
|
var status = firstDefined(item.status, item.state, item.settleStatus, 0);
|
||||||
|
var statusHtml =
|
||||||
|
status === 1 ||
|
||||||
|
status === "1" ||
|
||||||
|
status === "success" ||
|
||||||
|
status === "settled"
|
||||||
|
? statusLabel("已结算", "success")
|
||||||
|
: statusLabel("待结算", "pending");
|
||||||
|
var time = firstDefined(item.createTime, item.settleTime, item.time, item.createdAt);
|
||||||
|
$tbody.append(
|
||||||
|
"<tr>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(flowNo) +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(sourceUser) +
|
||||||
|
"</td>" +
|
||||||
|
'<td style="color:var(--orange);font-weight:600;">' +
|
||||||
|
amount +
|
||||||
|
"元</td>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(rate) +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
statusHtml +
|
||||||
|
"</td>" +
|
||||||
|
"<td>" +
|
||||||
|
escapeHtml(time ? String(time).substring(0, 19).replace("T", " ") : "--") +
|
||||||
|
"</td>" +
|
||||||
|
"</tr>",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPager(elem, total, curr, onJump) {
|
||||||
|
layui.laypage.render({
|
||||||
|
elem: elem,
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: curr,
|
||||||
|
layout: ["prev", "page", "next"],
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first && obj.curr !== curr) onJump(obj.curr);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(str) {
|
||||||
|
if (str === undefined || str === null) return "";
|
||||||
|
return String(str)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
$(function () {
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
$("#inviteFilter button").on("click", function () {
|
||||||
|
$("#inviteFilter button").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
inviteFilter = $(this).data("filter");
|
||||||
|
invitePage = 1;
|
||||||
|
loadInviteList();
|
||||||
|
});
|
||||||
|
$("#rebateFilter button").on("click", function () {
|
||||||
|
$("#rebateFilter button").removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
rebateFilter = $(this).data("filter");
|
||||||
|
rebatePage = 1;
|
||||||
|
loadRebateList();
|
||||||
|
});
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadPromoInfo();
|
||||||
|
loadPromoSummary();
|
||||||
|
loadInviteList();
|
||||||
|
loadRebateList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
<!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/distribution.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="topbar" id="navbar">
|
||||||
|
<div class="topbar__inner">
|
||||||
|
<a href="index.html" class="topbar__brand">
|
||||||
|
<img
|
||||||
|
src="../images/home-logo.png"
|
||||||
|
alt="彩先知"
|
||||||
|
class="topbar__logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="topbar__nav" id="navLotteryItems">
|
||||||
|
<!-- <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 Content -->
|
||||||
|
<main class="page-main">
|
||||||
|
<!-- Stats -->
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">下级总数</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="totalSubordinates">0</span><span class="unit">人</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">一级下级</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="levelOneCount">0</span><span class="unit">人</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">二级下级</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="levelTwoCount">0</span><span class="unit">人</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">分销收益</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
<span id="distIncome">0.00</span><span class="unit">元</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<div class="table-section">
|
||||||
|
<div class="table-section-title">
|
||||||
|
<i class="layui-icon layui-icon-group"></i> 下级用户列表
|
||||||
|
</div>
|
||||||
|
<table id="distTable" lay-filter="distTable" lay-even></table>
|
||||||
|
<div id="distPage"></div>
|
||||||
|
</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>
|
||||||
|
layui.use(["layer", "jquery", "table", "laypage"], function () {
|
||||||
|
var layer = layui.layer;
|
||||||
|
var $ = layui.$;
|
||||||
|
var table = layui.table;
|
||||||
|
var laypage = layui.laypage;
|
||||||
|
|
||||||
|
// Load page config
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
|
||||||
|
// Check login state for topbar
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
// Check auth and load data
|
||||||
|
CommonUtil.requireAuth(function () {
|
||||||
|
loadUserDetail();
|
||||||
|
loadDistList(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var token = CommonUtil.getToken();
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (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");
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadUserDetail() {
|
||||||
|
CommonUtil.getCurrentUserDetail(function (data) {
|
||||||
|
if (!data) return;
|
||||||
|
$("#totalSubordinates").text(data.totalSubordinates || 0);
|
||||||
|
$("#levelOneCount").text(data.levelOneCount || 0);
|
||||||
|
$("#levelTwoCount").text(data.levelTwoCount || 0);
|
||||||
|
$("#distIncome").text((data.distributionIncome || 0).toFixed(2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDistList(pageNum) {
|
||||||
|
currentPage = pageNum;
|
||||||
|
ApiClient.post(
|
||||||
|
"/api/web/distribution/getPageList",
|
||||||
|
{
|
||||||
|
pageNum: pageNum,
|
||||||
|
pageSize: pageSize,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: CommonUtil.authHeaders(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then(function (res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
renderTable(res.data.records || []);
|
||||||
|
renderPagination(res.data.total || 0);
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || "获取数据失败", { icon: 2 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
layer.msg("网络错误,请稍后重试", { icon: 2 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTable(records) {
|
||||||
|
if (records.length === 0) {
|
||||||
|
$("#distTable").replaceWith(
|
||||||
|
'<div class="empty-state"><i class="layui-icon layui-icon-group"></i><p>暂无下级用户</p></div>',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.render({
|
||||||
|
elem: "#distTable",
|
||||||
|
cols: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
field: "nickName",
|
||||||
|
title: "昵称",
|
||||||
|
width: 160,
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "phoneNumber",
|
||||||
|
title: "手机号",
|
||||||
|
width: 160,
|
||||||
|
align: "center",
|
||||||
|
templet: function (d) {
|
||||||
|
if (d.phoneNumber) {
|
||||||
|
return d.phoneNumber.replace(
|
||||||
|
/(\d{3})\d{4}(\d{4})/,
|
||||||
|
"$1****$2",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "--";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "level",
|
||||||
|
title: "层级",
|
||||||
|
width: 100,
|
||||||
|
align: "center",
|
||||||
|
templet: function (d) {
|
||||||
|
return d.level === 1
|
||||||
|
? '<span style="color:#102b6a;font-weight:600;">一级</span>'
|
||||||
|
: '<span style="color:#5b2c8e;font-weight:600;">二级</span>';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "createTime",
|
||||||
|
title: "注册时间",
|
||||||
|
width: 180,
|
||||||
|
align: "center",
|
||||||
|
templet: function (d) {
|
||||||
|
return d.createTime
|
||||||
|
? d.createTime.substring(0, 19).replace("T", " ")
|
||||||
|
: "--";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "totalRecharge",
|
||||||
|
title: "累计充值",
|
||||||
|
width: 130,
|
||||||
|
align: "center",
|
||||||
|
templet: function (d) {
|
||||||
|
return (
|
||||||
|
'<span style="color:#f15a22;font-weight:600;">' +
|
||||||
|
(d.totalRecharge || 0).toFixed(2) +
|
||||||
|
"</span>"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "distributionIncome",
|
||||||
|
title: "分销收益",
|
||||||
|
width: 130,
|
||||||
|
align: "center",
|
||||||
|
templet: function (d) {
|
||||||
|
return (
|
||||||
|
'<span style="color:#fdb933;font-weight:600;">' +
|
||||||
|
(d.distributionIncome || 0).toFixed(2) +
|
||||||
|
"</span>"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
data: records,
|
||||||
|
even: true,
|
||||||
|
skin: "line",
|
||||||
|
size: "lg",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(total) {
|
||||||
|
if (total <= pageSize) return;
|
||||||
|
laypage.render({
|
||||||
|
elem: "distPage",
|
||||||
|
count: total,
|
||||||
|
limit: pageSize,
|
||||||
|
curr: currentPage,
|
||||||
|
theme: "#102b6a",
|
||||||
|
jump: function (obj, first) {
|
||||||
|
if (!first) {
|
||||||
|
loadDistList(obj.curr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
<!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/static.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 Content -->
|
||||||
|
<main class="page-main">
|
||||||
|
<div class="policy-card">
|
||||||
|
<div class="policy-card-header">
|
||||||
|
<h1 id="articleTitle">隐私政策</h1>
|
||||||
|
<p>彩先知隐私政策说明</p>
|
||||||
|
</div>
|
||||||
|
<div class="policy-card-body" id="articleContent">
|
||||||
|
<h2>一、信息收集</h2>
|
||||||
|
<p>我们收集您主动提供的信息,包括但不限于:</p>
|
||||||
|
<ul>
|
||||||
|
<li>注册信息:手机号码、昵称、密码等;</li>
|
||||||
|
<li>身份信息:实名认证所需的姓名、身份证号码等;</li>
|
||||||
|
<li>交易信息:充值、提现等交易记录;</li>
|
||||||
|
<li>内容信息:您发布的文章、评论等用户生成内容;</li>
|
||||||
|
<li>设备信息:设备型号、操作系统版本、唯一设备标识符等;</li>
|
||||||
|
<li>日志信息:访问时间、访问页面、IP地址等。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>二、信息使用</h2>
|
||||||
|
<p>我们将收集的信息用于以下目的:</p>
|
||||||
|
<ul>
|
||||||
|
<li>提供、维护和改进我们的服务;</li>
|
||||||
|
<li>创建和管理您的账户;</li>
|
||||||
|
<li>处理交易和发送相关通知;</li>
|
||||||
|
<li>向您推送服务相关通知和营销信息(经您同意);</li>
|
||||||
|
<li>进行数据分析以改善用户体验;</li>
|
||||||
|
<li>遵守法律法规的要求。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>三、信息共享</h2>
|
||||||
|
<p>
|
||||||
|
我们不会将您的个人信息出售给任何第三方。在以下情况下,我们可能会共享您的信息:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>经您事先同意;</li>
|
||||||
|
<li>与关联公司共享:仅为本政策声明的目的;</li>
|
||||||
|
<li>与授权合作伙伴共享:仅为实现本政策中声明的目的;</li>
|
||||||
|
<li>应法律法规要求:依据法律法规或政府部门的强制性要求。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>四、信息存储</h2>
|
||||||
|
<p>
|
||||||
|
您的个人信息将存储在中华人民共和国境内。在您注销账户后,我们将在法律法规规定的期限内保留您的相关信息,超过保留期限后将对您的个人信息进行删除或匿名化处理。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>五、信息安全</h2>
|
||||||
|
<p>我们采取合理的安全措施保护您的个人信息,包括但不限于:</p>
|
||||||
|
<ul>
|
||||||
|
<li>使用加密技术保护数据传输安全;</li>
|
||||||
|
<li>对敏感信息进行加密存储;</li>
|
||||||
|
<li>建立严格的数据访问权限控制机制;</li>
|
||||||
|
<li>定期进行安全评估和漏洞修复。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>六、您的权利</h2>
|
||||||
|
<p>您对您的个人信息享有以下权利:</p>
|
||||||
|
<ul>
|
||||||
|
<li>访问权:您有权访问您的个人信息;</li>
|
||||||
|
<li>更正权:您有权更正不准确的个人信息;</li>
|
||||||
|
<li>删除权:在特定情况下,您有权要求删除您的个人信息;</li>
|
||||||
|
<li>撤回同意权:您有权撤回之前给予的同意;</li>
|
||||||
|
<li>注销权:您有权注销您的账户。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>七、未成年人保护</h2>
|
||||||
|
<p>
|
||||||
|
我们的产品和服务主要面向成年人。如果您是未满18周岁的未成年人,请在法定监护人的陪同下阅读本政策,并在取得监护人对本政策及使用我们服务的同意后使用我们的服务。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>八、隐私政策的更新</h2>
|
||||||
|
<p>
|
||||||
|
我们可能会不时更新本隐私政策。更新后的政策将在本页面上发布,并通过适当方式通知您。如您在政策更新后继续使用我们的服务,即表示您同意受修订后的政策约束。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>九、联系我们</h2>
|
||||||
|
<p>
|
||||||
|
如您对本隐私政策有任何疑问、意见或建议,请通过以下方式与我们联系:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>邮箱:support@caixianzhi.com</li>
|
||||||
|
<li>客服电话:400-XXX-XXXX</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="update-date">最后更新日期:2026年4月22日</div>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
// Load page config
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
loadAgreementDetail();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
var article = res.data;
|
||||||
|
if (article.title) {
|
||||||
|
$("#articleTitle").text(article.title);
|
||||||
|
}
|
||||||
|
$contentEl.html(article.content || "内容为空");
|
||||||
|
} else {
|
||||||
|
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">暂无隐私政策内容</p>');
|
||||||
|
}
|
||||||
|
}).catch(function () {
|
||||||
|
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">隐私政策加载失败</p>');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check login state for topbar
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var token = CommonUtil.getToken();
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (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");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
<!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/static.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 Content -->
|
||||||
|
<main class="page-main">
|
||||||
|
<div class="policy-card">
|
||||||
|
<div class="policy-card-header">
|
||||||
|
<h1 id="articleTitle">用户协议</h1>
|
||||||
|
<p>彩先知用户服务协议</p>
|
||||||
|
</div>
|
||||||
|
<div class="policy-card-body" id="articleContent">
|
||||||
|
<h2>一、协议的接受与修改</h2>
|
||||||
|
<p>
|
||||||
|
欢迎使用彩先知(以下简称"本平台")。在使用本平台服务之前,请您仔细阅读本用户协议(以下简称"本协议")。您一旦使用本平台服务,即视为您已充分理解并同意接受本协议的全部内容。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
本平台有权根据法律法规变化及业务发展需要,对本协议进行修改。修改后的协议将在本页面上公布,自公布之日起生效。如您不同意修改后的协议内容,您有权停止使用本平台服务。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>二、账户注册与管理</h2>
|
||||||
|
<p>
|
||||||
|
您在注册账户时,应提供真实、准确、完整的个人资料,并在资料发生变更时及时更新。
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
您应妥善保管账户信息和密码,因您的原因导致账户被盗用的,由您自行承担相关责任;
|
||||||
|
</li>
|
||||||
|
<li>您不得将账户出借、赠与、出租、转让或售卖给他人;</li>
|
||||||
|
<li>如发现账户被非法使用,您应立即通知本平台;</li>
|
||||||
|
<li>每个手机号码仅可注册一个账户。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>三、服务内容</h2>
|
||||||
|
<p>本平台提供的服务包括但不限于:</p>
|
||||||
|
<ul>
|
||||||
|
<li>彩票数据分析和预测信息展示;</li>
|
||||||
|
<li>专家预测文章发布与阅读;</li>
|
||||||
|
<li>分销推广及收益管理;</li>
|
||||||
|
<li>社区交流与互动功能;</li>
|
||||||
|
<li>其他本平台提供的相关服务。</li>
|
||||||
|
</ul>
|
||||||
|
<p>本平台有权根据运营需要,随时变更、中断或终止部分或全部服务。</p>
|
||||||
|
|
||||||
|
<h2>四、用户行为规范</h2>
|
||||||
|
<p>您在使用本平台服务时,应遵守以下规范:</p>
|
||||||
|
<ul>
|
||||||
|
<li>遵守中华人民共和国相关法律法规;</li>
|
||||||
|
<li>不得利用本平台从事任何违法违规活动;</li>
|
||||||
|
<li>不得发布虚假、诈骗、淫秽、暴力、恐怖或违反公序良俗的内容;</li>
|
||||||
|
<li>
|
||||||
|
不得恶意攻击本平台系统或网络,不得利用技术手段非法获取数据;
|
||||||
|
</li>
|
||||||
|
<li>不得冒充他人或伪造身份信息;</li>
|
||||||
|
<li>不得对其他用户进行骚扰、侮辱、威胁或其他侵害行为;</li>
|
||||||
|
<li>不得进行任何破坏或试图破坏网络安全的行为。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>五、内容规范</h2>
|
||||||
|
<p>您在本平台发布的所有内容,应确保:</p>
|
||||||
|
<ul>
|
||||||
|
<li>内容真实、合法,不侵犯任何第三方的合法权益;</li>
|
||||||
|
<li>预测分析仅供参考,不构成任何购买建议;</li>
|
||||||
|
<li>不得发布任何诱导他人进行非法赌博的内容;</li>
|
||||||
|
<li>本平台有权对违规内容进行删除,并对违规用户进行处罚。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>六、知识产权</h2>
|
||||||
|
<p>
|
||||||
|
本平台所有内容,包括但不限于文字、图片、音频、视频、软件、程序及页面设计等,均属于本平台的知识产权,受法律保护。未经本平台书面许可,任何人不得以任何形式使用。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
您在本平台发布的原创内容,您保留相应的知识产权。但您授予本平台在全球范围内免费的、非独家的使用许可,本平台有权使用、复制、修改、展示和分发您发布的内容。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>七、免责声明</h2>
|
||||||
|
<p>
|
||||||
|
本平台提供的所有预测分析信息仅供娱乐参考,不构成任何形式的投注建议或承诺。彩票开奖结果具有随机性,过往数据不代表未来表现。
|
||||||
|
</p>
|
||||||
|
<p>因以下原因导致的服务中断或损失,本平台不承担责任:</p>
|
||||||
|
<ul>
|
||||||
|
<li>不可抗力因素;</li>
|
||||||
|
<li>系统维护或升级;</li>
|
||||||
|
<li>网络故障或第三方服务故障;</li>
|
||||||
|
<li>用户自身原因导致的信息泄露或损失。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>八、交易与退款</h2>
|
||||||
|
<p>您在本平台进行的充值、购买等交易行为,应遵守以下规定:</p>
|
||||||
|
<ul>
|
||||||
|
<li>充值成功后,虚拟商品不支持退款;</li>
|
||||||
|
<li>因系统故障导致交易异常的,请联系客服处理;</li>
|
||||||
|
<li>提现申请将在审核通过后按规定时间到账;</li>
|
||||||
|
<li>如有疑问,请在交易完成后7日内联系客服。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>九、违约处理</h2>
|
||||||
|
<p>如您违反本协议的规定,本平台有权视情节轻重采取以下措施:</p>
|
||||||
|
<ol>
|
||||||
|
<li>警告并要求改正;</li>
|
||||||
|
<li>删除违规内容;</li>
|
||||||
|
<li>限制或暂停账户功能;</li>
|
||||||
|
<li>永久封禁账户;</li>
|
||||||
|
<li>追究法律责任。</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>十、协议的终止</h2>
|
||||||
|
<p>
|
||||||
|
您有权随时注销您的账户。账户注销后,本平台将在法律法规规定的期限内保留您的相关信息。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
如您严重违反本协议,本平台有权单方面终止向您提供服务,并永久封禁您的账户。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>十一、法律适用与争议解决</h2>
|
||||||
|
<p>
|
||||||
|
本协议的订立、执行和解释均适用中华人民共和国法律。因本协议引起的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向本平台所在地有管辖权的人民法院提起诉讼。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>十二、其他</h2>
|
||||||
|
<p>
|
||||||
|
本协议构成您与本平台之间关于使用本平台服务的完整协议,取代此前的任何口头或书面沟通。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
如本协议的任何条款被认定为无效或不可执行,该条款应在可执行的最大范围内执行,其余条款仍然有效。
|
||||||
|
</p>
|
||||||
|
<p>如您对本协议有任何疑问,请通过以下方式联系我们:</p>
|
||||||
|
<ul>
|
||||||
|
<li>邮箱:support@caixianzhi.com</li>
|
||||||
|
<li>客服电话:400-XXX-XXXX</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="update-date">最后更新日期:2026年4月22日</div>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
layui.use(["layer", "jquery"], function () {
|
||||||
|
var $ = layui.$;
|
||||||
|
|
||||||
|
// Load page config
|
||||||
|
CommonUtil.loadPageConfig({ ads: false, links: false });
|
||||||
|
loadAgreementDetail();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
var article = res.data;
|
||||||
|
if (article.title) {
|
||||||
|
$("#articleTitle").text(article.title);
|
||||||
|
}
|
||||||
|
$contentEl.html(article.content || "内容为空");
|
||||||
|
} else {
|
||||||
|
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">暂无协议内容</p>');
|
||||||
|
}
|
||||||
|
}).catch(function () {
|
||||||
|
$contentEl.html('<p style="text-align:center;color:var(--text-muted);padding:40px 0;">协议内容加载失败</p>');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check login state for topbar
|
||||||
|
checkLogin();
|
||||||
|
renderNav();
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
var token = CommonUtil.getToken();
|
||||||
|
if (token) {
|
||||||
|
$("#notLoggedInBox").hide();
|
||||||
|
$("#loggedInBox").css("display", "flex");
|
||||||
|
CommonUtil.getCurrentUserDetail(
|
||||||
|
function (data) {
|
||||||
|
if (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");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 242 B |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 820 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |