feat(kick): add module page and queue /api/kick
This commit is contained in:
1 parent
0401312ee3
commit
f551da0a8b
7 files changed
+551
-156
No files matched your search
@@ -0,0 +1,196 @@
|
||||
@namespace TelegramPanel.Web.Components.ModulePages
|
||||
@inject TelegramPanel.Core.Services.BotManagementService BotManagement
|
||||
@inject TelegramPanel.Core.Services.BatchTaskManagementService TaskManagement
|
||||
@inject ISnackbar Snackbar
|
||||
@inject NavigationManager Navigation
|
||||
@using System.Text.Json
|
||||
@using TelegramPanel.Core.BatchTasks
|
||||
@using TelegramPanel.Data.Entities
|
||||
@using TelegramPanel.Web.ExternalApi
|
||||
@using Microsoft.AspNetCore.Components
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-4 tp-page-title">踢人/封禁</MudText>
|
||||
|
||||
<MudPaper Class="pa-4" Elevation="0" Outlined="true">
|
||||
<MudStack Spacing="2">
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
|
||||
提交后会在后台执行,可到【任务中心】查看进度与结果。频道数量较多时可能需要较长时间。
|
||||
</MudAlert>
|
||||
|
||||
<MudSelect T="int" Value="@selectedBotId" ValueChanged="@(async (int id) => await OnSelectedBotChanged(id))"
|
||||
Label="选择机器人" Variant="Variant.Outlined" Dense="true" Disabled="@loading">
|
||||
<MudSelectItem Value="0">全部机器人(谨慎)</MudSelectItem>
|
||||
@foreach (var b in bots)
|
||||
{
|
||||
<MudSelectItem Value="@b.Id">@b.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudNumericField T="long" @bind-Value="userId" Label="用户 ID(user_id)" Variant="Variant.Outlined" Dense="true"
|
||||
Min="1" Disabled="@loading" />
|
||||
|
||||
<MudSwitch @bind-Value="permanentBan" Color="Color.Error" Disabled="@loading"
|
||||
Label="永久封禁(否则仅踢出,可重新加入)" />
|
||||
|
||||
<MudSwitch @bind-Value="useAllChats" Disabled="@(loading || selectedBotId == 0)"
|
||||
Label="使用全部频道/群组(关闭后可手动输入 chat_id 列表)" />
|
||||
|
||||
@if (!useAllChats && selectedBotId != 0)
|
||||
{
|
||||
<MudTextField @bind-Value="chatIdsText" Label="chat_id 列表(可选)" Variant="Variant.Outlined" Lines="3"
|
||||
Placeholder="支持逗号/空格/换行分隔,例如:123,456,789"
|
||||
Disabled="@loading" />
|
||||
}
|
||||
|
||||
<MudStack Row="true" Spacing="2">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Error" StartIcon="@Icons.Material.Filled.PersonRemove"
|
||||
Disabled="@(!CanSubmit)" OnClick="SubmitAsync">
|
||||
提交任务
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Default" Disabled="@loading"
|
||||
OnClick="@(() => Navigation.NavigateTo("/tasks"))">
|
||||
打开任务中心
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public string ModuleId { get; set; } = "";
|
||||
[Parameter] public string PageKey { get; set; } = "";
|
||||
|
||||
private bool loading = true;
|
||||
private List<Bot> bots = new();
|
||||
private int selectedBotId = 0;
|
||||
private long userId;
|
||||
private bool permanentBan;
|
||||
private bool useAllChats = true;
|
||||
private string chatIdsText = "";
|
||||
|
||||
private bool CanSubmit => !loading && userId > 0 && (selectedBotId == 0 || bots.Any(x => x.Id == selectedBotId));
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
bots = (await BotManagement.GetAllBotsAsync())
|
||||
.Where(b => b.IsActive)
|
||||
.OrderBy(b => b.Id)
|
||||
.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"加载机器人失败:{ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSelectedBotChanged(int id)
|
||||
{
|
||||
selectedBotId = id;
|
||||
if (selectedBotId == 0)
|
||||
useAllChats = true;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task SubmitAsync()
|
||||
{
|
||||
if (!CanSubmit)
|
||||
return;
|
||||
|
||||
var botId = selectedBotId;
|
||||
var runUseAllChats = botId == 0 ? true : useAllChats;
|
||||
var chatIds = runUseAllChats ? new List<long>() : ParseChatIds(chatIdsText);
|
||||
|
||||
loading = true;
|
||||
try
|
||||
{
|
||||
var total = await CountTargetsAsync(botId, runUseAllChats, chatIds);
|
||||
if (total <= 0)
|
||||
{
|
||||
Snackbar.Add("未匹配到任何可操作的频道/群组(请先同步 Bot 频道数据,或检查 chat_id 列表)", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var log = new KickTaskLog
|
||||
{
|
||||
ApiName = "模块页面",
|
||||
BotId = botId,
|
||||
UseAllChats = runUseAllChats,
|
||||
ChatIds = chatIds.Where(x => x != 0).Distinct().OrderBy(x => x).ToList(),
|
||||
UserId = userId,
|
||||
PermanentBan = permanentBan,
|
||||
RequestedAtUtc = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var task = new BatchTask
|
||||
{
|
||||
TaskType = BatchTaskTypes.ExternalApiKick,
|
||||
Total = total,
|
||||
Completed = 0,
|
||||
Failed = 0,
|
||||
Config = JsonSerializer.Serialize(log, new JsonSerializerOptions { WriteIndented = true })
|
||||
};
|
||||
|
||||
var created = await TaskManagement.CreateTaskAsync(task);
|
||||
Snackbar.Add($"已提交后台任务 #{created.Id}。请到【任务中心】查看进度。", Severity.Success);
|
||||
Navigation.NavigateTo("/tasks");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"提交失败:{ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<int> CountTargetsAsync(int botId, bool runUseAllChats, IReadOnlyCollection<long> chatIds)
|
||||
{
|
||||
if (botId > 0)
|
||||
{
|
||||
var chats = (await BotManagement.GetChatsAsync(botId)).ToList();
|
||||
if (!runUseAllChats && chatIds.Count > 0)
|
||||
chats = chats.Where(c => chatIds.Contains(c.TelegramId)).ToList();
|
||||
return chats.Count;
|
||||
}
|
||||
|
||||
// botId==0: all bots (force useAllChats)
|
||||
var botsList = (await BotManagement.GetAllBotsAsync())
|
||||
.Where(b => b.IsActive)
|
||||
.OrderBy(b => b.Id)
|
||||
.ToList();
|
||||
|
||||
var total = 0;
|
||||
foreach (var b in botsList)
|
||||
{
|
||||
var chats = await BotManagement.GetChatsAsync(b.Id);
|
||||
total += chats.Count();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private static List<long> ParseChatIds(string raw)
|
||||
{
|
||||
raw = (raw ?? "").Trim();
|
||||
if (raw.Length == 0)
|
||||
return new List<long>();
|
||||
|
||||
var parts = raw
|
||||
.Replace("\r", "\n", StringComparison.Ordinal)
|
||||
.Split(new[] { ',', ';', ' ', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
var ids = new List<long>();
|
||||
foreach (var p in parts)
|
||||
{
|
||||
if (long.TryParse(p, out var v) && v != 0)
|
||||
ids.Add(v);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user