新功能

This commit is contained in:
milimoe 2026-05-25 22:50:38 +08:00
parent 5492fc4eb9
commit 9d3fdfe328
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
6 changed files with 182 additions and 41 deletions

View File

@ -51,6 +51,9 @@ namespace Oshima.FunGame.WebAPI.Model
[JsonPropertyName("team1_win_probability")]
public decimal? Team1WinProbability { get; set; }
[JsonPropertyName("betting_enabled")]
public bool? BettingEnabled { get; set; }
}
public class UpdateMatchRequest

View File

@ -85,6 +85,7 @@ namespace Oshima.FunGame.OshimaServers.Model
public long FunGameUID { get; set; }
public bool UseNotice { get; set; }
public string ImageUrl { get; set; }
public bool SendProactive { get; set; }
}
public class BotReply
@ -267,6 +268,9 @@ namespace Oshima.FunGame.OshimaServers.Model
[JsonIgnore]
public string ImageUrl { get; set; } = "";
[JsonIgnore]
public bool SendProactive { get; set; }
}
public class C2CMessage : IBotMessage
@ -303,6 +307,9 @@ namespace Oshima.FunGame.OshimaServers.Model
public string OpenId => Author.UserOpenId;
public bool IsGroup => false;
public string AuthorOpenId => Author.UserOpenId;
[JsonIgnore]
public bool SendProactive { get; set; }
}
public class GroupAtMessage : IBotMessage
@ -342,6 +349,9 @@ namespace Oshima.FunGame.OshimaServers.Model
public string OpenId => GroupOpenId;
public bool IsGroup => true;
public string AuthorOpenId => Author.MemberOpenId;
[JsonIgnore]
public bool SendProactive { get; set; }
}
public class MediaResponse

View File

