mirror of
https://github.com/oshima-studios/OshimaGameModule.git
synced 2026-06-04 19:42:13 +00:00
改进
This commit is contained in:
parent
dd46e85606
commit
a5d91d6fc5
@ -1,19 +1,21 @@
|
||||
using System.Data;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Milimoe.FunGame.Core.Api.Transmittal;
|
||||
using Milimoe.FunGame.Core.Api.Utility;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
using Oshima.FunGame.OshimaServers.Model;
|
||||
|
||||
namespace Oshima.FunGame.WebAPI.Services
|
||||
{
|
||||
public class CSBettingSQLService
|
||||
public class CSBettingService
|
||||
{
|
||||
public static string GetEventsOverview()
|
||||
{
|
||||
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
|
||||
if (sql != null)
|
||||
{
|
||||
UpdateStatuses(sql);
|
||||
|
||||
sql.ExecuteDataSet("SELECT id, name, status, start_time FROM csbetting_events ORDER BY start_time DESC");
|
||||
if (!sql.Success || sql.DataSet.Tables.Count == 0) return "暂无赛事。";
|
||||
StringBuilder sb = new();
|
||||
@ -35,6 +37,8 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
|
||||
if (sql != null)
|
||||
{
|
||||
UpdateStatuses(sql);
|
||||
|
||||
sql.Parameters["@id"] = eventId;
|
||||
sql.ExecuteDataSet("SELECT * FROM csbetting_events WHERE id = @id");
|
||||
if (!sql.Success || sql == null || sql.DataSet.Tables[0].Rows.Count == 0) return "赛事不存在。";
|
||||
@ -66,7 +70,7 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
string mStatusStr = mstatus switch { 0 => "未开始", 1 => "进行中", 2 => "已结束", _ => "未知" };
|
||||
string matchLabel = $"{t1} vs {t2}";
|
||||
string clickableMatch = matchLabel.CreateCmdInput($"比赛详情 {mid}");
|
||||
sb.AppendLine($" [{mid}] {(stage != "" ? $"{stage} - " : "")} {clickableMatch} (状态:{mStatusStr}, 截止:{deadline:MM-dd HH:mm})");
|
||||
sb.AppendLine($" [{mid}] {(stage != "" ? $"{stage} " : "")} {clickableMatch} (状态:{mStatusStr}, 截止:{deadline:MM-dd HH:mm})");
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
@ -74,11 +78,14 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
return "数据库连接失败。";
|
||||
}
|
||||
|
||||
public static string GetMatchDetail(int matchId)
|
||||
public static string GetMatchDetail(int matchId, out int status)
|
||||
{
|
||||
status = 0;
|
||||
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
|
||||
if (sql != null)
|
||||
{
|
||||
UpdateStatuses(sql);
|
||||
|
||||
sql.Parameters["@mid"] = matchId;
|
||||
sql.ExecuteDataSet("SELECT * FROM csbetting_matches WHERE id = @mid");
|
||||
if (!sql.Success || sql.DataSet.Tables[0].Rows.Count == 0) return "比赛不存在。";
|
||||
@ -86,11 +93,13 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
long eventId = Convert.ToInt64(row["event_id"]);
|
||||
string t1 = row["team1_name"].ToString() ?? "";
|
||||
string t2 = row["team2_name"].ToString() ?? "";
|
||||
int status = Convert.ToInt32(row["status"]);
|
||||
status = Convert.ToInt32(row["status"]);
|
||||
DateTime start = Convert.ToDateTime(row["start_time"]);
|
||||
DateTime deadline = Convert.ToDateTime(row["bet_deadline"]);
|
||||
string stage = row["stage"].ToString() ?? "";
|
||||
string available = row["available_options"]?.ToString() ?? "[]";
|
||||
string result = row["result"] != DBNull.Value ? row["result"].ToString() ?? "" : "";
|
||||
long winner = row["winner"] != DBNull.Value ? Convert.ToInt64(row["winner"]) : 0;
|
||||
|
||||
string eventName = "";
|
||||
sql.Parameters["@eid"] = eventId;
|
||||
@ -113,12 +122,22 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
sb.AppendLine($"开赛:{start:yyyy/MM/dd HH:mm}");
|
||||
sb.AppendLine($"竞猜截止:{deadline:yyyy/MM/dd HH:mm}");
|
||||
sb.AppendLine($"状态:{statusStr}");
|
||||
sb.AppendLine($"可用选项:");
|
||||
if (available.Contains("team1_win")) sb.AppendLine($" - {t1}胜 (x 2.5)");
|
||||
if (available.Contains("team2_win")) sb.AppendLine($" - {t2}胜 (x 2.5)");
|
||||
if (available.Contains("score")) sb.AppendLine($" - 精确比分 (x 3.5)");
|
||||
if (available.Contains("mvp")) sb.AppendLine($" - 赛事MVP (x 3.5)");
|
||||
return sb.ToString();
|
||||
if (status == 0)
|
||||
{
|
||||
sb.AppendLine($"可用选项:");
|
||||
if (available.Contains("team1_win")) sb.AppendLine($" - {t1}胜 (x 2.5)");
|
||||
if (available.Contains("team2_win")) sb.AppendLine($" - {t2}胜 (x 2.5)");
|
||||
if (available.Contains("score")) sb.AppendLine($" - 精确比分 (x 3.5)");
|
||||
if (available.Contains("mvp")) sb.AppendLine($" - 赛事MVP (x 3.5)");
|
||||
}
|
||||
else if (status == 2)
|
||||
{
|
||||
string winnerName = winner switch { 1 => t1, 2 => t2, 3 => result, _ => "待定" };
|
||||
sb.AppendLine($"胜者:{winnerName}");
|
||||
if (winner != 3) sb.AppendLine($"结果:{result}");
|
||||
}
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
return "数据库连接失败。";
|
||||
}
|
||||
@ -142,7 +161,24 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
DateTime deadline = Convert.ToDateTime(row["bet_deadline"]);
|
||||
if (status != 0 || DateTime.Now > deadline)
|
||||
{
|
||||
error = "当前比赛已截止或非投注期。";
|
||||
error = "当前比赛已结束或非投注期。";
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- 单场比赛投注上限检查 ---
|
||||
long alreadyBet = 0;
|
||||
long totalBet = amount;
|
||||
sql.Parameters["@uid"] = uid;
|
||||
sql.Parameters["@mid"] = matchId;
|
||||
sql.ExecuteDataSet("SELECT COALESCE(SUM(amount), 0) AS total FROM csbetting_bet_records WHERE user_id = @uid AND match_id = @mid");
|
||||
if (sql.Success && sql.DataSet.Tables[0].Rows.Count > 0)
|
||||
{
|
||||
alreadyBet = Convert.ToInt64(sql.DataSet.Tables[0].Rows[0]["total"] ?? 0L);
|
||||
totalBet += alreadyBet;
|
||||
}
|
||||
if (totalBet > 5000)
|
||||
{
|
||||
error = $"本场比赛你的投注总额不能超过 5000 {General.GameplayEquilibriumConstant.InGameCurrency}(已投 {alreadyBet})。";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -193,19 +229,26 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
|
||||
if (sql != null)
|
||||
{
|
||||
UpdateStatuses(sql);
|
||||
|
||||
sql.Parameters["@mid"] = matchId;
|
||||
sql.ExecuteDataSet("SELECT * FROM csbetting_matches WHERE id = @mid");
|
||||
if (!sql.Success || sql.DataSet.Tables[0].Rows.Count == 0)
|
||||
return "比赛不存在。";
|
||||
DataRow row = sql.DataSet.Tables[0].Rows[0];
|
||||
string available = row["available_options"]?.ToString() ?? "[]";
|
||||
bool isMvp = available.Contains("mvp", StringComparison.CurrentCultureIgnoreCase);
|
||||
int status = Convert.ToInt32(row["status"]);
|
||||
if (status == 2)
|
||||
return "比赛已结算。";
|
||||
|
||||
int winTeam;
|
||||
if (winner == "team1") winTeam = 1;
|
||||
else if (winner == "team2") winTeam = 2;
|
||||
else return "请指定获胜方为 team1 或 team2。";
|
||||
int winTeam = 3;
|
||||
if (!isMvp)
|
||||
{
|
||||
if (winner == "team1") winTeam = 1;
|
||||
else if (winner == "team2") winTeam = 2;
|
||||
else return "请指定获胜方为 team1 或 team2。MVP 赛事获胜方请直接指定选手 ID。";
|
||||
}
|
||||
|
||||
// 更新比赛结果
|
||||
sql.Parameters["@res"] = result;
|
||||
@ -228,7 +271,8 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
bool win = false;
|
||||
if (otype == 1 && winTeam == 1) win = true;
|
||||
else if (otype == 2 && winTeam == 2) win = true;
|
||||
else if (otype == 3 && ovalue == result) win = true;
|
||||
else if (otype == 3 && ovalue.Replace(":", ":").Equals(result, StringComparison.CurrentCultureIgnoreCase)) win = true;
|
||||
else if (otype == 4 && ovalue.Equals(result, StringComparison.CurrentCultureIgnoreCase)) win = true;
|
||||
|
||||
long payout = 0;
|
||||
string note = "未中奖";
|
||||
@ -249,46 +293,127 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
return "数据库连接失败。";
|
||||
}
|
||||
|
||||
public static string GetMyBets(long uid)
|
||||
public static string GetMyBets(long uid, long mid = -1)
|
||||
{
|
||||
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
|
||||
if (sql != null)
|
||||
{
|
||||
UpdateStatuses(sql);
|
||||
|
||||
sql.Parameters["@uid"] = uid;
|
||||
sql.ExecuteDataSet(@"
|
||||
SELECT br.id, br.match_id, br.option_type, br.option_value, br.amount, br.bet_time,
|
||||
br.is_settled, br.payout, br.is_claimed, br.result_note,
|
||||
m.team1_name, m.team2_name
|
||||
FROM csbetting_bet_records br
|
||||
JOIN csbetting_matches m ON br.match_id = m.id
|
||||
WHERE br.user_id = @uid
|
||||
ORDER BY br.bet_time DESC");
|
||||
string matchFilter = "";
|
||||
if (mid > 0)
|
||||
{
|
||||
sql.Parameters["@mid"] = mid;
|
||||
matchFilter = " AND br.match_id = @mid";
|
||||
}
|
||||
sql.ExecuteDataSet($@"SELECT br.match_id, m.team1_name, m.team2_name, m.status AS match_status,
|
||||
GROUP_CONCAT(CONCAT(br.option_type, ':', br.option_value, ':', br.amount) ORDER BY br.id SEPARATOR '|') AS details,
|
||||
SUM(br.amount) AS total_amount,
|
||||
MIN(br.is_settled) AS all_settled,
|
||||
SUM(CASE WHEN br.is_settled = 1 AND br.payout > 0 AND br.is_claimed = 1 THEN 1 ELSE 0 END) AS claimed_count,
|
||||
SUM(CASE WHEN br.is_settled = 1 AND br.payout > 0 AND br.is_claimed = 0 THEN 1 ELSE 0 END) AS unclaimed_count,
|
||||
SUM(CASE WHEN br.is_settled = 1 AND br.payout = 0 THEN 1 ELSE 0 END) AS lost_count,
|
||||
SUM(CASE WHEN br.is_settled = 1 THEN br.payout ELSE 0 END) AS total_payout
|
||||
FROM csbetting_bet_records br
|
||||
JOIN csbetting_matches m ON br.match_id = m.id
|
||||
WHERE br.user_id = @uid {matchFilter}
|
||||
GROUP BY br.match_id, m.team1_name, m.team2_name, m.status
|
||||
ORDER BY MAX(br.bet_time) DESC");
|
||||
if (!sql.Success || sql.DataSet.Tables[0].Rows.Count == 0) return "你还没有任何竞猜记录。";
|
||||
|
||||
StringBuilder sb = new();
|
||||
foreach (DataRow row in sql.DataSet.Tables[0].Rows)
|
||||
{
|
||||
long bid = Convert.ToInt64(row["id"]);
|
||||
long mid = Convert.ToInt64(row["match_id"]);
|
||||
int matchId = Convert.ToInt32(row["match_id"]);
|
||||
string t1 = row["team1_name"].ToString() ?? "";
|
||||
string t2 = row["team2_name"].ToString() ?? "";
|
||||
int otype = Convert.ToInt32(row["option_type"]);
|
||||
string ovalue = row["option_value"].ToString() ?? "";
|
||||
long amt = Convert.ToInt64(row["amount"]);
|
||||
bool settled = Convert.ToBoolean(row["is_settled"]);
|
||||
long? payout = row["payout"] as long?;
|
||||
bool claimed = Convert.ToBoolean(row["is_claimed"]);
|
||||
int matchStatus = Convert.ToInt32(row["match_status"]);
|
||||
long totalAmount = Convert.ToInt64(row["total_amount"]);
|
||||
long totalPayout = Convert.ToInt64(row["total_payout"]);
|
||||
int allSettled = Convert.ToInt32(row["all_settled"]);
|
||||
int claimedCount = Convert.ToInt32(row["claimed_count"]);
|
||||
int unclaimedCount = Convert.ToInt32(row["unclaimed_count"]);
|
||||
int lostCount = Convert.ToInt32(row["lost_count"]);
|
||||
|
||||
string optStr = otype switch { 1 => $"{t1}胜", 2 => $"{t2}胜", 3 => $"比分 {ovalue}", 4 => $"MVP {ovalue}", _ => ovalue };
|
||||
string statusStr = settled ? (payout > 0 ? (claimed ? $"+{payout} (已领)" : $"+{payout} (可领)") : "未中奖") : "进行中";
|
||||
string matchLabel = $"{t1} vs {t2}";
|
||||
string clickableMatch = matchLabel.CreateCmdInput($"比赛详情 {mid}");
|
||||
sb.AppendLine($"[{bid}] {clickableMatch} | 选项:{optStr} | 投注:{amt} | 状态:{statusStr}");
|
||||
// 解析投注详情
|
||||
string detailsStr = row["details"].ToString() ?? "";
|
||||
string[]?parts = detailsStr.Split('|');
|
||||
List<string> summary = [];
|
||||
foreach (string part in parts)
|
||||
{
|
||||
string[] items = part.Split(':');
|
||||
if (items.Length >= 3)
|
||||
{
|
||||
int otype = int.Parse(items[0]);
|
||||
string ovalue = items[1];
|
||||
long oamount = long.Parse(items[2]);
|
||||
string optStr = otype switch
|
||||
{
|
||||
1 => $"{t1}胜",
|
||||
2 => $"{t2}胜",
|
||||
3 => $"比分 {ovalue}",
|
||||
4 => $"MVP {ovalue}",
|
||||
_ => ovalue
|
||||
};
|
||||
summary.Add($"{optStr} {oamount}G");
|
||||
}
|
||||
}
|
||||
|
||||
string detailLine = string.Join(", ", summary);
|
||||
string statusLine;
|
||||
if (allSettled == 0)
|
||||
{
|
||||
statusLine = "待开奖";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (claimedCount > 0 && unclaimedCount == 0 && lostCount == 0)
|
||||
statusLine = "已领取";
|
||||
else if (unclaimedCount > 0)
|
||||
statusLine = "待领奖";
|
||||
else if (lostCount > 0 && claimedCount == 0 && unclaimedCount == 0)
|
||||
statusLine = "未中奖";
|
||||
else
|
||||
statusLine = "部分已领";
|
||||
}
|
||||
|
||||
string matchLabel = $"{t1} vs {t2}".CreateCmdInput($"比赛详情 {matchId}");
|
||||
sb.Append($"[比赛{matchId}] {matchLabel} | ");
|
||||
sb.Append($"投注:{totalAmount}G ({detailLine}) | ");
|
||||
sb.Append($"状态:{statusLine}");
|
||||
if (totalPayout > 0)
|
||||
sb.Append($" (+{totalPayout}G)");
|
||||
sb.AppendLine();
|
||||
}
|
||||
return sb.ToString();
|
||||
return sb.ToString().TrimEnd();
|
||||
}
|
||||
return "数据库连接失败。";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据当前时间更新赛事和比赛的状态(仅更新未结束的记录)
|
||||
/// </summary>
|
||||
private static void UpdateStatuses(SQLHelper sql)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// 更新赛事状态:0→1 (进行中),1→2 (已结束)
|
||||
sql.Parameters["@now"] = now;
|
||||
sql.Execute("UPDATE csbetting_events SET status = 1 WHERE status = 0 AND start_time <= @now AND end_time > @now");
|
||||
sql.Parameters["@now"] = now;
|
||||
sql.Execute("UPDATE csbetting_events SET status = 2 WHERE status <= 1 AND end_time <= @now");
|
||||
|
||||
// 更新比赛状态:0→1 (进行中),1→2 (已结束) - 注意不要覆盖已结算的比赛(winner 为 null 时视为未结束)
|
||||
sql.Parameters["@now"] = now;
|
||||
sql.Execute("UPDATE csbetting_matches SET status = 1 WHERE status = 0 AND start_time <= @now AND bet_deadline < @now AND winner IS NULL");
|
||||
// 对于已经过了开始时间但还没有 winner 且状态为 1 的,可保留为进行中;实际上只要 winner 为 null,状态应为 1(进行中)
|
||||
// 如果有结果但 winner 不为 null,管理员应该已经手动结算,状态会设为 2,这里不做额外修改。
|
||||
// 安全起见,只更新未开始的,以及当比赛时间已过且无 winner 时自动变成进行中。
|
||||
// 如果需要自动结束(比如时间过长),可再添加规则,但竞猜系统通常由管理员手动结算结束。
|
||||
// 这里只做基础更新。
|
||||
}
|
||||
|
||||
public static long ClaimRewards(long uid)
|
||||
{
|
||||
// 返回领取的总金币,由上层加到用户身上
|
||||
@ -13,7 +13,6 @@ using Oshima.FunGame.OshimaModules.Regions;
|
||||
using Oshima.FunGame.OshimaModules.Skills;
|
||||
using Oshima.FunGame.OshimaModules.Units;
|
||||
using Oshima.FunGame.OshimaServers.Model;
|
||||
using Oshima.FunGame.OshimaServers.Model;
|
||||
using ProjectRedbud.FunGame.SQLQueryExtension;
|
||||
|
||||
namespace Oshima.FunGame.OshimaServers.Service
|
||||
|
||||
@ -28,28 +28,35 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
[HttpGet("events")]
|
||||
public BotReply GetEventsOverview()
|
||||
{
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingSQLService.GetEventsOverview() } };
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingService.GetEventsOverview() } };
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("event/{eventId:int}")]
|
||||
public BotReply GetEventDetail(int eventId)
|
||||
{
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingSQLService.GetEventDetail(eventId) } };
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingService.GetEventDetail(eventId) } };
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("match/{matchId:int}")]
|
||||
public BotReply GetMatchDetail(int matchId)
|
||||
{
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingSQLService.GetMatchDetail(matchId) } };
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingService.GetMatchDetail(matchId, out int status) + (status == 0 ? $"\r\n竞猜指令:{"竞猜".CreateCmdInput()} <比赛ID> <选项> <{General.GameplayEquilibriumConstant.InGameCurrency}数>\r\n👇🏻 点击下方按钮快速竞猜" : "")} };
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("mybets/{uid:long}")]
|
||||
public BotReply GetMyBets(long uid)
|
||||
{
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingSQLService.GetMyBets(uid) } };
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingService.GetMyBets(uid) } };
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("mybets/{uid:long}/{mid:long}")]
|
||||
public BotReply GetMyBets(long uid, long mid)
|
||||
{
|
||||
return new BotReply { Markdown = new MarkdownMessage { Content = CSBettingService.GetMyBets(uid, mid) } };
|
||||
}
|
||||
|
||||
// ---------- 需要用户锁的操作 ----------
|
||||
@ -88,7 +95,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
return reply;
|
||||
}
|
||||
|
||||
if (CSBettingSQLService.PlaceBet(uid, matchId, option, amount, out string error))
|
||||
if (CSBettingService.PlaceBet(uid, matchId, option, amount, out string error))
|
||||
{
|
||||
user.Inventory.Credits -= (int)amount;
|
||||
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
|
||||
@ -131,7 +138,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
}
|
||||
|
||||
User user = FunGameService.GetUser(pc);
|
||||
long total = CSBettingSQLService.ClaimRewards(uid);
|
||||
long total = CSBettingService.ClaimRewards(uid);
|
||||
if (total > 0)
|
||||
{
|
||||
user.Inventory.Credits += (int)total;
|
||||
@ -176,7 +183,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
return reply;
|
||||
}
|
||||
|
||||
md.Content = CSBettingSQLService.SettleMatch(matchId, winner, result);
|
||||
md.Content = CSBettingService.SettleMatch(matchId, winner, result);
|
||||
return reply;
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -202,7 +209,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
return reply;
|
||||
}
|
||||
|
||||
if (CSBettingSQLService.CreateEvent(request.Name, request.StartTime, request.EndTime, out string error, out long? newId))
|
||||
if (CSBettingService.CreateEvent(request.Name, request.StartTime, request.EndTime, out string error, out long? newId))
|
||||
{
|
||||
md.Content = $"赛事创建成功!新赛事ID:{newId}";
|
||||
}
|
||||
@ -235,7 +242,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
|
||||
return reply;
|
||||
}
|
||||
|
||||
if (CSBettingSQLService.CreateMatch(request.EventId, request.Team1Name, request.Team2Name, request.Stage,
|
||||
if (CSBettingService.CreateMatch(request.EventId, request.Team1Name, request.Team2Name, request.Stage,
|
||||
request.StartTime, request.BetDeadline, request.AvailableOptions, out string error, out long? newId))
|
||||
{
|
||||
md.Content = $"比赛创建成功!新比赛ID:{newId}";
|
||||
|
||||
336
OshimaWebAPI/Services/CSBettingInputHandler.cs
Normal file
336
OshimaWebAPI/Services/CSBettingInputHandler.cs
Normal file
@ -0,0 +1,336 @@
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
using Oshima.FunGame.OshimaModules.Models;
|
||||
using Oshima.FunGame.OshimaServers.Model;
|
||||
using Oshima.FunGame.WebAPI.Model;
|
||||
|
||||
namespace Oshima.FunGame.WebAPI.Services
|
||||
{
|
||||
public partial class RainBOTService
|
||||
{
|
||||
public async Task<bool> HandleCSBettingInput(IBotMessage e, long uid)
|
||||
{
|
||||
if (e.Detail == "竞猜帮助")
|
||||
{
|
||||
e.UseNotice = false;
|
||||
BotReply reply = new()
|
||||
{
|
||||
Markdown = new MarkdownMessage
|
||||
{
|
||||
Content = "🎮 CS赛事竞猜帮助:\r\n"
|
||||
+ $"✨ {"赛事列表".CreateCmdInput()} - 查看所有赛事\r\n"
|
||||
+ $"✨ {"我的竞猜".CreateCmdInput()} - 查看我的投注记录\r\n"
|
||||
+ $"✨ {"竞猜领奖".CreateCmdInput()} - 领取竞猜奖励\r\n"
|
||||
+ $"✨ {"比赛详情".CreateCmdInput()} - 查看单场比赛并投注"
|
||||
},
|
||||
Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"))
|
||||
};
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 赛事列表
|
||||
if (e.Detail == "赛事列表")
|
||||
{
|
||||
BotReply reply = BettingController.GetEventsOverview();
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail.StartsWith("比赛详情"))
|
||||
{
|
||||
string detail = e.Detail.Replace("比赛详情", "").Trim();
|
||||
if (int.TryParse(detail, out int matchId))
|
||||
{
|
||||
BotReply reply = BettingController.GetMatchDetail(matchId);
|
||||
KeyboardMessage kb = new();
|
||||
// 构建投注键盘(填充“竞猜 <matchId> <选项> ”)
|
||||
if (reply.Markdown?.Content?.Contains("可用选项") ?? false)
|
||||
{
|
||||
kb.AppendButtons(2,
|
||||
Button.CreateCmdButton("⚔️ 队伍1胜", $"竞猜 {matchId} team1 1000", enter: false),
|
||||
Button.CreateCmdButton("🛡️ 队伍2胜", $"竞猜 {matchId} team2 1000", enter: false),
|
||||
Button.CreateCmdButton("🎯 精确比分", $"竞猜 {matchId} score:", enter: false),
|
||||
Button.CreateCmdButton("🏆 MVP", $"竞猜 {matchId} mvp:", enter: false));
|
||||
}
|
||||
kb.AppendButtonsWithNewRow(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"));
|
||||
reply.Keyboard = kb;
|
||||
BotReply reply2 = BettingController.GetMyBets(uid, matchId);
|
||||
if (reply.Markdown != null && reply.Markdown.Content != null && !(reply2.Markdown?.Content?.Equals("你还没有任何竞猜记录。") ?? true))
|
||||
{
|
||||
reply.Markdown.Content = $"{reply.Markdown.Content.Trim()}\r\n你的本场竞猜记录:\r\n{reply2.Markdown.Content}";
|
||||
}
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendAsync(e, "CS赛事竞猜", "格式:比赛详情 <比赛ID>");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 赛事详情:用于查看某一赛事下的所有比赛
|
||||
if (e.Detail.StartsWith("赛事详情"))
|
||||
{
|
||||
string detail = e.Detail.Replace("赛事详情", "").Trim();
|
||||
if (int.TryParse(detail, out int eventId))
|
||||
{
|
||||
// 调用控制器获取详情(返回BotReply)
|
||||
BotReply reply = BettingController.GetEventDetail(eventId);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("🔍 比赛详情 ", "比赛详情 ", enter: false),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
BotReply reply = new()
|
||||
{
|
||||
Markdown = new()
|
||||
{
|
||||
Content = "格式:赛事详情 <赛事ID>"
|
||||
},
|
||||
Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"))
|
||||
};
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail == "我的竞猜")
|
||||
{
|
||||
BotReply reply = BettingController.GetMyBets(uid);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖", enter: true),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"));
|
||||
if (reply.Markdown?.Content?.Contains("创建存档") ?? false)
|
||||
{
|
||||
reply.Keyboard.AppendButtons(2, Button.CreateCmdButton("⚙️ 创建存档", "创建存档"));
|
||||
}
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail == "竞猜领奖")
|
||||
{
|
||||
BotReply reply = BettingController.ClaimRewards(uid);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail.StartsWith("竞猜"))
|
||||
{
|
||||
string detail = e.Detail.Replace("竞猜", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 3 || !int.TryParse(parts[0], out int mid) || !long.TryParse(parts[^1], out long amt))
|
||||
{
|
||||
await SendAsync(e, "CS赛事竞猜", $"格式:竞猜 <比赛ID> <选项> <{General.GameplayEquilibriumConstant.InGameCurrency}数>\r\n选项:team1 / team2 / score:2:0 / mvp:选手UID");
|
||||
return true;
|
||||
}
|
||||
string option = string.Join(" ", parts[1..^1]).ToLower();
|
||||
|
||||
BotReply reply = BettingController.PlaceBet(uid, mid, option, amt);
|
||||
|
||||
// 根据控制器返回的消息判断投注结果(简单判断是否包含"成功")
|
||||
bool success = reply.Markdown?.Content?.Contains("成功") ?? false;
|
||||
|
||||
KeyboardMessage kb = new();
|
||||
// 成功与失败通用的按钮
|
||||
kb.AppendButtons(2,
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"));
|
||||
|
||||
if (reply.Markdown?.Content?.Contains("创建存档") ?? false)
|
||||
{
|
||||
kb.AppendButtons(2, Button.CreateCmdButton("⚙️ 创建存档", "创建存档"));
|
||||
}
|
||||
|
||||
// 成功时追加“继续查看该场比赛”按钮(填充指令)
|
||||
if (success)
|
||||
{
|
||||
kb.AppendButtonsWithNewRow(2,
|
||||
Button.CreateCmdButton("🔄 再次投注", e.Detail, enter: false),
|
||||
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {mid}"));
|
||||
}
|
||||
|
||||
reply.Keyboard = kb;
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 管理员结算
|
||||
if (e.Detail.StartsWith("结算比赛"))
|
||||
{
|
||||
string detail = e.Detail.Replace("结算比赛", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 2 && int.TryParse(parts[0], out int mid))
|
||||
{
|
||||
string winner = "", mResult = "";
|
||||
foreach (var p in parts[1..])
|
||||
{
|
||||
if (p.StartsWith("winner=")) winner = p[7..];
|
||||
if (p.StartsWith("result=")) mResult = p[7..];
|
||||
}
|
||||
BotReply reply = BettingController.SettleMatch(uid, mid, winner, mResult);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("⚙️ 继续结算", "结算比赛 ", enter: false));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
await SendAsync(e, "CS赛事竞猜", "格式:结算比赛 <比赛ID> winner=team1 result=2:0");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指令:创建赛事 <名称> <开始时间> <结束时间>
|
||||
// 示例:创建赛事 春季赛 2026-03-01 2026-03-10
|
||||
// 示例:创建赛事 总决赛 2026-04-01 2026-04-05 1001,1002
|
||||
if (e.Detail.StartsWith("创建赛事"))
|
||||
{
|
||||
e.UseNotice = false;
|
||||
if (!FunGameConstant.UserIdAndUsername.TryGetValue(uid, out User? user) || (!user.IsAdmin && !user.IsOperator))
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "你没有权限执行此操作。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string detail = e.Detail.Replace("创建赛事", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 3)
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "格式:创建赛事 <名称> <开始时间> <结束时间>\r\n" +
|
||||
"时间格式:yyyy-MM-dd HH:mm 或 yyyy-MM-dd(默认00:00)\r\n" +
|
||||
"示例:创建赛事 春季赛 2026-03-01 2026-03-10\r\n" +
|
||||
"示例:创建赛事 总决赛 2026-04-01 12:00 2026-04-05 18:00");
|
||||
return true;
|
||||
}
|
||||
|
||||
string name = parts[0];
|
||||
if (name.Length > 100)
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "赛事名称不能超过100个字符。");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 尝试解析时间(支持 yyyy-MM-dd 或 yyyy-MM-dd HH:mm)
|
||||
string startStr = parts[1] + (parts[2].Contains(':') ? " " + parts[2] : " 00:00");
|
||||
int nextIndex = parts[2].Contains(':') ? 3 : 2;
|
||||
string endStr = parts[nextIndex] + (parts.Length > nextIndex + 1 && parts[nextIndex + 1].Contains(':') ? " " + parts[nextIndex + 1] : " 00:00");
|
||||
|
||||
if (!DateTime.TryParseExact(startStr, CheckDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime startTime) ||
|
||||
!DateTime.TryParseExact(endStr, CheckDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime endTime))
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "时间格式错误,请使用 yyyy-MM-dd 或 yyyy-MM-dd HH:mm。");
|
||||
return true;
|
||||
}
|
||||
|
||||
BotReply reply = BettingController.CreateEvent(new CreateEventRequest
|
||||
{
|
||||
Uid = uid,
|
||||
Name = name,
|
||||
StartTime = startTime,
|
||||
EndTime = endTime
|
||||
});
|
||||
await SendAsync(e, "创建赛事", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指令:创建比赛 <赛事ID> <队伍1> <队伍2> <阶段> <开始时间> <投注截止时间> [选项列表(逗号分隔)]
|
||||
// 示例:创建比赛 1 NAVI FaZe Quarter-final 2026-03-05 14:00 2026-03-05 13:55
|
||||
// 示例:创建比赛 1 G2 Vitality Semi-final 2026-04-02 18:00 2026-04-02 17:55 team1_win,team2_win,score
|
||||
if (e.Detail.StartsWith("创建比赛"))
|
||||
{
|
||||
e.UseNotice = false;
|
||||
if (!FunGameConstant.UserIdAndUsername.TryGetValue(uid, out User? user) || (!user.IsAdmin && !user.IsOperator))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "你没有权限执行此操作。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string detail = e.Detail.Replace("创建比赛", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 7) // 最少需要 eventId, team1, team2, stage, start date, start time, deadline date, deadline time
|
||||
{
|
||||
await SendAsync(e, "创建比赛",
|
||||
"格式:创建比赛 <赛事ID> <队伍1> <队伍2> <阶段> <开始时间> <投注截止时间> [选项列表(逗号分隔)]\r\n" +
|
||||
"时间格式:yyyy-MM-dd HH:mm(开始/截止各占两段)\r\n" +
|
||||
"示例:创建比赛 1 NAVI FaZe Quarter-final 2026-03-05 14:00 2026-03-05 13:55\r\n" +
|
||||
"选项默认 team1_win,team2_win ,可额外添加 score,mvp");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!int.TryParse(parts[0], out int eventId))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "赛事ID必须为数字。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string team1 = parts[1];
|
||||
string team2 = parts[2];
|
||||
string stage = parts[3];
|
||||
|
||||
// 开始时间(parts[4] + parts[5])
|
||||
string startDate = parts[4];
|
||||
string startTime = parts[5];
|
||||
// 截止时间(parts[6] + parts[7] 如果存在)
|
||||
if (parts.Length < 8)
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "投注截止时间需要完整日期和时间,示例:2026-03-05 13:55");
|
||||
return true;
|
||||
}
|
||||
string deadlineDate = parts[6];
|
||||
string deadlineTime = parts[7];
|
||||
|
||||
if (!DateTime.TryParseExact(startDate + " " + startTime, "yyyy-MM-dd HH:mm", null, System.Globalization.DateTimeStyles.None, out DateTime startDt) ||
|
||||
!DateTime.TryParseExact(deadlineDate + " " + deadlineTime, "yyyy-MM-dd HH:mm", null, System.Globalization.DateTimeStyles.None, out DateTime deadlineDt))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "时间格式错误,请使用 yyyy-MM-dd HH:mm(开始时间和截止时间各两段)。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string options = "team1_win,team2_win";
|
||||
if (parts.Length > 8)
|
||||
{
|
||||
options = string.Join(",", parts[8..]); // 剩余部分视为选项列表
|
||||
}
|
||||
|
||||
BotReply reply = BettingController.CreateMatch(new CreateMatchRequest
|
||||
{
|
||||
Uid = uid,
|
||||
EventId = eventId,
|
||||
Team1Name = team1,
|
||||
Team2Name = team2,
|
||||
Stage = stage,
|
||||
StartTime = startDt,
|
||||
BetDeadline = deadlineDt,
|
||||
AvailableOptions = options
|
||||
});
|
||||
await SendAsync(e, "创建比赛", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,14 +13,14 @@ using Oshima.FunGame.OshimaServers.Model;
|
||||
using Oshima.FunGame.OshimaServers.Service;
|
||||
using Oshima.FunGame.WebAPI.Constant;
|
||||
using Oshima.FunGame.WebAPI.Controllers;
|
||||
using Oshima.FunGame.WebAPI.Model;
|
||||
using Oshima.FunGame.WebAPI.Models;
|
||||
|
||||
namespace Oshima.FunGame.WebAPI.Services
|
||||
{
|
||||
public class RainBOTService(FunGameController controller, QQController qqcontroller, QQBotService service, ILogger<RainBOTService> logger, IMemoryCache memoryCache, TestController testController, CSBettingController bettingController)
|
||||
public partial class RainBOTService(FunGameController controller, QQController qqcontroller, QQBotService service, ILogger<RainBOTService> logger, IMemoryCache memoryCache, TestController testController, CSBettingController bettingController)
|
||||
{
|
||||
private static List<string> FunGameItemType { get; } = ["卡包", "武器", "防具", "鞋子", "饰品", "消耗品", "魔法卡", "收藏品", "特殊物品", "任务物品", "礼包", "其他"];
|
||||
private static string[] CheckDateTimeFormat { get; } = ["yyyy-MM-dd HH:mm", "yyyy-MM-dd"];
|
||||
private bool FunGameSimulation { get; set; } = false;
|
||||
private FunGameController Controller { get; } = controller;
|
||||
private QQController QQController { get; } = qqcontroller;
|
||||
@ -3878,306 +3878,8 @@ namespace Oshima.FunGame.WebAPI.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
if (e.Detail == "竞猜帮助")
|
||||
if (await HandleCSBettingInput(e, uid))
|
||||
{
|
||||
e.UseNotice = false;
|
||||
BotReply reply = new()
|
||||
{
|
||||
Markdown = new MarkdownMessage
|
||||
{
|
||||
Content = "🎮 CS赛事竞猜帮助:\r\n"
|
||||
+ $"✨ {"赛事列表".CreateCmdInput()} - 查看所有赛事\r\n"
|
||||
+ $"✨ {"我的竞猜".CreateCmdInput()} - 查看我的投注记录\r\n"
|
||||
+ $"✨ {"竞猜领奖".CreateCmdInput()} - 领取竞猜奖励\r\n"
|
||||
+ $"✨ {"比赛详情".CreateCmdInput()} - 查看单场比赛并投注"
|
||||
},
|
||||
Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"))
|
||||
};
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 赛事列表
|
||||
if (e.Detail == "赛事列表")
|
||||
{
|
||||
BotReply reply = BettingController.GetEventsOverview();
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail.StartsWith("比赛详情"))
|
||||
{
|
||||
string detail = e.Detail.Replace("比赛详情", "").Trim();
|
||||
if (int.TryParse(detail, out int matchId))
|
||||
{
|
||||
BotReply reply = BettingController.GetMatchDetail(matchId);
|
||||
// 构建投注键盘(填充“竞猜 <matchId> <选项> ”)
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("⚔️ 队伍1胜", $"竞猜 {matchId} team1 ", enter: false),
|
||||
Button.CreateCmdButton("🛡️ 队伍2胜", $"竞猜 {matchId} team2 ", enter: false),
|
||||
Button.CreateCmdButton("🎯 精确比分", $"竞猜 {matchId} score:", enter: false),
|
||||
Button.CreateCmdButton("🏆 MVP", $"竞猜 {matchId} mvp:", enter: false))
|
||||
.AppendButtonsWithNewRow(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendAsync(e, "CS赛事竞猜", "格式:比赛详情 <比赛ID>");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 赛事详情:用于查看某一赛事下的所有比赛
|
||||
if (e.Detail.StartsWith("赛事详情"))
|
||||
{
|
||||
string detail = e.Detail.Replace("赛事详情", "").Trim();
|
||||
if (int.TryParse(detail, out int eventId))
|
||||
{
|
||||
// 调用控制器获取详情(返回BotReply)
|
||||
BotReply reply = BettingController.GetEventDetail(eventId);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("🔍 比赛详情 ", "比赛详情 ", enter: false),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
BotReply reply = new()
|
||||
{
|
||||
Markdown = new()
|
||||
{
|
||||
Content = "格式:赛事详情 <赛事ID>"
|
||||
},
|
||||
Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"))
|
||||
};
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail == "我的竞猜")
|
||||
{
|
||||
BotReply reply = BettingController.GetMyBets(uid);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(3,
|
||||
Button.CreateCmdButton("💰 竞猜领奖", "竞猜领奖", enter: true),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail == "竞猜领奖")
|
||||
{
|
||||
BotReply reply = BettingController.ClaimRewards(uid);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Detail.StartsWith("竞猜"))
|
||||
{
|
||||
string detail = e.Detail.Replace("竞猜", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 3 || !int.TryParse(parts[0], out int mid) || !long.TryParse(parts[^1], out long amt))
|
||||
{
|
||||
await SendAsync(e, "CS赛事竞猜", "格式:竞猜 <比赛ID> <选项> <金额>\r\n选项:team1 / team2 / score:16:14 / mvp:选手UID");
|
||||
return true;
|
||||
}
|
||||
string option = string.Join(" ", parts[1..^1]).ToLower();
|
||||
|
||||
BotReply reply = BettingController.PlaceBet(uid, mid, option, amt);
|
||||
|
||||
// 根据控制器返回的消息判断投注结果(简单判断是否包含"成功")
|
||||
bool success = reply.Markdown?.Content?.Contains("成功") ?? false;
|
||||
|
||||
KeyboardMessage kb = new();
|
||||
// 成功与失败通用的按钮
|
||||
kb.AppendButtons(3,
|
||||
Button.CreateCmdButton("📜 我的竞猜", "我的竞猜"),
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("❓ 竞猜帮助", "竞猜帮助"));
|
||||
|
||||
// 成功时追加“继续查看该场比赛”按钮(填充指令)
|
||||
if (success)
|
||||
{
|
||||
kb.AppendButtonsWithNewRow(2,
|
||||
Button.CreateCmdButton("🔄 再次投注", e.Detail, enter: false),
|
||||
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {mid}"));
|
||||
}
|
||||
|
||||
reply.Keyboard = kb;
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 管理员结算
|
||||
if (e.Detail.StartsWith("结算比赛"))
|
||||
{
|
||||
string detail = e.Detail.Replace("结算比赛", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 2 && int.TryParse(parts[0], out int mid))
|
||||
{
|
||||
string winner = "", mResult = "";
|
||||
foreach (var p in parts[1..])
|
||||
{
|
||||
if (p.StartsWith("winner=")) winner = p[7..];
|
||||
if (p.StartsWith("result=")) mResult = p[7..];
|
||||
}
|
||||
BotReply reply = BettingController.SettleMatch(uid, mid, winner, mResult);
|
||||
reply.Keyboard = new KeyboardMessage()
|
||||
.AppendButtons(2,
|
||||
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
|
||||
Button.CreateCmdButton("⚙️ 继续结算", "结算比赛 ", enter: false));
|
||||
await SendAsync(e, "CS赛事竞猜", reply);
|
||||
}
|
||||
else
|
||||
await SendAsync(e, "CS赛事竞猜", "格式:结算比赛 <比赛ID> winner=team1 result=16:14");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指令:创建赛事 <名称> <开始时间> <结束时间>
|
||||
// 示例:创建赛事 春季赛 2026-03-01 2026-03-10
|
||||
// 示例:创建赛事 总决赛 2026-04-01 2026-04-05 1001,1002
|
||||
if (e.Detail.StartsWith("创建赛事"))
|
||||
{
|
||||
e.UseNotice = false;
|
||||
if (!FunGameConstant.UserIdAndUsername.TryGetValue(uid, out User? user) || (!user.IsAdmin && !user.IsOperator))
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "你没有权限执行此操作。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string detail = e.Detail.Replace("创建赛事", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 3)
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "格式:创建赛事 <名称> <开始时间> <结束时间>\r\n" +
|
||||
"时间格式:yyyy-MM-dd HH:mm 或 yyyy-MM-dd(默认00:00)\r\n" +
|
||||
"示例:创建赛事 春季赛 2026-03-01 2026-03-10\r\n" +
|
||||
"示例:创建赛事 总决赛 2026-04-01 12:00 2026-04-05 18:00");
|
||||
return true;
|
||||
}
|
||||
|
||||
string name = parts[0];
|
||||
if (name.Length > 100)
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "赛事名称不能超过100个字符。");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 尝试解析时间(支持 yyyy-MM-dd 或 yyyy-MM-dd HH:mm)
|
||||
string startStr = parts[1] + (parts[2].Contains(':') ? " " + parts[2] : " 00:00");
|
||||
int nextIndex = parts[2].Contains(':') ? 3 : 2;
|
||||
string endStr = parts[nextIndex] + (parts.Length > nextIndex + 1 && parts[nextIndex + 1].Contains(':') ? " " + parts[nextIndex + 1] : " 00:00");
|
||||
int mvpStart = parts[nextIndex].Contains(':') ? nextIndex + 2 : nextIndex + 1;
|
||||
|
||||
if (!DateTime.TryParseExact(startStr, new[] { "yyyy-MM-dd HH:mm", "yyyy-MM-dd" }, null, System.Globalization.DateTimeStyles.None, out DateTime startTime) ||
|
||||
!DateTime.TryParseExact(endStr, new[] { "yyyy-MM-dd HH:mm", "yyyy-MM-dd" }, null, System.Globalization.DateTimeStyles.None, out DateTime endTime))
|
||||
{
|
||||
await SendAsync(e, "创建赛事", "时间格式错误,请使用 yyyy-MM-dd 或 yyyy-MM-dd HH:mm。");
|
||||
return true;
|
||||
}
|
||||
|
||||
BotReply reply = BettingController.CreateEvent(new CreateEventRequest
|
||||
{
|
||||
Uid = uid,
|
||||
Name = name,
|
||||
StartTime = startTime,
|
||||
EndTime = endTime
|
||||
});
|
||||
await SendAsync(e, "创建赛事", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指令:创建比赛 <赛事ID> <队伍1> <队伍2> <阶段> <开始时间> <投注截止时间> [选项列表(逗号分隔)]
|
||||
// 示例:创建比赛 1 NAVI FaZe Quarter-final 2026-03-05 14:00 2026-03-05 13:55
|
||||
// 示例:创建比赛 1 G2 Vitality Semi-final 2026-04-02 18:00 2026-04-02 17:55 team1_win,team2_win,score
|
||||
if (e.Detail.StartsWith("创建比赛"))
|
||||
{
|
||||
e.UseNotice = false;
|
||||
if (!FunGameConstant.UserIdAndUsername.TryGetValue(uid, out User? user) || (!user.IsAdmin && !user.IsOperator))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "你没有权限执行此操作。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string detail = e.Detail.Replace("创建比赛", "").Trim();
|
||||
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 7) // 最少需要 eventId, team1, team2, stage, start date, start time, deadline date, deadline time
|
||||
{
|
||||
await SendAsync(e, "创建比赛",
|
||||
"格式:创建比赛 <赛事ID> <队伍1> <队伍2> <阶段> <开始时间> <投注截止时间> [选项列表(逗号分隔)]\r\n" +
|
||||
"时间格式:yyyy-MM-dd HH:mm(开始/截止各占两段)\r\n" +
|
||||
"示例:创建比赛 1 NAVI FaZe Quarter-final 2026-03-05 14:00 2026-03-05 13:55\r\n" +
|
||||
"选项默认 team1_win,team2_win ,可额外添加 score,mvp");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!int.TryParse(parts[0], out int eventId))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "赛事ID必须为数字。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string team1 = parts[1];
|
||||
string team2 = parts[2];
|
||||
string stage = parts[3];
|
||||
|
||||
// 开始时间(parts[4] + parts[5])
|
||||
string startDate = parts[4];
|
||||
string startTime = parts[5];
|
||||
// 截止时间(parts[6] + parts[7] 如果存在)
|
||||
if (parts.Length < 8)
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "投注截止时间需要完整日期和时间,示例:2026-03-05 13:55");
|
||||
return true;
|
||||
}
|
||||
string deadlineDate = parts[6];
|
||||
string deadlineTime = parts[7];
|
||||
|
||||
if (!DateTime.TryParseExact(startDate + " " + startTime, "yyyy-MM-dd HH:mm", null, System.Globalization.DateTimeStyles.None, out DateTime startDt) ||
|
||||
!DateTime.TryParseExact(deadlineDate + " " + deadlineTime, "yyyy-MM-dd HH:mm", null, System.Globalization.DateTimeStyles.None, out DateTime deadlineDt))
|
||||
{
|
||||
await SendAsync(e, "创建比赛", "时间格式错误,请使用 yyyy-MM-dd HH:mm(开始时间和截止时间各两段)。");
|
||||
return true;
|
||||
}
|
||||
|
||||
string options = "team1_win,team2_win";
|
||||
if (parts.Length > 8)
|
||||
{
|
||||
options = string.Join(",", parts[8..]); // 剩余部分视为选项列表
|
||||
}
|
||||
|
||||
BotReply reply = BettingController.CreateMatch(new CreateMatchRequest
|
||||
{
|
||||
Uid = uid,
|
||||
EventId = eventId,
|
||||
Team1Name = team1,
|
||||
Team2Name = team2,
|
||||
Stage = stage,
|
||||
StartTime = startDt,
|
||||
BetDeadline = deadlineDt,
|
||||
AvailableOptions = options
|
||||
});
|
||||
await SendAsync(e, "创建比赛", reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user