Files
Telegram-Panel/src/TelegramPanel.Web/Components/Pages/AccountImport.razor
T
2025-12-19 13:44:39 +08:00

304 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@page "/accounts/import"
@inject AccountImportService AccountImportService
@inject IConfiguration Configuration
@inject ISnackbar Snackbar
<PageTitle>导入账号 - Telegram Panel</PageTitle>
<MudText Typo="Typo.h4" Class="mb-4">导入账号</MudText>
<MudGrid>
<MudItem xs="12">
<MudCard Class="mb-4">
<MudCardHeader>
<MudText Typo="Typo.h6">压缩包导入(推荐)</MudText>
</MudCardHeader>
<MudCardContent>
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
支持批量导入账号压缩包:每个账号一个独立子文件夹,文件夹内包含一个 <strong>.json</strong> + 一个 <strong>.session</strong>。
</MudAlert>
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="OnZipFilesChanged" Accept=".zip" MaximumFileCount="1">
<ActivatorContent>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.FolderZip" Class="mt-3">
选择 Zip 压缩包
</MudButton>
</ActivatorContent>
</MudFileUpload>
@if (zipFile != null)
{
<MudText Typo="Typo.body2" Class="mt-3">已选择:@zipFile.Name(@zipFile.Size bytes)</MudText>
}
<MudButton Variant="Variant.Filled" Color="Color.Success" FullWidth="true"
Disabled="@(zipFile == null || importingZip)" Class="mt-4"
OnClick="@(async (MouseEventArgs _) => await ImportZip())">
@if (importingZip)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="mr-2" />
<span>导入中...</span>
}
else
{
<span>开始导入 Zip</span>
}
</MudButton>
</MudCardContent>
</MudCard>
</MudItem>
<MudItem xs="12" md="6">
<MudCard>
<MudCardHeader>
<MudText Typo="Typo.h6">Session 文件导入</MudText>
</MudCardHeader>
<MudCardContent>
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="OnFilesChanged" Accept=".session" MaximumFileCount="100">
<ActivatorContent>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload" Class="mt-4">
选择 Session 文件
</MudButton>
</ActivatorContent>
</MudFileUpload>
@if (selectedFiles.Any())
{
<MudText Typo="Typo.body2" Class="mt-3">已选择 @selectedFiles.Count 个文件</MudText>
<MudList T="string" Dense="true">
@foreach (var file in selectedFiles)
{
<MudListItem T="string" Icon="@Icons.Material.Filled.Description">@file.Name</MudListItem>
}
</MudList>
}
<MudButton Variant="Variant.Filled" Color="Color.Success" FullWidth="true"
Disabled="@(!selectedFiles.Any() || importing)" Class="mt-4"
OnClick="@(async (MouseEventArgs _) => await ImportSessionFiles())">
@if (importing)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="mr-2" />
<span>导入中...</span>
}
else
{
<span>开始导入</span>
}
</MudButton>
</MudCardContent>
</MudCard>
</MudItem>
<MudItem xs="12" md="6">
<MudCard>
<MudCardHeader>
<MudText Typo="Typo.h6">StringSession 导入</MudText>
</MudCardHeader>
<MudCardContent>
<MudTextField @bind-Value="sessionString" Label="Session String (Base64)" Variant="Variant.Outlined"
Lines="5" Required="true" Class="mt-3" />
<MudButton Variant="Variant.Filled" Color="Color.Success" FullWidth="true"
Disabled="@(string.IsNullOrEmpty(sessionString) || importingString)" Class="mt-4"
OnClick="@(async (MouseEventArgs _) => await ImportStringSession())">
@if (importingString)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="mr-2" />
<span>导入中...</span>
}
else
{
<span>导入 StringSession</span>
}
</MudButton>
</MudCardContent>
</MudCard>
</MudItem>
</MudGrid>
@if (importResults.Any())
{
<MudCard Class="mt-4">
<MudCardHeader>
<MudText Typo="Typo.h6">导入结果</MudText>
</MudCardHeader>
<MudCardContent>
<MudTable Items="@importResults" Hover="true">
<HeaderContent>
<MudTh>手机号</MudTh>
<MudTh>用户ID</MudTh>
<MudTh>用户名</MudTh>
<MudTh>状态</MudTh>
<MudTh>消息</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="手机号">@(context.Phone ?? "-")</MudTd>
<MudTd DataLabel="用户ID">@(context.UserId?.ToString() ?? "-")</MudTd>
<MudTd DataLabel="用户名">@(context.Username ?? "-")</MudTd>
<MudTd DataLabel="状态">
<MudChip T="string" Size="Size.Small" Color="@(context.Success ? Color.Success : Color.Error)">
@(context.Success ? "成功" : "失败")
</MudChip>
</MudTd>
<MudTd DataLabel="消息">@(context.Success ? "成功" : (context.Error ?? "失败"))</MudTd>
</RowTemplate>
</MudTable>
</MudCardContent>
</MudCard>
}
@code {
private List<IBrowserFile> selectedFiles = new();
private bool importing = false;
private IBrowserFile? zipFile;
private bool importingZip = false;
private string sessionString = "";
private bool importingString = false;
private List<ImportResult> importResults = new();
private bool TryGetTelegramApi(out int apiId, out string apiHash)
{
apiHash = Configuration["Telegram:ApiHash"] ?? "";
return int.TryParse(Configuration["Telegram:ApiId"], out apiId)
&& apiId > 0
&& !string.IsNullOrWhiteSpace(apiHash);
}
private void OnFilesChanged(IReadOnlyList<IBrowserFile> files)
{
selectedFiles = files.ToList();
}
private void OnZipFilesChanged(IReadOnlyList<IBrowserFile> files)
{
zipFile = files.FirstOrDefault();
}
private async Task ImportZip()
{
if (zipFile == null)
{
Snackbar.Add("请先选择 Zip 压缩包", Severity.Error);
return;
}
importingZip = true;
importResults.Clear();
try
{
var results = await AccountImportService.ImportFromZipAsync(zipFile);
importResults.AddRange(results);
var successCount = results.Count(r => r.Success);
var failureCount = results.Count - successCount;
if (successCount > 0)
Snackbar.Add($"成功导入 {successCount} 个账号", Severity.Success);
if (failureCount > 0)
Snackbar.Add($"{failureCount} 个账号导入失败", Severity.Warning);
zipFile = null;
}
catch (Exception ex)
{
Snackbar.Add($"导入失败:{ex.Message}", Severity.Error);
}
finally
{
importingZip = false;
}
}
private async Task ImportSessionFiles()
{
if (!TryGetTelegramApi(out var apiId, out var apiHash))
{
Snackbar.Add("请先在【系统设置】中配置全局 Telegram API(ApiId/ApiHash)", Severity.Error);
return;
}
importing = true;
importResults.Clear();
try
{
var results = await AccountImportService.ImportFromBrowserFilesAsync(
selectedFiles,
apiId,
apiHash
);
importResults.AddRange(results);
var successCount = results.Count(r => r.Success);
var failureCount = results.Count - successCount;
if (successCount > 0)
{
Snackbar.Add($"成功导入 {successCount} 个账号", Severity.Success);
}
if (failureCount > 0)
{
Snackbar.Add($"{failureCount} 个账号导入失败", Severity.Warning);
}
// 清空已选文件
selectedFiles.Clear();
}
catch (Exception ex)
{
Snackbar.Add($"导入失败:{ex.Message}", Severity.Error);
}
finally
{
importing = false;
}
}
private async Task ImportStringSession()
{
if (!TryGetTelegramApi(out var apiId, out var apiHash))
{
Snackbar.Add("请先在【系统设置】中配置全局 Telegram API(ApiId/ApiHash)", Severity.Error);
return;
}
importingString = true;
try
{
var result = await AccountImportService.ImportFromStringSessionAsync(
sessionString,
apiId,
apiHash
);
importResults.Add(result);
if (result.Success)
{
Snackbar.Add($"导入成功:{result.Phone}", Severity.Success);
sessionString = "";
}
else
{
Snackbar.Add($"导入失败:{result.Error ?? "未知错误"}", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"导入失败:{ex.Message}", Severity.Error);
}
finally
{
importingString = false;
}
}
}