@ -324,6 +324,35 @@ namespace Oshima.FunGame.WebAPI.Services
return "数据库连接失败。";
}
public static bool GetMatchTimes(int matchId, out DateTime startTime, out DateTime betDeadline, out int status, out string error)
{
startTime = DateTime.MinValue;
betDeadline = DateTime.MinValue;
status = -1;
error = "";
using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null)
{
error = "数据库连接失败。";
return false;
}
sql.Parameters["@mid"] = matchId;
sql.ExecuteDataSet("SELECT start_time, bet_deadline, status FROM csbetting_matches WHERE id = @mid");
if (!sql.Success || sql.DataSet.Tables[0].Rows.Count == 0)
{
error = "比赛不存在。";
return false;
}
DataRow row = sql.DataSet.Tables[0].Rows[0];
startTime = Convert.ToDateTime(row["start_time"]);
betDeadline = Convert.ToDateTime(row["bet_deadline"]);
status = Convert.ToInt32(row["status"]);
return true;
}
public static bool PlaceBet(long uid, int matchId, string option, long amount, out string error)
{
error = "";
@ -770,7 +799,7 @@ namespace Oshima.FunGame.WebAPI.Services
}
// 创建比赛
public static bool CreateMatch(int eventId, string team1Name, string team2Name, string stage, DateTime startTime, DateTime betDeadline, string availableOptions, decimal? team1WinOdds, decimal? team2WinOdds, decimal? team1WinProbability, out string error, out long? newMatchId)
public static bool CreateMatch(int eventId, string team1Name, string team2Name, string stage, DateTime startTime, DateTime betDeadline, string availableOptions, decimal? team1WinOdds, decimal? team2WinOdds, decimal? team1WinProbability, bool? enableBet, out string error, out long? newMatchId)
{
error = "";
newMatchId = null;
@ -822,9 +851,7 @@ namespace Oshima.FunGame.WebAPI.Services
}
else
{
// 默认双方各 2.0
t1Odds = 2.0m;
t2Odds = 2.0m;
(t1Odds, t2Odds) = CalculateOdds(0.5M);
}
// 校验奖励率大于0
@ -843,9 +870,10 @@ namespace Oshima.FunGame.WebAPI.Services
sql.Parameters["@opts"] = optionsJson;
sql.Parameters["@t1_odds"] = t1Odds;
sql.Parameters["@t2_odds"] = t2Odds;
sql.Parameters["@betting_enabled"] = (enableBet ?? false) ? 1 : 0;
sql.Execute(@"INSERT INTO csbetting_matches
(event_id, team1_name, team2_name, stage, start_time, bet_deadline, available_options, team1_win_odds, team2_win_odds, status)
VALUES (@eid, @t1, @t2, @stage, @start, @deadline, @opts, @t1_odds, @t2_odds, 0)");
VALUES (@eid, @t1, @t2, @stage, @start, @deadline, @opts, @t1_odds, @t2_odds, 0, @betting_enabled)");
if (sql.Success)
{

View File

@ -79,6 +79,19 @@ namespace Oshima.FunGame.WebAPI.Controllers
return new BotReply { Markdown = new MarkdownMessage { Content = content } };
}
[HttpGet("match/time/{mid:int}")]
public BotReply GetMatchTimes(int mid)
{
MarkdownMessage md = new() { Content = busy };
BotReply reply = new() { Markdown = md };
if (CSBettingService.GetMatchTimes(mid, out DateTime startTime, out DateTime betDeadline, out int status, out string error))
{
md.Content = $"比赛开始时间:{startTime:yyyy-MM-dd HH:mm:ss}\n预测截止时间{betDeadline:yyyy-MM-dd HH:mm:ss}\n当前状态{(status == 0 ? "" : status == 1 ? "" : "")}";
}
else md.Content = error;
return reply;
}
// ---------- 需要用户锁的操作 ----------
/// <summary>
@ -264,7 +277,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
}
if (CSBettingService.CreateMatch(request.EventId, request.Team1Name, request.Team2Name, request.Stage,
request.StartTime, request.BetDeadline, request.AvailableOptions, request.Team1WinOdds, request.Team2WinOdds, request.Team1WinProbability, out string error, out long? newId))
request.StartTime, request.BetDeadline, request.AvailableOptions, request.Team1WinOdds, request.Team2WinOdds, request.Team1WinProbability, request.BettingEnabled, out string error, out long? newId))
{
md.Content = $"比赛创建成功新比赛ID{newId}";
reply.Keyboard = new KeyboardMessage().AppendButtons(1, Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {newId}"));

View File

@ -409,6 +409,21 @@ namespace Oshima.FunGame.WebAPI.Services
return true;
}
}
bool enableBet = true;
if (paramDict.TryGetValue("be", out string? be))
{
if (be == "0" || be == "1") enableBet = be == "1";
else
{
await SendAsync(e, "创建比赛", "enabled 值必须为 0 或 1。");
return true;
}
}
// 如果队伍包含TBD则默认不可预测
if (team1 == "TBD" || team2 == "TBD")
{
enableBet = false;
}
BotReply reply = BettingController.CreateMatch(new CreateMatchRequest
{
@ -422,42 +437,13 @@ namespace Oshima.FunGame.WebAPI.Services
AvailableOptions = options,
Team1WinOdds = team1Odds,
Team2WinOdds = team2Odds,
Team1WinProbability = team1WinProbability
Team1WinProbability = team1WinProbability,
BettingEnabled = enableBet
});
await SendAsync(e, "创建比赛", reply);
return true;
}
// 指令:关闭预测 <比赛ID>
if (e.Detail.StartsWith("关闭预测") || 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("关闭预测", "")
.Replace("结束预测", "")
.Trim();
if (int.TryParse(detail, out int matchId))
{
BotReply reply = BettingController.CloseBetting(uid, matchId);
reply.Keyboard = new KeyboardMessage()
.AppendButtons(2,
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {matchId}"));
await SendAsync(e, "关闭预测", reply);
}
else
{
await SendAsync(e, "关闭预测", "格式:关闭预测 <比赛ID>");
}
return true;
}
// 指令:修改比赛 <比赛ID> [参数=值 ...]
if (e.Detail.StartsWith("修改比赛"))
{
@ -581,6 +567,107 @@ namespace Oshima.FunGame.WebAPI.Services
return true;
}
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 < 2 || !int.TryParse(parts[0], out int matchId) || !int.TryParse(parts[1], out int minutes) || minutes <= 0)
{
await SendAsync(e, "修改比赛", "格式:推迟比赛 <比赛ID> <分钟数>\n示例推迟比赛 123 30");
return true;
}
// 获取当前比赛时间
if (!CSBettingService.GetMatchTimes(matchId, out DateTime oldStart, out DateTime oldDeadline, out int status, out string error))
{
await SendAsync(e, "修改比赛", error);
return true;
}
if (status == 2)
{
await SendAsync(e, "修改比赛", "比赛已结束,无法推迟。");
return true;
}
DateTime newStart = oldStart.AddMinutes(minutes);
DateTime newDeadline = oldDeadline.AddMinutes(minutes);
UpdateMatchRequest request = new()
{
MatchId = matchId,
StartTime = newStart,
BetDeadline = newDeadline
};
BotReply reply = BettingController.UpdateMatch(request);
reply.Keyboard = new KeyboardMessage()
.AppendButtons(2,
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
Button.CreateCmdButton("📅 比赛列表", "比赛列表"),
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {matchId}"));
await SendAsync(e, "修改比赛", reply);
return true;
}
// 提前比赛
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 < 2 || !int.TryParse(parts[0], out int matchId) || !int.TryParse(parts[1], out int minutes) || minutes <= 0)
{
await SendAsync(e, "修改比赛", "格式:提前比赛 <比赛ID> <分钟数>\n示例提前比赛 123 30");
return true;
}
// 获取当前比赛时间
if (!CSBettingService.GetMatchTimes(matchId, out DateTime oldStart, out DateTime oldDeadline, out int status, out string error))
{
await SendAsync(e, "修改比赛", error);
return true;
}
if (status == 2)
{
await SendAsync(e, "修改比赛", "比赛已结束,无法推迟。");
return true;
}
DateTime newStart = oldStart.AddMinutes(-minutes);
DateTime newDeadline = oldDeadline.AddMinutes(-minutes);
UpdateMatchRequest request = new()
{
MatchId = matchId,
StartTime = newStart,
BetDeadline = newDeadline
};
BotReply reply = BettingController.UpdateMatch(request);
reply.Keyboard = new KeyboardMessage()
.AppendButtons(2,
Button.CreateCmdButton("📋 赛事列表", "赛事列表"),
Button.CreateCmdButton("📅 比赛列表", "比赛列表"),
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {matchId}"));
await SendAsync(e, "修改比赛", reply);
return true;
}
return false;
}

