@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(); } }