Files
pk10/App/Views/Web/follow_plan.php
T
li 4a94fe36cf feat: 重构代码架构 + 新增报表/跟单/输赢统计功能
- 拆分 HomeController → TransactionController, ReportWebController, FollowPlanController
- 新增 Service 层: TransactionService, ReportService, FollowPlanService
- pk10.php JS 抽离为 4 个独立文件 (sound/race/bet/poll)
- 前台新增报表查询页面 (/report) + 跟单计划页面 (/follow-plan)
- 后台新增跟单计划管理 + 用户输赢明细统计
- 封盘状态显示倒计时 (x:xx)
- 音效仅在开奖弹窗打开时播放
- 路由按模块分组整理
- autoload 支持 App\Services 命名空间
2026-03-27 18:41:06 +08:00

132 lines
6.3 KiB
PHP

<?php use App\Core\I18n; I18n::init(); $t = function($k,$p=[]){return I18n::t($k,$p);}; ?>
<!DOCTYPE html><html lang="<?=I18n::getLang()?>">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title><?=$t('follow_plan')?></title>
<link rel="stylesheet" href="/Static/css/app.css">
<style>
.page-header{display:flex;align-items:center;padding:12px 16px;background:#fff;border-bottom:1px solid #F0F0F0;position:sticky;top:0;z-index:10}
.page-header .back{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}
.page-header .title{flex:1;text-align:center;font-size:17px;font-weight:600;color:#333}
.page-header .balance{font-size:13px;color:#1E90FF;display:flex;align-items:center;gap:4px}
.game-select{background:#fff;padding:12px 16px;border-bottom:1px solid #F0F0F0}
.game-select select{width:100%;padding:8px 12px;border:1px solid #ddd;border-radius:8px;font-size:14px;color:#333;background:#F9F9F9}
.stats-cards{display:flex;gap:12px;padding:16px;background:#fff;margin-top:1px}
.stat-card{flex:1;background:linear-gradient(135deg,#E8F4FF,#D0E8FF);border-radius:12px;padding:16px;text-align:center}
.stat-card .label{font-size:12px;color:#1E90FF;margin-bottom:6px}
.stat-card .value{font-size:22px;font-weight:700;color:#333}
.plan-card{background:#fff;margin:8px 16px;border-radius:12px;padding:16px;box-shadow:0 2px 8px rgba(0,0,0,.06)}
.plan-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.plan-name{font-size:15px;font-weight:600;color:#333}
.plan-type-badge{padding:2px 10px;border-radius:12px;font-size:11px;font-weight:600;color:#fff;background:#1E90FF}
.plan-stats{display:flex;gap:16px;margin-bottom:12px}
.plan-stat{text-align:center;flex:1}
.plan-stat .ps-label{font-size:11px;color:#999;margin-bottom:2px}
.plan-stat .ps-value{font-size:16px;font-weight:700}
.plan-stat .ps-value.win{color:#4CAF50}
.plan-stat .ps-value.lose{color:#FF4444}
.plan-recent{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:12px}
.plan-dot{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:#fff}
.plan-dot.w{background:#4CAF50}
.plan-dot.l{background:#FF4444}
.plan-actions{display:flex;gap:8px}
.follow-btn{flex:1;padding:10px;border-radius:8px;text-align:center;font-size:14px;font-weight:600;cursor:pointer;transition:all .2s;border:none}
.follow-btn.active{background:#FF4444;color:#fff}
.follow-btn.inactive{background:linear-gradient(135deg,#1E90FF,#0066CC);color:#fff}
.follow-btn:active{transform:scale(.98)}
.empty-plans{text-align:center;padding:60px 20px}
.empty-plans .icon{font-size:48px;margin-bottom:16px;opacity:.3}
.empty-plans .text{font-size:14px;color:#999}
.plan-type-select{background:#fff;padding:12px 16px;border-bottom:1px solid #F0F0F0}
.type-tabs{display:flex;gap:8px;flex-wrap:wrap}
.type-tab{padding:6px 16px;border-radius:20px;font-size:13px;color:#666;background:#F0F0F0;cursor:pointer;border:none}
.type-tab.active{background:#1E90FF;color:#fff}
</style>
</head>
<body style="background:#F5F5F5;padding-bottom:20px">
<div class="page-header">
<a href="/profile" class="back"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></a>
<div class="title"><?=$t('follow_plan')?></div>
<div class="balance"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v12M8 10h8M8 14h8"/></svg> <?=number_format($user['balance']??0,2)?></div>
</div>
<div class="game-select">
<select>
<option><?=htmlspecialchars($game['name'] ?? $t('pk10_title'))?></option>
</select>
</div>
<div class="stats-cards">
<div class="stat-card">
<div class="label"><?=$t('total_win_rate')?></div>
<div class="value"><?=$summary['win_rate']?>%</div>
</div>
<div class="stat-card">
<div class="label"><?=$t('total_profit')?></div>
<div class="value" style="color:<?=$summary['profit']>=0?'#4CAF50':'#FF4444'?>"><?=$summary['profit']>=0?'+':''?><?=number_format($summary['profit'],2)?></div>
</div>
</div>
<?php if(empty($plans)): ?>
<div class="empty-plans">
<div class="icon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#ccc" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 3v18"/></svg>
</div>
<div class="text"><?=$t('no_follow_plan')?></div>
</div>
<?php else: ?>
<?php
$typeNames = ['bs'=>$t('big').'/'.$t('small'), 'oe'=>$t('odd').'/'.$t('even'), 'dt'=>$t('dragon').'/'.$t('tiger'), 'sum_bs'=>$t('sum_big').'/'.$t('sum_small')];
foreach($plans as $plan):
$isFollowing = isset($userFollows[$plan['id']]);
?>
<div class="plan-card">
<div class="plan-header">
<div class="plan-name"><?=htmlspecialchars($plan['name'])?></div>
<span class="plan-type-badge"><?=$typeNames[$plan['plan_type']]??$plan['plan_type']?></span>
</div>
<div class="plan-stats">
<div class="plan-stat">
<div class="ps-label"><?=$t('total_win_rate')?></div>
<div class="ps-value <?=$plan['win_rate']>=50?'win':'lose'?>"><?=$plan['win_rate']?>%</div>
</div>
<div class="plan-stat">
<div class="ps-label"><?=$t('bet_amount')?></div>
<div class="ps-value"><?=number_format($plan['bet_amount'],0)?></div>
</div>
<div class="plan-stat">
<div class="ps-label">总期数</div>
<div class="ps-value"><?=$plan['total_records']?></div>
</div>
</div>
<?php if(!empty($plan['recent'])): ?>
<div class="plan-recent">
<?php foreach(array_reverse($plan['recent']) as $rec): ?>
<div class="plan-dot <?=$rec['is_win']?'w':'l'?>"><?=$rec['is_win']?'W':'L'?></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="plan-actions">
<button class="follow-btn <?=$isFollowing?'active':'inactive'?>" onclick="toggleFollow(<?=$plan['id']?>,this)">
<?=$isFollowing?'取消跟单':'开始跟单'?>
</button>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
<script>
function toggleFollow(planId, btn) {
fetch('/api/follow-plan/toggle', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({plan_id: planId})
}).then(function(r) { return r.json(); }).then(function(d) {
if (d.success) location.reload();
else alert(d.message || '操作失败');
});
}
</script>
</body></html>