fix: 完善订阅加群任务并补充文档
This commit is contained in:
1 parent
76496f935e
commit
016a38949a
4 files changed
+77
-9
No files matched your search
@@ -12,11 +12,35 @@
|
||||
- 📥 **多账号批量导入/登录**:支持 Session/压缩包导入;支持手机号验证码登录与 2FA 密码
|
||||
- 🔁 **账号维度一键切换操作**:选择不同账号创建频道/群组、查看与管理账号创建的数据
|
||||
- 👥 **批量运营能力**:批量邀请成员/机器人、批量设置管理员、导出链接等高频操作
|
||||
- 🧩 **用户任务:批量订阅/加群**:任务中心新建「用户任务 → 批量订阅/加群」,支持按账号分类筛选;账号列表支持单账号“进群/订阅”入口(多链接换行分隔)
|
||||
- 🔐 **二级密码(2FA)与找回邮箱**:支持单个/批量修改二级密码;支持绑定/换绑 2FA 找回邮箱(验证码确认)
|
||||
- 🧯 **忘记二级密码可申请重置**:支持单个或批量向 Telegram 提交“忘记密码重置”申请(通常等待 7 天后可重新设置)
|
||||
- 🪪 **账号资料管理**:支持单账号编辑昵称/Bio/用户名/头像;支持批量修改昵称(自动追加手机号后 4 位便于区分)与批量修改 Bio
|
||||
- 🤖 **Bot 频道管理**:用于管理“频道创建人不在系统中”的频道(把 Bot 设为管理员即可纳入管理),支持批量导出链接、批量设置管理员(踢人能力可扩展)
|
||||
|
||||
## 批量订阅/加群(用户任务)
|
||||
|
||||
说明:这是**用户账号**任务(Bot 无法主动加群/订阅)。
|
||||
|
||||
### 入口 1:任务中心批量执行
|
||||
|
||||
1. 进入「任务中心」→ 点击「新建任务」
|
||||
2. 选择:任务分类 =「用户任务」,任务类型 =「批量订阅/加群」
|
||||
3. 选择执行账号(支持按**账号分类**筛选 + 搜索)
|
||||
4. 粘贴链接/用户名(**换行分隔**),设置间隔(建议 1500–4000ms)
|
||||
5. 提交后到「任务中心」查看进度与结果
|
||||
|
||||
### 入口 2:账号列表单账号执行
|
||||
|
||||
在「账号列表」每行账号的操作区点击「进群/订阅」,输入多个链接/用户名(换行分隔)后确认即可提交后台任务。
|
||||
|
||||
### 支持的链接/格式
|
||||
|
||||
- `https://t.me/xxx`
|
||||
- `t.me/+hash`
|
||||
- `@username` / `username`
|
||||
- `tg://join?invite=hash`
|
||||
|
||||
|
||||
## 🧊 防冻结指南(新号必看)
|
||||
|
||||
|
||||
@@ -659,8 +659,8 @@ public class AccountTelegramToolsService
|
||||
|
||||
var title = chat switch
|
||||
{
|
||||
Channel c => c.title,
|
||||
Chat c => c.title,
|
||||
TL.Channel c => c.title,
|
||||
TL.Chat c => c.title,
|
||||
_ => null
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@namespace TelegramPanel.Web.Components.Dialogs
|
||||
@inject AccountManagementService AccountManagement
|
||||
@inject AccountCategoryManagementService CategoryManagement
|
||||
@inject TelegramPanel.Core.Services.AccountRiskService RiskService
|
||||
@inject BatchTaskManagementService TaskManagement
|
||||
@inject ISnackbar Snackbar
|
||||
@@ -43,7 +44,7 @@
|
||||
<MudDivider Class="my-2" />
|
||||
|
||||
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined" Dense="true">
|
||||
批量订阅频道/加群(用户任务):支持输入多个链接/用户名,换行分隔。支持:<b>https://t.me/xxx</b>、<b>t.me/+hash</b>、<b>@username</b>、<b>username</b>、<b>tg://join?invite=hash</b>。
|
||||
批量订阅频道/加群(用户任务):支持输入多个链接/用户名,换行分隔。支持:<b>https://t.me/xxx</b>、<b>t.me/+hash</b>、<b>@@username</b>、<b>username</b>、<b>tg://join?invite=hash</b>。
|
||||
</MudAlert>
|
||||
|
||||
<MudTextField @bind-Value="linksText" Label="频道/群链接列表(换行分隔)" Variant="Variant.Outlined" Lines="8"
|
||||
@@ -55,12 +56,26 @@
|
||||
<MudStack direction="Row" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudText Typo="Typo.subtitle2">选择执行账号:@selectedAccounts.Count / @accounts.Count</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" OnClick="SelectAll" Disabled="@(accounts.Count == 0)">全选</MudButton>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" OnClick="SelectAll" Disabled="@(accounts.Count == 0)">全选当前筛选</MudButton>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Secondary" OnClick="ClearSelection" Disabled="@(selectedAccounts.Count == 0)">清空</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudTextField @bind-Value="accountSearch" Placeholder="搜索账号(手机号/昵称/用户名)" Variant="Variant.Outlined"
|
||||
Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" Immediate="true" />
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudSelect @bind-Value="filterAccountCategoryId" Label="账号分类筛选" Variant="Variant.Outlined" Dense="true" Style="min-width: 160px;">
|
||||
<MudSelectItem Value="0">全部分类</MudSelectItem>
|
||||
<MudSelectItem Value="-1">未分类</MudSelectItem>
|
||||
@foreach (var c in categories)
|
||||
{
|
||||
<MudSelectItem Value="@c.Id">@c.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="8">
|
||||
<MudTextField @bind-Value="accountSearch" Placeholder="搜索账号(手机号/昵称/用户名)" Variant="Variant.Outlined"
|
||||
Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" Immediate="true" />
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudTable Items="@FilteredAccounts" Dense="true" Hover="true" Breakpoint="Breakpoint.Sm"
|
||||
MultiSelection="true" @bind-SelectedItems="selectedAccounts" Loading="@loadingAccounts">
|
||||
@@ -68,11 +83,13 @@
|
||||
<MudTh>手机号</MudTh>
|
||||
<MudTh>昵称</MudTh>
|
||||
<MudTh>用户名</MudTh>
|
||||
<MudTh>分类</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="手机号">@context.Phone</MudTd>
|
||||
<MudTd DataLabel="昵称">@(string.IsNullOrWhiteSpace(context.Nickname) ? "-" : context.Nickname)</MudTd>
|
||||
<MudTd DataLabel="用户名">@(string.IsNullOrWhiteSpace(context.Username) ? "-" : "@" + context.Username)</MudTd>
|
||||
<MudTd DataLabel="分类">@GetAccountCategoryName(context.CategoryId)</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText>暂无账号</MudText>
|
||||
@@ -150,7 +167,9 @@
|
||||
|
||||
private bool loadingAccounts;
|
||||
private List<Account> accounts = new();
|
||||
private List<AccountCategory> categories = new();
|
||||
private string accountSearch = "";
|
||||
private int filterAccountCategoryId = 0;
|
||||
private HashSet<Account> selectedAccounts = new();
|
||||
|
||||
private IEnumerable<TaskOption> AvailableOptions => Options.Where(o => o.Category == selectedCategory);
|
||||
@@ -159,6 +178,11 @@
|
||||
private IEnumerable<Account> FilteredAccounts =>
|
||||
accounts.Where(a =>
|
||||
{
|
||||
if (filterAccountCategoryId > 0 && a.CategoryId != filterAccountCategoryId)
|
||||
return false;
|
||||
if (filterAccountCategoryId == -1 && a.CategoryId != null)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(accountSearch))
|
||||
return true;
|
||||
var q = accountSearch.Trim();
|
||||
@@ -170,9 +194,23 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
EnsureTaskTypeValid();
|
||||
await LoadCategories();
|
||||
await LoadAccounts();
|
||||
}
|
||||
|
||||
private async Task LoadCategories()
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = await CategoryManagement.GetAllCategoriesAsync();
|
||||
categories = list.OrderBy(c => c.Id).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
categories = new List<AccountCategory>();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadAccounts()
|
||||
{
|
||||
loadingAccounts = true;
|
||||
@@ -201,9 +239,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectAll() => selectedAccounts = accounts.ToHashSet();
|
||||
private void SelectAll() => selectedAccounts = FilteredAccounts.ToHashSet();
|
||||
private void ClearSelection() => selectedAccounts = new HashSet<Account>();
|
||||
|
||||
private string GetAccountCategoryName(int? categoryId)
|
||||
{
|
||||
if (categoryId is not > 0)
|
||||
return "未分类";
|
||||
return categories.FirstOrDefault(c => c.Id == categoryId)?.Name ?? $"#{categoryId}";
|
||||
}
|
||||
|
||||
private async Task Create()
|
||||
{
|
||||
if (creating)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined" Dense="true">
|
||||
将使用指定账号订阅频道/加入群组。支持输入多个链接/用户名,换行分隔。
|
||||
<MudText Typo="Typo.body2" Class="mt-1">
|
||||
支持:<b>https://t.me/xxx</b>、<b>t.me/+hash</b>、<b>@username</b>、<b>username</b>、<b>tg://join?invite=hash</b>
|
||||
支持:<b>https://t.me/xxx</b>、<b>t.me/+hash</b>、<b>@@username</b>、<b>username</b>、<b>tg://join?invite=hash</b>
|
||||
</MudText>
|
||||
</MudAlert>
|
||||
|
||||
@@ -155,4 +155,3 @@
|
||||
|
||||
private void Cancel() => MudDialog.Close();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user