diff --git a/OshimaServers/Service/CSBettingService.cs b/OshimaServers/Service/CSBettingService.cs index 7875560..14a1ee0 100644 --- a/OshimaServers/Service/CSBettingService.cs +++ b/OshimaServers/Service/CSBettingService.cs @@ -20,8 +20,8 @@ namespace Oshima.FunGame.WebAPI.Services sql.ExecuteDataSet("SELECT COUNT(*) FROM csbetting_events"); int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0; int totalPages = (int)Math.Ceiling(total / (double)pageSize); - if (page < 1) page = 1; if (page > totalPages) page = totalPages; + if (page < 1) page = 1; if (total == 0) return ("暂无赛事。", 1); @@ -41,7 +41,7 @@ namespace Oshima.FunGame.WebAPI.Services return ("暂无赛事。", 1); StringBuilder sb = new(); - sb.AppendLine($"🏆 赛事列表(第 {page}/{totalPages} 页)"); + sb.AppendLine($"🏆 赛事列表{(totalPages > 1 ? $"(第 {page}/{totalPages} 页)" : "")}"); foreach (DataRow row in sql.DataSet.Tables[0].Rows) { int id = Convert.ToInt32(row["id"]); @@ -82,10 +82,10 @@ namespace Oshima.FunGame.WebAPI.Services sql.ExecuteDataSet("SELECT COUNT(*) FROM csbetting_matches WHERE event_id = @eid"); int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0; int totalPages = (int)Math.Ceiling(total / (double)pageSize); - if (page < 1) page = 1; if (page > totalPages) page = totalPages; + if (page < 1) page = 1; - header.AppendLine($"比赛列表(第 {page}/{totalPages} 页):"); + header.AppendLine($"比赛列表{(totalPages > 1 ? $"(第 {page}/{totalPages} 页)" : "")}:"); // 分页查询比赛 int offset = (page - 1) * pageSize; @@ -347,39 +347,43 @@ namespace Oshima.FunGame.WebAPI.Services UpdateStatuses(sql); + bool paged = true; sql.Parameters["@uid"] = uid; string matchFilter = ""; if (mid > 0) { sql.Parameters["@mid"] = mid; matchFilter = " AND br.match_id = @mid"; + paged = false; } - // 总数查询:不同比赛的数量 - sql.ExecuteDataSet($@" + int totalPages = 0; + if (paged) + { + // 总数查询:不同比赛的数量 + sql.ExecuteDataSet($@" SELECT COUNT(DISTINCT br.match_id) FROM csbetting_bet_records br JOIN csbetting_matches m ON br.match_id = m.id WHERE br.user_id = @uid {matchFilter}"); - int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0; - int totalPages = (int)Math.Ceiling(total / (double)pageSize); - if (page < 1) page = 1; - if (page > totalPages) page = totalPages; - if (total == 0) - return ("你还没有任何竞猜记录。", 1); - - sql.Parameters["@uid"] = uid; - matchFilter = ""; - if (mid > 0) - { - sql.Parameters["@mid"] = mid; - matchFilter = " AND br.match_id = @mid"; + int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0; + totalPages = (int)Math.Ceiling(total / (double)pageSize); + if (page > totalPages) page = totalPages; + if (page < 1) page = 1; + if (total == 0) + return ("你还没有任何竞猜记录。", 1); + } + + // 构建分页SQL片段 + string limitClause = ""; + if (paged) + { + int offset = (page - 1) * pageSize; + limitClause = $" LIMIT {pageSize} OFFSET {offset}"; } - int offset = (page - 1) * pageSize; - sql.Parameters["@page_size"] = pageSize; - sql.Parameters["@offset"] = offset; // 分页聚合查询 + sql.Parameters["@uid"] = uid; sql.ExecuteDataSet($@" SELECT br.match_id, m.team1_name, m.team2_name, m.status AS match_status, m.start_time, GROUP_CONCAT(CONCAT(br.option_type, ':', br.option_value, ':', br.amount) ORDER BY br.id SEPARATOR '|') AS details, @@ -397,13 +401,13 @@ namespace Oshima.FunGame.WebAPI.Services MIN(br.is_settled) ASC, CASE WHEN MIN(br.is_settled) = 0 THEN MIN(m.start_time) END ASC, CASE WHEN MIN(br.is_settled) = 1 THEN MIN(m.start_time) END DESC - LIMIT {pageSize} OFFSET {offset}"); + {limitClause}"); if (!sql.Success || sql.DataSet.Tables[0].Rows.Count == 0) return ("你还没有任何竞猜记录。", 1); StringBuilder sb = new(); - sb.AppendLine($"我的竞猜(第 {page}/{totalPages} 页)"); + sb.AppendLine($"我的竞猜{(paged && totalPages > 1 ? $"(第 {page}/{totalPages} 页)" : "")}"); foreach (DataRow row in sql.DataSet.Tables[0].Rows) { int matchId = Convert.ToInt32(row["match_id"]); diff --git a/OshimaWebAPI/Constant/CSBetting.sql b/OshimaWebAPI/Constant/CSBetting.sql new file mode 100644 index 0000000..9bdf28d --- /dev/null +++ b/OshimaWebAPI/Constant/CSBetting.sql @@ -0,0 +1,62 @@ +-- 导出 表 fungame.csbetting_bet_records 结构 +CREATE TABLE IF NOT EXISTS `csbetting_bet_records` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '投注记录ID', + `user_id` bigint unsigned NOT NULL COMMENT '用户UID', + `match_id` int unsigned NOT NULL COMMENT '比赛ID', + `option_type` tinyint NOT NULL COMMENT '投注类型:1=队伍1胜,2=队伍2胜,3=精确比分,4=赛事MVP', + `option_value` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '投注值,如 team1, team2, 16:14, 1001', + `amount` bigint unsigned NOT NULL COMMENT '投注金币数', + `bet_time` datetime NOT NULL COMMENT '投注时间', + `is_settled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已结算:0=未结算,1=已结算', + `payout` bigint unsigned DEFAULT NULL COMMENT '派彩金额(含本金),NULL表示未结算', + `is_claimed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已领取派彩:0=未领取,1=已领取', + `result_note` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '结算备注,如 中奖、未中奖', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_match_id` (`match_id`), + KEY `idx_is_settled` (`is_settled`), + KEY `idx_bet_time` (`bet_time`), + CONSTRAINT `fk_bet_match` FOREIGN KEY (`match_id`) REFERENCES `csbetting_matches` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CS竞猜投注记录表'; + +-- 导出 表 fungame.csbetting_events 结构 +CREATE TABLE IF NOT EXISTS `csbetting_events` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '赛事ID', + `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '赛事名称', + `status` tinyint NOT NULL DEFAULT '0' COMMENT '赛事状态:0=未开始,1=进行中,2=已结束', + `start_time` datetime NOT NULL COMMENT '赛事开始时间', + `end_time` datetime NOT NULL COMMENT '赛事结束时间', + `mvp_candidates` json DEFAULT NULL COMMENT 'MVP候选人UID列表,如 [1001, 1002]', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_status` (`status`), + KEY `idx_start_time` (`start_time`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CS赛事表'; + +-- 导出 表 fungame.csbetting_matches 结构 +CREATE TABLE IF NOT EXISTS `csbetting_matches` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '比赛ID', + `event_id` int unsigned NOT NULL COMMENT '所属赛事ID', + `stage` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '比赛阶段,如Group Stage, Quarter-final, Semi-final, Final', + `team1_name` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '队伍1名称', + `team1_logo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '队伍1标志URL', + `team2_name` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '队伍2名称', + `team2_logo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '队伍2标志URL', + `status` tinyint NOT NULL DEFAULT '0' COMMENT '比赛状态:0=未开始,1=进行中,2=已结束', + `start_time` datetime NOT NULL COMMENT '比赛开始时间', + `bet_deadline` datetime NOT NULL COMMENT '投注截止时间', + `result` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '比赛结果,如 16:14 或 2:1', + `winner` tinyint DEFAULT NULL COMMENT '获胜方:1=队伍1,2=队伍2,NULL=未定', + `available_options` json NOT NULL COMMENT '可用投注选项,如 ["team1_win","team2_win","score"]', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_event_id` (`event_id`), + KEY `idx_status` (`status`), + KEY `idx_bet_deadline` (`bet_deadline`), + KEY `idx_start_time` (`start_time`), + CONSTRAINT `fk_matches_event` FOREIGN KEY (`event_id`) REFERENCES `csbetting_events` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CS比赛表'; diff --git a/OshimaWebAPI/Controllers/CSBettingController.cs b/OshimaWebAPI/Controllers/CSBettingController.cs index d5acdf3..4d6c89c 100644 --- a/OshimaWebAPI/Controllers/CSBettingController.cs +++ b/OshimaWebAPI/Controllers/CSBettingController.cs @@ -29,7 +29,8 @@ namespace Oshima.FunGame.WebAPI.Controllers public BotReply GetEventsOverview([FromQuery] int page = 1, [FromQuery] int pageSize = 10) { var (content, totalPages) = CSBettingService.GetEventsOverview(page, pageSize); - KeyboardMessage kb = new KeyboardMessage().AddPaginationRow("赛事列表 ", page, totalPages); + KeyboardMessage kb = new(); + if (totalPages > 1) kb = new KeyboardMessage().AddPaginationRow("赛事列表 ", page, totalPages); return new BotReply { Markdown = new MarkdownMessage { Content = content }, Keyboard = kb }; } @@ -38,7 +39,8 @@ namespace Oshima.FunGame.WebAPI.Controllers public BotReply GetEventDetail(int eventId, [FromQuery] int page = 1, [FromQuery] int pageSize = 10) { var (content, totalPages) = CSBettingService.GetEventDetail(eventId, page, pageSize); - KeyboardMessage kb = new KeyboardMessage().AddPaginationRow($"赛事详情 {eventId} ", page, totalPages); + KeyboardMessage kb = new(); + if (totalPages > 1) kb = new KeyboardMessage().AddPaginationRow($"赛事详情 {eventId} ", page, totalPages); return new BotReply { Markdown = new MarkdownMessage { Content = content }, Keyboard = kb }; } @@ -54,7 +56,8 @@ namespace Oshima.FunGame.WebAPI.Controllers public BotReply GetMyBets(long uid, [FromQuery] int page = 1, [FromQuery] int pageSize = 10) { var (content, totalPages) = CSBettingService.GetMyBets(uid, -1, page, pageSize); - KeyboardMessage kb = new KeyboardMessage().AddPaginationRow("我的竞猜 ", page, totalPages); + KeyboardMessage kb = new(); + if (totalPages > 1) kb = new KeyboardMessage().AddPaginationRow("我的竞猜 ", page, totalPages); return new BotReply { Markdown = new MarkdownMessage { Content = content }, Keyboard = kb }; }