feat(bot-channels): 删除频道时可勾选要移除的Bot绑定

This commit is contained in:
meoacgx committed 2026-03-04 22:45:08 +08:00
1 parent 62a4519c5e
commit ace820bb66
5 files changed
+277 -26

No files matched your search

@@ -0,0 +1,147 @@
@namespace TelegramPanel.Web.Components.Dialogs
@using TelegramPanel.Data.Entities
<MudDialog>
<DialogContent>
<MudStack Spacing="2">
<MudText Typo="Typo.body2">@Prompt</MudText>
@if (options.Count == 0)
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined">
当前没有可删除的 Bot 绑定。
</MudAlert>
}
else
{
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Primary"
OnClick="SelectCurrentBot"
Disabled="@(!options.Any(x => x.Id == CurrentBotId))">
仅当前 Bot
</MudButton>
<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Default" OnClick="SelectAll">
全选
</MudButton>
<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Default" OnClick="ClearAll">
清空
</MudButton>
<MudSpacer />
<MudChip T="string" Size="Size.Small" Color="Color.Info">
已选 @selectedBotIds.Count / @options.Count
</MudChip>
</MudStack>
<MudPaper Class="pa-2" Outlined="true">
<MudStack Spacing="1">
@foreach (var bot in options)
{
<MudCheckBox T="bool"
Label="@BuildBotLabel(bot)"
Value="@IsChecked(bot.Id)"
ValueChanged="@(value => SetChecked(bot.Id, value))" />
}
</MudStack>
</MudPaper>
}
</MudStack>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Text" Color="Color.Default" OnClick="Cancel">取消</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="Confirm"
Disabled="@(options.Count == 0 || selectedBotIds.Count == 0)">
删除选中绑定
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] private MudDialogInstance MudDialog { get; set; } = default!;
[Parameter] public string Prompt { get; set; } = "";
[Parameter] public List<Bot> Bots { get; set; } = new();
[Parameter] public int CurrentBotId { get; set; }
private List<Bot> options = new();
private HashSet<int> selectedBotIds = new();
protected override void OnParametersSet()
{
options = (Bots ?? new List<Bot>())
.Where(x => x.Id > 0)
.GroupBy(x => x.Id)
.Select(x => x.First())
.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase)
.ToList();
selectedBotIds = new HashSet<int>();
if (options.Count == 0)
return;
if (CurrentBotId > 0 && options.Any(x => x.Id == CurrentBotId))
{
selectedBotIds.Add(CurrentBotId);
return;
}
foreach (var bot in options)
selectedBotIds.Add(bot.Id);
}
private bool IsChecked(int botId) => selectedBotIds.Contains(botId);
private void SetChecked(int botId, bool selected)
{
if (selected)
selectedBotIds.Add(botId);
else
selectedBotIds.Remove(botId);
}
private void SelectCurrentBot()
{
selectedBotIds.Clear();
if (CurrentBotId > 0)
selectedBotIds.Add(CurrentBotId);
}
private void SelectAll()
{
selectedBotIds.Clear();
foreach (var bot in options)
selectedBotIds.Add(bot.Id);
}
private void ClearAll()
{
selectedBotIds.Clear();
}
private static string BuildBotLabel(Bot bot)
{
var name = string.IsNullOrWhiteSpace(bot.Name) ? $"Bot {bot.Id}" : bot.Name.Trim();
var username = string.IsNullOrWhiteSpace(bot.Username) ? null : "@" + bot.Username.Trim().TrimStart('@');
return string.IsNullOrWhiteSpace(username) ? name : $"{name}({username})";
}
private void Cancel()
{
MudDialog.Cancel();
}
private void Confirm()
{
var result = selectedBotIds
.Where(x => x > 0)
.OrderBy(x => x)
.ToList();
if (result.Count == 0)
{
MudDialog.Cancel();
return;
}
MudDialog.Close(DialogResult.Ok(result));
}
}
@@ -88,7 +88,7 @@
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenSetAdmins">批量设置管理员(机器人/ID)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBatchSetCategory">批量设置分类(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBanMember">踢出用户(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="DeleteSelectedChannelsAsync">全局删除频道(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="DeleteSelectedChannelsAsync">删除频道(已选)</MudMenuItem>
</MudMenu>
@if (selected.Count > 0)
@@ -157,7 +157,7 @@
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" Color="Color.Primary"
OnClick="@(async () => await EditChannelAsync(context))" Title="编辑频道" />
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error"
OnClick="@(async () => await DeleteSingleChannelAsync(context))" title="全局删除频道" />
OnClick="@(async () => await DeleteSingleChannelAsync(context))" title="删除频道" />
</MudStack>
</MudTd>
</RowTemplate>
@@ -484,19 +484,18 @@
return;
var channelName = string.IsNullOrWhiteSpace(channel.Title) ? channel.TelegramId.ToString() : channel.Title;
bool? ok = await DialogService.ShowMessageBox(
"确认删除",
$"确定全局删除频道“{channelName}”吗?该频道会从所有 Bot 的频道列表中移除。",
yesText: "删除", cancelText: "取消");
if (ok != true)
var selectedBotIds = await SelectBotsForDeleteAsync(new[] { channel.TelegramId }, channelName);
if (selectedBotIds == null || selectedBotIds.Count == 0)
return;
loading = true;
try
{
await BotManagement.DeleteChannelGloballyByTelegramIdAsync(channel.TelegramId);
Snackbar.Add($"已全局删除频道:{channelName}", Severity.Success);
var removed = await BotManagement.DeleteChannelBindingsByBotIdsAsync(channel.TelegramId, selectedBotIds);
if (removed > 0)
Snackbar.Add($"已删除频道绑定:{channelName}(删除 {removed} 条绑定)", Severity.Success);
else
Snackbar.Add($"未删除任何绑定:{channelName}(所选 Bot 可能未绑定该频道)", Severity.Info);
await ReloadTable();
}
catch (Exception ex)
@@ -520,26 +519,24 @@
return;
}
bool? ok = await DialogService.ShowMessageBox(
"确认批量删除",
$"确定全局删除已选 {selected.Count} 个频道吗?这些频道会从所有 Bot 的频道列表中移除。",
yesText: "删除", cancelText: "取消");
if (ok != true)
var ids = selected.Select(x => x.TelegramId).Distinct().ToList();
var selectedBotIds = await SelectBotsForDeleteAsync(ids, null);
if (selectedBotIds == null || selectedBotIds.Count == 0)
return;
loading = true;
try
{
var ids = selected.Select(x => x.TelegramId).Distinct().ToList();
var success = 0;
var failed = 0;
var removedTotal = 0;
foreach (var chatId in ids)
{
try
{
await BotManagement.DeleteChannelGloballyByTelegramIdAsync(chatId);
var removed = await BotManagement.DeleteChannelBindingsByBotIdsAsync(chatId, selectedBotIds);
removedTotal += removed;
success++;
}
catch
@@ -550,11 +547,11 @@
if (failed == 0)
{
Snackbar.Add($"批量删除完成:成功 {success} 个频道", Severity.Success);
Snackbar.Add($"批量删除完成:处理 {success} 个频道,删除绑定 {removedTotal} 条", Severity.Success);
}
else
{
Snackbar.Add($"批量删除完成:成功 {success} 个,失败 {failed} 个", Severity.Warning);
Snackbar.Add($"批量删除完成:处理成功 {success} 个,失败 {failed} 个,删除绑定 {removedTotal} 条", Severity.Warning);
}
await ReloadTable();
@@ -569,6 +566,53 @@
}
}
private async Task<List<int>?> SelectBotsForDeleteAsync(IReadOnlyCollection<long> channelTelegramIds, string? singleChannelName)
{
var ids = channelTelegramIds.Where(x => x != 0).Distinct().ToList();
if (ids.Count == 0)
return null;
var botMap = new Dictionary<int, Bot>();
foreach (var telegramId in ids)
{
var boundBots = await BotManagement.GetChannelBoundBotsAsync(telegramId);
foreach (var bot in boundBots)
{
if (bot.Id > 0 && !botMap.ContainsKey(bot.Id))
botMap[bot.Id] = bot;
}
}
if (botMap.Count == 0)
{
Snackbar.Add("未找到可删除的 Bot 绑定", Severity.Info);
return null;
}
var prompt = ids.Count == 1
? $"频道“{singleChannelName ?? ids[0].ToString()}”当前绑定了以下 Bot,请勾选要删除的绑定:"
: $"已选 {ids.Count} 个频道。请勾选要批量删除的 Bot 绑定(未绑定的频道会自动跳过)。";
var parameters = new DialogParameters
{
["Prompt"] = prompt,
["Bots"] = botMap.Values.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase).ToList(),
["CurrentBotId"] = selectedBotId
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
var dialog = DialogService.Show<BotChannelDeleteBindingsDialog>("选择要删除的 Bot 绑定", parameters, options);
var result = await dialog.Result;
if (result.Canceled)
return null;
if (result.Data is List<int> selectedIds)
return selectedIds.Where(x => x > 0).Distinct().ToList();
if (result.Data is IReadOnlyList<int> selectedReadOnlyIds)
return selectedReadOnlyIds.Where(x => x > 0).Distinct().ToList();
return null;
}
private async Task OpenCreateCategoryDialog()
{
if (selectedBotId <= 0)