View File

@ -63,12 +63,12 @@ namespace Oshima.FunGame.WebAPI.Services
else if (msg.IsGroup)
{
content = "\r\n" + content.Trim();
await Service.SendGroupMessageAsync(msg.OpenId, content, msgType, media, msg.Id, msgSeq);
await Service.SendGroupMessageAsync(msg.OpenId, content, msgType, media, msg.SendProactive ? null : msg.Id, msgSeq);
}
else
{
content = content.Trim();
await Service.SendC2CMessageAsync(msg.OpenId, content, msgType, media, msg.Id, msgSeq);
await Service.SendC2CMessageAsync(msg.OpenId, content, msgType, media, msg.SendProactive ? null : msg.Id, msgSeq);
}
await CheckOfflineNotice(msg);
}
@ -83,11 +83,11 @@ namespace Oshima.FunGame.WebAPI.Services
}
else if (msg.IsGroup)
{
await Service.SendGroupMarkdownAsync(msg.OpenId, mdMsg, kbMsg, msg.Id, msgSeq);
await Service.SendGroupMarkdownAsync(msg.OpenId, mdMsg, kbMsg, msg.SendProactive ? null : msg.Id, msgSeq);
}
else
{
await Service.SendC2CMarkdownAsync(msg.OpenId, mdMsg, kbMsg, msg.Id, msgSeq);
await Service.SendC2CMarkdownAsync(msg.OpenId, mdMsg, kbMsg, msg.SendProactive ? null : msg.Id, msgSeq);
}
await CheckOfflineNotice(msg);
}