@page "/bots/channels"
@inject BotManagementService BotManagement
@inject TelegramPanel.Core.Services.Telegram.BotTelegramService BotTelegram
@inject ISnackbar Snackbar
@inject IDialogService DialogService
@inject NavigationManager Navigation
@inject IJSRuntime JS
@using TelegramPanel.Data.Entities
@using TelegramPanel.Web.Components.Dialogs
Bot 频道 - Telegram Panel
Bot 频道
-- 请选择机器人 --
@foreach (var b in bots)
{
@b.Name
}
频道 (@channels.Count)
全部分类
未分类
@foreach (var c in categories)
{
@c.Name
}
同步
导出邀请(已选)
设置管理员(已选)
批量设置分类(@selected.Count)
踢出用户(@selected.Count)
刷新
频道名称
用户名
分类
最后同步
操作
@context.Title
@if (!string.IsNullOrWhiteSpace(context.Username))
{
@context.Username
}
else
{
-
}
未分类
@foreach (var c in categories)
{
@c.Name
}
复制链接
查看详情
编辑频道
@if (selectedBotId <= 0)
{
请先选择机器人
}
else
{
暂无频道
}
@code {
[SupplyParameterFromQuery(Name = "botId")]
public int? BotIdQuery { get; set; }
private List bots = new();
private Bot? selectedBot;
private int selectedBotId = 0;
private bool loading = true;
private List categories = new();
private List channels = new();
private HashSet selected = new();
private int filterCategoryId = 0;
private string search = "";
private IEnumerable filtered => selectedBotId <= 0
? Enumerable.Empty()
: channels.Where(c =>
{
if (filterCategoryId == -1 && c.CategoryId != null)
return false;
if (filterCategoryId > 0 && c.CategoryId != filterCategoryId)
return false;
if (string.IsNullOrWhiteSpace(search))
return true;
return c.Title.Contains(search, StringComparison.OrdinalIgnoreCase)
|| (c.Username?.Contains(search, StringComparison.OrdinalIgnoreCase) ?? false);
});
protected override async Task OnInitializedAsync()
{
try
{
bots = (await BotManagement.GetAllBotsAsync()).ToList();
if (BotIdQuery is > 0 && bots.Any(x => x.Id == BotIdQuery.Value))
{
selectedBotId = BotIdQuery.Value;
await LoadBotData();
}
else if (bots.Count == 1)
{
selectedBotId = bots[0].Id;
await LoadBotData();
}
}
catch (Exception ex)
{
Snackbar.Add($"加载机器人失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
private async Task OnSelectedBotChanged(int botId)
{
if (selectedBotId == botId)
return;
selectedBotId = botId;
filterCategoryId = 0;
search = "";
selected.Clear();
if (selectedBotId <= 0)
{
selectedBot = null;
categories.Clear();
channels.Clear();
Navigation.NavigateTo("/bots/channels", replace: true);
return;
}
Navigation.NavigateTo($"/bots/channels?botId={selectedBotId}", replace: true);
await LoadBotData();
}
private async Task LoadBotData()
{
if (selectedBotId <= 0)
return;
loading = true;
try
{
selectedBot = await BotManagement.GetBotAsync(selectedBotId);
if (selectedBot == null)
{
Snackbar.Add("机器人不存在", Severity.Error);
selectedBotId = 0;
return;
}
categories = (await BotManagement.GetCategoriesAsync(selectedBotId)).ToList();
channels = (await BotManagement.GetChannelsAsync(selectedBotId)).ToList();
// 清理已选
var ids = channels.Select(x => x.Id).ToHashSet();
selected = selected.Where(x => ids.Contains(x.Id)).ToHashSet();
}
catch (Exception ex)
{
Snackbar.Add($"加载失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
private async Task Sync()
{
if (selectedBotId <= 0)
return;
loading = true;
try
{
var result = await BotTelegram.SyncBotChannelsAsync(selectedBotId, CancellationToken.None);
if (result.AppliedUpdates > 0 || result.RemovedStale > 0)
Snackbar.Add($"同步完成:应用更新 {result.AppliedUpdates} 条,清理失效 {result.RemovedStale} 个频道", Severity.Success);
else
Snackbar.Add("同步完成:没有需要处理的更新或失效频道。提示:请先把 Bot 设为频道管理员,再点同步。", Severity.Info);
await LoadBotData();
}
catch (Exception ex)
{
Snackbar.Add($"同步失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
private async Task OpenCreateCategoryDialog()
{
if (selectedBotId <= 0)
return;
var parameters = new DialogParameters
{
["BotId"] = selectedBotId
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
var dialog = DialogService.Show("新建分类", parameters, options);
var result = await dialog.Result;
if (!result.Canceled)
{
// 重新加载分类列表
await LoadBotData();
}
}
private async Task SetCategoryAsync(BotChannel channel, int? categoryId)
{
try
{
await BotManagement.SetChannelCategoryAsync(channel.Id, categoryId);
channel.CategoryId = categoryId;
Snackbar.Add("已保存分类", Severity.Success);
}
catch (Exception ex)
{
Snackbar.Add($"保存失败:{ex.Message}", Severity.Error);
}
}
private async Task CopyLinkAsync(BotChannel channel)
{
if (selectedBotId <= 0)
return;
loading = true;
try
{
var link = await BotTelegram.ExportInviteLinkAsync(selectedBotId, channel.TelegramId, CancellationToken.None);
await JS.InvokeVoidAsync("telegramPanel.copyText", link);
Snackbar.Add("已复制链接", Severity.Success);
}
catch (Exception ex)
{
Snackbar.Add($"复制失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
private async Task ExportInvites()
{
if (selectedBotId <= 0)
return;
if (selected.Count == 0)
{
Snackbar.Add("请先选择频道", Severity.Info);
return;
}
bool? result = await DialogService.ShowMessageBox(
"确认导出",
$"将为 {selected.Count} 个频道生成邀请链接并导出(需要机器人具备管理权限)。是否继续?",
yesText: "继续", cancelText: "取消");
if (result != true)
return;
var ids = string.Join(",", selected.Select(x => x.TelegramId));
var url = $"/downloads/bots/{selectedBotId}/invites.txt?ids={Uri.EscapeDataString(ids)}";
Navigation.NavigateTo(url, forceLoad: true);
await Task.CompletedTask;
}
private async Task OpenSetAdmins()
{
if (selectedBotId <= 0)
return;
if (selected.Count == 0)
{
Snackbar.Add("请先选择频道", Severity.Info);
return;
}
var parameters = new DialogParameters
{
["BotId"] = selectedBotId,
["ChannelTelegramIds"] = selected.Select(x => x.TelegramId).Distinct().ToList()
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
var dialog = DialogService.Show("批量设置管理员", parameters, options);
var result = await dialog.Result;
if (!result.Canceled)
{
// 管理员设置后不影响本地数据,但用户可能期望刷新一下
await LoadBotData();
}
}
private async Task OpenBatchSetCategory()
{
if (selectedBotId <= 0)
return;
if (selected.Count == 0)
{
Snackbar.Add("请先选择频道", Severity.Info);
return;
}
var parameters = new DialogParameters
{
["Categories"] = categories,
["SelectedCount"] = selected.Count
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
var dialog = DialogService.Show("批量设置分类", parameters, options);
var result = await dialog.Result;
if (!result.Canceled && result.Data is int categoryId)
{
loading = true;
try
{
var channelIds = selected.Select(x => x.Id).ToList();
int successCount = 0;
int failCount = 0;
foreach (var channelId in channelIds)
{
try
{
await BotManagement.SetChannelCategoryAsync(channelId, categoryId == 0 ? null : categoryId);
successCount++;
}
catch
{
failCount++;
}
}
if (failCount == 0)
{
Snackbar.Add($"已成功设置 {successCount} 个频道的分类", Severity.Success);
}
else
{
Snackbar.Add($"成功:{successCount} 个,失败:{failCount} 个", Severity.Warning);
}
// 重新加载数据
await LoadBotData();
selected.Clear();
}
catch (Exception ex)
{
Snackbar.Add($"批量设置失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
}
private async Task OpenBanMember()
{
if (selectedBotId <= 0)
return;
if (selected.Count == 0)
{
Snackbar.Add("请先选择频道", Severity.Info);
return;
}
var parameters = new DialogParameters
{
["SelectedCount"] = selected.Count
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
var dialog = DialogService.Show("移除用户", parameters, options);
var result = await dialog.Result;
if (!result.Canceled && result.Data is BotBanMemberDialog.BanUserRequest request)
{
loading = true;
try
{
var channelTelegramIds = selected.Select(x => x.TelegramId).ToList();
var banResult = await BotTelegram.BanChatMemberAsync(
selectedBotId,
channelTelegramIds,
request.UserId,
request.PermanentBan,
CancellationToken.None);
var actionText = request.PermanentBan ? "封禁" : "踢出";
if (banResult.Failures.Count == 0)
{
Snackbar.Add($"已成功从 {banResult.SuccessCount} 个频道{actionText}用户 {request.UserId}", Severity.Success);
}
else
{
var msg = $"成功:{banResult.SuccessCount} 个,失败:{banResult.Failures.Count} 个";
if (banResult.Failures.Count > 0)
{
var firstError = banResult.Failures.First();
msg += $"(首个失败原因:{firstError.Value})";
}
Snackbar.Add(msg, Severity.Warning);
}
selected.Clear();
}
catch (Exception ex)
{
Snackbar.Add($"操作失败:{ex.Message}", Severity.Error);
}
finally
{
loading = false;
}
}
}
private async Task ShowDetailsAsync(BotChannel channel)
{
if (selectedBotId <= 0)
return;
var parameters = new DialogParameters
{
["BotId"] = selectedBotId,
["ChannelTelegramId"] = channel.TelegramId
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Large, FullWidth = true };
DialogService.Show("频道详情", parameters, options);
await Task.CompletedTask;
}
private async Task EditChannelAsync(BotChannel channel)
{
if (selectedBotId <= 0)
return;
var parameters = new DialogParameters
{
["BotId"] = selectedBotId,
["ChannelTelegramId"] = channel.TelegramId
};
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Medium, FullWidth = true };
var dialog = DialogService.Show("编辑频道", parameters, options);
var result = await dialog.Result;
if (!result.Canceled)
await LoadBotData();
}
}