Files
pk10/App/Services/FollowPlanService.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

246 lines
7.7 KiB
PHP

<?php
namespace App\Services;
use Db\Database;
class FollowPlanService {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
/**
* 获取所有启用的跟单计划(前台展示)
*/
public function getActivePlans(int $gameId = 0): array
{
$where = ['status' => 1];
if ($gameId > 0) $where['game_id'] = $gameId;
$where['ORDER'] = ['id' => 'ASC'];
$plans = $this->db->select('follow_plans', '*', $where);
foreach ($plans as &$plan) {
$stats = $this->getPlanStats($plan['id']);
$plan['total_records'] = $stats['total'];
$plan['win_count'] = $stats['wins'];
$plan['win_rate'] = $stats['total'] > 0 ? round($stats['wins'] / $stats['total'] * 100, 1) : 0;
// 最近 10 期记录
$plan['recent'] = $this->db->select('follow_plan_records', '*', [
'plan_id' => $plan['id'],
'is_win[!]' => null,
'ORDER' => ['id' => 'DESC'],
'LIMIT' => 10
]);
}
unset($plan);
return $plans;
}
/**
* 获取计划统计
*/
public function getPlanStats(int $planId): array
{
$total = $this->db->count('follow_plan_records', [
'plan_id' => $planId,
'is_win[!]' => null
]);
$wins = $this->db->count('follow_plan_records', [
'plan_id' => $planId,
'is_win' => 1
]);
return ['total' => $total, 'wins' => $wins];
}
/**
* 获取用户的跟单状态
*/
public function getUserFollowStatus(int $userId): array
{
$rows = $this->db->select('user_follow_plans', '*', [
'user_id' => $userId,
'is_active' => 1
]);
$result = [];
foreach ($rows as $r) {
$result[$r['plan_id']] = $r;
}
return $result;
}
/**
* 用户开始/停止跟单
*/
public function toggleFollow(int $userId, int $planId): array
{
$existing = $this->db->get('user_follow_plans', '*', [
'user_id' => $userId,
'plan_id' => $planId
]);
if ($existing) {
$newStatus = $existing['is_active'] ? 0 : 1;
$this->db->update('user_follow_plans', ['is_active' => $newStatus], [
'id' => $existing['id']
]);
return ['success' => true, 'active' => $newStatus];
}
// 新建
$plan = $this->db->get('follow_plans', '*', ['id' => $planId, 'status' => 1]);
if (!$plan) {
return ['success' => false, 'message' => '计划不存在或已禁用'];
}
$this->db->insert('user_follow_plans', [
'user_id' => $userId,
'plan_id' => $planId,
'is_active' => 1,
]);
return ['success' => true, 'active' => 1];
}
/**
* 获取用户跟单汇总(总胜率、总盈亏)
*/
public function getUserSummary(int $userId): array
{
$pdo = $this->db->medoo->pdo;
$totalWinRate = 0;
$totalProfit = 0;
try {
$stmt = $pdo->prepare("
SELECT SUM(total_bets) as bets, SUM(total_wins) as wins, SUM(total_profit) as profit
FROM user_follow_plans WHERE user_id = ?
");
$stmt->execute([$userId]);
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
$bets = intval($row['bets'] ?? 0);
$wins = intval($row['wins'] ?? 0);
$totalWinRate = $bets > 0 ? round($wins / $bets * 100, 1) : 0;
$totalProfit = floatval($row['profit'] ?? 0);
} catch (\Exception $e) {}
return ['win_rate' => $totalWinRate, 'profit' => $totalProfit];
}
// ===== 后台管理 =====
/**
* 获取所有计划(后台)
*/
public function getAllPlans(): array
{
$plans = $this->db->select('follow_plans', '*', ['ORDER' => ['id' => 'DESC']]);
foreach ($plans as &$plan) {
$stats = $this->getPlanStats($plan['id']);
$plan['total_records'] = $stats['total'];
$plan['win_count'] = $stats['wins'];
$plan['win_rate'] = $stats['total'] > 0 ? round($stats['wins'] / $stats['total'] * 100, 1) : 0;
$plan['follower_count'] = $this->db->count('user_follow_plans', [
'plan_id' => $plan['id'], 'is_active' => 1
]);
}
unset($plan);
return $plans;
}
/**
* 创建/更新计划
*/
public function savePlan(array $data): array
{
$fields = [
'game_id' => intval($data['game_id'] ?? 1),
'name' => trim($data['name'] ?? ''),
'plan_type' => trim($data['plan_type'] ?? 'bs'),
'target_rank' => intval($data['target_rank'] ?? 1),
'strategy' => trim($data['strategy'] ?? 'follow'),
'bet_amount' => floatval($data['bet_amount'] ?? 100),
'status' => intval($data['status'] ?? 1),
];
if (empty($fields['name'])) {
return ['success' => false, 'message' => '计划名称不能为空'];
}
$id = intval($data['id'] ?? 0);
if ($id > 0) {
$this->db->update('follow_plans', $fields, ['id' => $id]);
} else {
$fields['created_by'] = intval($data['created_by'] ?? 0);
$this->db->insert('follow_plans', $fields);
$id = intval($this->db->id());
}
return ['success' => true, 'id' => $id];
}
/**
* 删除计划
*/
public function deletePlan(int $planId): array
{
$this->db->delete('follow_plan_records', ['plan_id' => $planId]);
$this->db->delete('user_follow_plans', ['plan_id' => $planId]);
$this->db->delete('follow_plans', ['id' => $planId]);
return ['success' => true];
}
/**
* 添加计划推荐记录(由 cron 或后台手动触发)
*/
public function addRecord(int $planId, int $periodId, string $periodNumber, string $recommendValue): array
{
$exists = $this->db->get('follow_plan_records', 'id', [
'plan_id' => $planId, 'period_id' => $periodId
]);
if ($exists) {
return ['success' => false, 'message' => '该期已有推荐记录'];
}
$this->db->insert('follow_plan_records', [
'plan_id' => $planId,
'period_id' => $periodId,
'period_number' => $periodNumber,
'recommend_value' => $recommendValue,
]);
return ['success' => true, 'id' => intval($this->db->id())];
}
/**
* 结算推荐记录(开奖后调用)
*/
public function settleRecord(int $recordId, string $resultValue, bool $isWin): void
{
$this->db->update('follow_plan_records', [
'result_value' => $resultValue,
'is_win' => $isWin ? 1 : 0,
], ['id' => $recordId]);
// 更新所有跟了这个计划的用户统计
$record = $this->db->get('follow_plan_records', '*', ['id' => $recordId]);
if (!$record) return;
$plan = $this->db->get('follow_plans', '*', ['id' => $record['plan_id']]);
if (!$plan) return;
$betAmount = floatval($plan['bet_amount']);
$profit = $isWin ? $betAmount * 0.95 : -$betAmount; // 简化盈亏计算
$followers = $this->db->select('user_follow_plans', '*', [
'plan_id' => $record['plan_id'], 'is_active' => 1
]);
foreach ($followers as $f) {
$this->db->update('user_follow_plans', [
'total_bets[+]' => 1,
'total_wins[+]' => $isWin ? 1 : 0,
'total_profit[+]' => $profit,
], ['id' => $f['id']]);
}
}
}