fix(web): 优化账号/频道列表 UI(移动端)

This commit is contained in:
meoacgx committed 2025-12-27 00:18:58 +08:00
1 parent 42f3161748
commit 3b2971905f
3 files changed
+295 -277

No files matched your search

@@ -15,86 +15,69 @@
<MudText Typo="Typo.h4" Class="mb-4 tp-page-title">账号列表</MudText>
<MudPaper Class="pa-4 mb-4" Elevation="0" Outlined="true">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudSelect @bind-Value="filterCategoryId" @bind-Value:after="OnFiltersChanged" Label="分类" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs"
Style="min-width: 180px; flex: 0 1 220px;">
<MudSelectItem Value="0">全部分类</MudSelectItem>
@foreach (var c in categories)
{
<MudSelectItem Value="@c.Id">@c.Name</MudSelectItem>
}
</MudSelect>
<MudTextField @bind-Value="searchString" Placeholder="搜索账号..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0 tp-input-full-xs"
Style="min-width: 200px; flex: 1; max-width: 400px;"
Immediate="true" @bind-Value:after="OnSearchChanged" />
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Refresh"
Disabled="@loading" OnClick="ReloadTable" Size="Size.Small" Class="tp-input-full-xs">
刷新列表
</MudButton>
</MudStack>
</MudPaper>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="mb-2" Style="flex-wrap: wrap;">
<MudButton Variant="Variant.Outlined" Color="Color.Primary" StartIcon="@SelectionToggleIcon"
Disabled="@(loading || accounts.Count == 0)" OnClick="CycleSelectionToggle" Size="Size.Small">
@SelectionToggleText
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@loading" OnClick="BatchRefreshTelegramStatus" Size="Size.Small">
批量刷新状态
</MudButton>
<MudMenu Label="批量操作" Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Size="Size.Small" Disabled="@loading" Dense="true" EndIcon="@Icons.Material.Filled.KeyboardArrowDown">
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchJoinSubscribe">批量加群/订阅(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchLeaveUnsubscribe">批量退群/退订(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeTwoFactorPassword">修改二级密码(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="BatchKickAllOtherDevices">批量踢出所有其他设备(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchSetAccountCategory">批量修改分类(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeNickname">批量改昵称(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeUsername">批量改用户名(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeBio">批量改Bio(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="DeleteSelectedAccounts">删除已选</MudMenuItem>
<MudMenuItem OnClick="ExportSelectedAccounts">导出已选</MudMenuItem>
<MudMenuItem OnClick="ExportCurrentPageAccounts">导出当前页</MudMenuItem>
</MudMenu>
@if (selectedAccounts.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info" Class="ml-2">已选 @selectedAccounts.Count</MudChip>
}
else
{
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="ml-2">共 @totalCount 个账号</MudText>
}
</MudStack>
<MudCard>
<MudCardContent>
<MudTable ServerData="LoadAccountsServerData" Hover="true" Breakpoint="Breakpoint.Sm" Loading="@loading"
Class="tp-table"
MultiSelection="true" @bind-SelectedItems="selectedAccounts" @ref="_table">
<ToolBarContent>
<MudStack Spacing="1" Style="width: 100%;">
<div class="tp-toolbar-row tp-flex-wrap">
<div class="tp-toolbar-left">
<MudText Typo="Typo.h6">已导入账号 (@totalCount)</MudText>
@if (selectedAccounts.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info">已选 @selectedAccounts.Count</MudChip>
}
</div>
<div class="tp-toolbar-right">
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Refresh"
Disabled="@loading" OnClick="ReloadTable" Size="Size.Small">
刷新
</MudButton>
<MudMenu Dense="true" Disabled="@loading">
<ActivatorContent>
<MudButton Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Class="tp-nowrap"
Disabled="@loading" Size="Size.Small">
批量操作
</MudButton>
</ActivatorContent>
<ChildContent>
<MudMenuItem Disabled="@(accounts.Count == 0)" Icon="@SelectionToggleIcon" OnClick="CycleSelectionToggle">@SelectionToggleText</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Sync" Disabled="@loading" OnClick="BatchRefreshTelegramStatus">批量刷新状态</MudMenuItem>
<MudDivider />
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchJoinSubscribe">批量加群/订阅(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchLeaveUnsubscribe">批量退群/退订(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeTwoFactorPassword">修改二级密码(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="BatchKickAllOtherDevices">批量踢出所有其他设备(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchSetAccountCategory">批量修改分类(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeNickname">批量改昵称(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeUsername">批量改用户名(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="OpenBatchChangeBio">批量改Bio(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedAccounts.Count == 0)" OnClick="DeleteSelectedAccounts">删除已选</MudMenuItem>
<MudMenuItem OnClick="ExportSelectedAccounts">导出已选</MudMenuItem>
<MudMenuItem OnClick="ExportCurrentPageAccounts">导出当前页</MudMenuItem>
</ChildContent>
</MudMenu>
</div>
</div>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Class="tp-flex-wrap" Style="gap: 6px;">
<MudSelect @bind-Value="filterCategoryId" @bind-Value:after="OnFiltersChanged" Label="分类" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs"
Style="min-width: 180px; flex: 0 1 220px;">
<MudSelectItem Value="0">全部分类</MudSelectItem>
@foreach (var c in categories)
{
<MudSelectItem Value="@c.Id">@c.Name</MudSelectItem>
}
</MudSelect>
<MudTextField @bind-Value="searchString" Placeholder="搜索账号..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0 tp-input-full-xs"
Style="min-width: 220px; flex: 1 1 260px;"
Immediate="true" @bind-Value:after="OnSearchChanged" />
<MudButton Variant="Variant.Outlined" Color="Color.Primary" StartIcon="@SelectionToggleIcon"
Class="tp-hide-xs tp-nowrap"
Disabled="@(loading || accounts.Count == 0)" OnClick="CycleSelectionToggle" Size="Size.Small">
@SelectionToggleText
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Class="tp-hide-xs tp-nowrap"
Disabled="@loading" OnClick="BatchRefreshTelegramStatus" Size="Size.Small">
批量刷新状态
</MudButton>
</MudStack>
<MudDivider Class="mt-2" />
</MudStack>
</ToolBarContent>
<HeaderContent>
<MudTh>手机号</MudTh>
<MudTh>昵称</MudTh>
@@ -105,7 +88,7 @@
<MudTh>状态</MudTh>
<MudTh>Telegram 状态</MudTh>
<MudTh>最后数据同步</MudTh>
<MudTh>操作</MudTh>
<MudTh Style="min-width: 180px;">操作</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="手机号">@context.DisplayPhone</MudTd>
@@ -146,53 +129,31 @@
</MudTd>
<MudTd DataLabel="最后数据同步"><PanelTime Value="context.LastSyncAt" /></MudTd>
<MudTd DataLabel="操作">
<div class="tp-actions-inline">
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudIconButton Icon="@Icons.Material.Filled.Info" Size="Size.Small" Color="Color.Info"
OnClick="@(() => ShowDetails(context))" Title="查看详情" />
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" Color="Color.Info"
Disabled="@loading" OnClick="@(() => OpenEditUserProfile(context))" Title="编辑用户资料" />
<MudIconButton Icon="@Icons.Material.Filled.Sync" Size="Size.Small" Color="Color.Primary"
Disabled="@loading" OnClick="@(() => RefreshTelegramStatus(context))" Title="刷新 Telegram 状态" />
<MudIconButton Icon="@Icons.Material.Filled.GroupAdd" Size="Size.Small" Color="Color.Success"
Disabled="@loading" OnClick="@(() => OpenJoinSubscribe(context))" Title="加群/订阅" />
<MudIconButton Icon="@Icons.Material.Filled.ExitToApp" Size="Size.Small" Color="Color.Warning"
Disabled="@loading" OnClick="@(() => OpenLeaveUnsubscribe(context))" Title="退群/退订" />
<MudIconButton Icon="@Icons.Material.Filled.MarkEmailUnread" Size="Size.Small" Color="Color.Info"
Disabled="@loading" OnClick="@(() => OpenSystemInbox(context))" Title="系统通知(验证码)" />
<MudIconButton Icon="@Icons.Material.Filled.Devices" Size="Size.Small" Color="Color.Info"
Disabled="@loading" OnClick="@(() => OpenDevices(context))" Title="在线设备" />
<MudIconButton Icon="@Icons.Material.Filled.Password" Size="Size.Small" Color="Color.Warning"
Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorPassword(context))" Title="修改二级密码" />
<MudIconButton Icon="@Icons.Material.Filled.AlternateEmail" Size="Size.Small" Color="Color.Warning"
Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorRecoveryEmail(context))" Title="绑定/换绑找回邮箱" />
<MudIconButton Icon="@(context.IsActive ? Icons.Material.Filled.Stop : Icons.Material.Filled.PlayArrow)"
Size="Size.Small" Color="@(context.IsActive ? Color.Warning : Color.Success)"
OnClick="@(() => ToggleActive(context))"
Title="@(context.IsActive ? "停用" : "启用")" />
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error"
OnClick="@(() => DeleteAccount(context))" Title="删除账号" />
</div>
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small" Class="tp-actions-menu">
<MudMenuItem Icon="@Icons.Material.Filled.Info" OnClick="@(() => ShowDetails(context))">查看详情</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Edit" Disabled="@loading" OnClick="@(() => OpenEditUserProfile(context))">编辑用户资料</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Sync" Disabled="@loading" OnClick="@(() => RefreshTelegramStatus(context))">刷新 Telegram 状态</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.GroupAdd" Disabled="@loading" OnClick="@(() => OpenJoinSubscribe(context))">加群/订阅</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.ExitToApp" Disabled="@loading" OnClick="@(() => OpenLeaveUnsubscribe(context))">退群/退订</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.MarkEmailUnread" Disabled="@loading" OnClick="@(() => OpenSystemInbox(context))">系统通知(验证码)</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Devices" Disabled="@loading" OnClick="@(() => OpenDevices(context))">在线设备</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Password" Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorPassword(context))">修改二级密码</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.AlternateEmail" Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorRecoveryEmail(context))">绑定/换绑找回邮箱</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@(context.IsActive ? Icons.Material.Filled.Stop : Icons.Material.Filled.PlayArrow)"
Disabled="@loading"
OnClick="@(() => ToggleActive(context))">
@(context.IsActive ? "停用" : "启用")
</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Delete" Disabled="@loading" OnClick="@(() => DeleteAccount(context))">删除账号</MudMenuItem>
</MudMenu>
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small" Dense="true">
<MudMenuItem Icon="@Icons.Material.Filled.GroupAdd" Disabled="@loading" OnClick="@(() => OpenJoinSubscribe(context))">加群/订阅</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.ExitToApp" Disabled="@loading" OnClick="@(() => OpenLeaveUnsubscribe(context))">退群/退订</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.MarkEmailUnread" Disabled="@loading" OnClick="@(() => OpenSystemInbox(context))">系统通知(验证码)</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Devices" Disabled="@loading" OnClick="@(() => OpenDevices(context))">在线设备</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Password" Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorPassword(context))">修改二级密码</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.AlternateEmail" Disabled="@loading" OnClick="@(() => OpenChangeTwoFactorRecoveryEmail(context))">绑定/换绑找回邮箱</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@(context.IsActive ? Icons.Material.Filled.Stop : Icons.Material.Filled.PlayArrow)"
Disabled="@loading"
OnClick="@(() => ToggleActive(context))">
@(context.IsActive ? "停用" : "启用")
</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Delete" Disabled="@loading" OnClick="@(() => DeleteAccount(context))">删除账号</MudMenuItem>
</MudMenu>
</MudStack>
</MudTd>
</RowTemplate>
<NoRecordsContent>
@@ -12,98 +12,79 @@
<MudText Typo="Typo.h4" Class="mb-4 tp-page-title">Bot 频道</MudText>
<MudPaper Class="pa-4 mb-4" Elevation="0" Outlined="true">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudSelect T="int" Value="@selectedBotId" ValueChanged="@(async (int id) => await OnSelectedBotChanged(id))" Label="选择机器人"
Variant="Variant.Outlined" Dense="true" Class="tp-input-full-xs"
Style="min-width: 200px; flex: 1; max-width: 400px;">
<MudSelectItem Value="0">-- 请选择机器人 --</MudSelectItem>
@foreach (var b in bots)
{
<MudSelectItem Value="@b.Id">@b.Name</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="filterCategoryId" @bind-Value:after="OnFiltersChanged" Label="分类" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs"
Style="min-width: 160px; flex: 0 1 200px;" Disabled="@(selectedBotId <= 0)">
<MudSelectItem Value="0">全部分类</MudSelectItem>
<MudSelectItem Value="-1">未分类</MudSelectItem>
@foreach (var c in categories)
{
<MudSelectItem Value="@c.Id">@c.Name</MudSelectItem>
}
</MudSelect>
<MudIconButton Icon="@Icons.Material.Filled.Add" Color="Color.Primary" Size="Size.Small"
Title="新建分类" OnClick="OpenCreateCategoryDialog"
Disabled="@(selectedBotId <= 0)" />
<MudTextField @bind-Value="search" Placeholder="搜索频道..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0 tp-input-full-xs"
Style="min-width: 200px; flex: 1; max-width: 400px;"
Immediate="true" Disabled="@(selectedBotId <= 0)" @bind-Value:after="OnSearchChanged" />
</MudStack>
</MudPaper>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="mb-2" Style="flex-wrap: wrap;">
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Refresh"
Disabled="@(loading || selectedBotId <= 0)" OnClick="ReloadTable" Size="Size.Small">
刷新
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Primary" StartIcon="@SelectionToggleIcon"
Disabled="@(loading || selectedBotId <= 0 || channels.Count == 0)" OnClick="CycleSelectionToggle" Size="Size.Small">
@SelectionToggleText
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@(loading || selectedBotId <= 0)" OnClick="Sync" Size="Size.Small">
同步
</MudButton>
<MudMenu Label="批量操作" Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Size="Size.Small" Disabled="@(loading || selectedBotId <= 0)" Dense="true" EndIcon="@Icons.Material.Filled.KeyboardArrowDown">
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="ExportInvites">导出邀请(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenSetAdmins">批量设置管理员(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBatchSetCategory">批量设置分类(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBanMember">踢出用户(已选)</MudMenuItem>
</MudMenu>
@if (selected.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info" Class="ml-2">已选 @selected.Count</MudChip>
}
else
{
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="ml-2">频道 (@totalCount)</MudText>
}
</MudStack>
<MudCard>
<MudCardContent>
<MudTable ServerData="LoadChannelsServerData" Hover="true" Breakpoint="Breakpoint.Sm" Loading="@loading"
Class="tp-table"
MultiSelection="true" @bind-SelectedItems="selected" @ref="_table">
<ToolBarContent>
<MudStack Spacing="1" Style="width: 100%;">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Class="tp-flex-wrap">
<MudSelect T="int" Value="@selectedBotId" ValueChanged="@(async (int id) => await OnSelectedBotChanged(id))" Label="选择机器人"
Variant="Variant.Outlined" Dense="true" Class="tp-input-full-xs"
Style="min-width: 260px; flex: 1 1 260px;">
<MudSelectItem Value="0">-- 请选择机器人 --</MudSelectItem>
@foreach (var b in bots)
{
<MudSelectItem Value="@b.Id">@b.Name</MudSelectItem>
}
</MudSelect>
<MudText Typo="Typo.h6">
频道 (@totalCount)
</MudText>
@if (selected.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info">已选 @selected.Count</MudChip>
}
<div class="tp-hide-xs">
<MudSpacer />
</div>
<MudSelect @bind-Value="filterCategoryId" @bind-Value:after="OnFiltersChanged" Label="分类" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs"
Style="min-width: 160px; flex: 0 1 200px;" Disabled="@(selectedBotId <= 0)">
<MudSelectItem Value="0">全部分类</MudSelectItem>
<MudSelectItem Value="-1">未分类</MudSelectItem>
@foreach (var c in categories)
{
<MudSelectItem Value="@c.Id">@c.Name</MudSelectItem>
}
</MudSelect>
<MudIconButton Icon="@Icons.Material.Filled.Add" Color="Color.Primary" Size="Size.Small"
Title="新建分类" OnClick="OpenCreateCategoryDialog"
Disabled="@(selectedBotId <= 0)" />
<MudTextField @bind-Value="search" Placeholder="搜索频道..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0 tp-input-full-xs"
Style="min-width: 220px; flex: 1 1 260px;"
Immediate="true" Disabled="@(selectedBotId <= 0)" @bind-Value:after="OnSearchChanged" />
<MudMenu Dense="true" Disabled="@(loading || selectedBotId <= 0)">
<ActivatorContent>
<MudButton Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Class="tp-nowrap"
Disabled="@(loading || selectedBotId <= 0)" Size="Size.Small">
批量操作
</MudButton>
</ActivatorContent>
<ChildContent>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="ExportInvites">导出邀请(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenSetAdmins">批量设置管理员(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBatchSetCategory">批量设置分类(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selected.Count == 0)" OnClick="OpenBanMember">踢出用户(已选)</MudMenuItem>
</ChildContent>
</MudMenu>
<MudIconButton Icon="@(_actionsExpanded ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)"
Color="Color.Default"
Title="@(_actionsExpanded ? "收起操作" : "展开操作")"
Disabled="@(selectedBotId <= 0)"
OnClick="@ToggleActions" />
</MudStack>
<MudCollapse Expanded="@_actionsExpanded">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Style="flex-wrap: wrap; margin-top: 6px;">
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@(loading || selectedBotId <= 0)" OnClick="Sync" Size="Size.Small">
同步
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Refresh"
Disabled="@(loading || selectedBotId <= 0)" OnClick="ReloadTable" Size="Size.Small">
刷新
</MudButton>
</MudStack>
</MudCollapse>
<MudDivider Class="mt-2" />
</MudStack>
</ToolBarContent>
<HeaderContent>
<MudTh>频道名称</MudTh>
<MudTh>用户名</MudTh>
@@ -137,12 +118,14 @@
</MudTd>
<MudTd DataLabel="最后同步"><PanelTime Value="context.SyncedAt" /></MudTd>
<MudTd DataLabel="操作">
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small">
<MudMenuItem Icon="@Icons.Material.Filled.Link" OnClick="@(async () => await CopyLinkAsync(context))">复制链接</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Info" OnClick="@(async () => await ShowDetailsAsync(context))">查看详情</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Edit" OnClick="@(async () => await EditChannelAsync(context))">编辑频道</MudMenuItem>
</MudMenu>
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudIconButton Icon="@Icons.Material.Filled.Link" Size="Size.Small" Color="Color.Info"
OnClick="@(async () => await CopyLinkAsync(context))" Title="复制链接" />
<MudIconButton Icon="@Icons.Material.Filled.Info" Size="Size.Small" Color="Color.Default"
OnClick="@(async () => await ShowDetailsAsync(context))" Title="查看详情" />
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" Color="Color.Primary"
OnClick="@(async () => await EditChannelAsync(context))" Title="编辑频道" />
</MudStack>
</MudTd>
</RowTemplate>
<NoRecordsContent>
@@ -183,6 +166,23 @@
private bool _actionsExpanded = true;
private CancellationTokenSource? _searchDebounceCts;
private SelectionToggleMode _selectionToggleMode = SelectionToggleMode.SelectAll;
private string SelectionToggleText => _selectionToggleMode switch
{
SelectionToggleMode.SelectAll => "全选本页",
SelectionToggleMode.Invert => "反选本页",
SelectionToggleMode.Clear => "清空选择",
_ => "全选本页"
};
private string SelectionToggleIcon => _selectionToggleMode switch
{
SelectionToggleMode.SelectAll => Icons.Material.Filled.SelectAll,
SelectionToggleMode.Invert => Icons.Material.Filled.Flip,
SelectionToggleMode.Clear => Icons.Material.Filled.Clear,
_ => Icons.Material.Filled.SelectAll
};
protected override async Task OnInitializedAsync()
{
try
@@ -608,4 +608,58 @@
if (!result.Canceled)
await LoadBotData();
}
private Task SelectAllFiltered()
{
selected = channels.ToHashSet();
return Task.CompletedTask;
}
private Task InvertSelection()
{
var targets = channels.ToList();
foreach (var c in targets)
{
if (selected.Contains(c))
selected.Remove(c);
else
selected.Add(c);
}
return Task.CompletedTask;
}
private Task ClearSelection()
{
selected.Clear();
return Task.CompletedTask;
}
private async Task CycleSelectionToggle()
{
switch (_selectionToggleMode)
{
case SelectionToggleMode.SelectAll:
await SelectAllFiltered();
_selectionToggleMode = SelectionToggleMode.Invert;
break;
case SelectionToggleMode.Invert:
await InvertSelection();
_selectionToggleMode = SelectionToggleMode.Clear;
break;
case SelectionToggleMode.Clear:
await ClearSelection();
_selectionToggleMode = SelectionToggleMode.SelectAll;
break;
default:
_selectionToggleMode = SelectionToggleMode.SelectAll;
break;
}
}
private enum SelectionToggleMode
{
SelectAll = 0,
Invert = 1,
Clear = 2
}
}
@@ -15,67 +15,66 @@
<MudText Typo="Typo.h4" Class="mb-4">频道列表</MudText>
<MudPaper Class="pa-4 mb-4" Elevation="0" Outlined="true">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudSelect @bind-Value="filterAccount" @bind-Value:after="OnFiltersChanged" Label="筛选账号" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs" Style="min-width: 200px; flex: 1; max-width: 400px;">
<MudSelectItem Value="0">全部账号</MudSelectItem>
@foreach (var account in accounts)
{
<MudSelectItem Value="@account.Id">@FormatAccountLabel(account)</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="filterType" @bind-Value:after="OnFiltersChanged" Label="频道类型" Variant="Variant.Outlined" Dense="true"
Class="tp-input-full-xs" Style="min-width: 120px; flex: 0 1 150px;">
<MudSelectItem Value='@("all")'>全部</MudSelectItem>
<MudSelectItem Value='@("public")'>公开</MudSelectItem>
<MudSelectItem Value='@("private")'>私密</MudSelectItem>
</MudSelect>
<MudTextField @bind-Value="searchString" Placeholder="搜索频道..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0 tp-input-full-xs"
Style="min-width: 200px; flex: 1; max-width: 400px;"
Immediate="true" @bind-Value:after="OnSearchChanged" />
</MudStack>
</MudPaper>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="mb-2" Style="flex-wrap: wrap;">
<MudButton Variant="Variant.Outlined" Color="Color.Primary" StartIcon="@SelectionToggleIcon"
Disabled="@(loading || channels.Count == 0)" OnClick="CycleSelectionToggle" Size="Size.Small">
@SelectionToggleText
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@(loading || filterAccount <= 0)" OnClick="SyncCurrentAccountChannels" Size="Size.Small">
同步当前
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@loading" OnClick="SyncAllAccountsChannels" Size="Size.Small">
同步全部
</MudButton>
<MudMenu Label="批量操作" Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Size="Size.Small" Disabled="@loading" Dense="true" EndIcon="@Icons.Material.Filled.KeyboardArrowDown">
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchInviteSelected">批量邀请(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchSetAdminsSelected">批量设置管理员(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchSetGroupSelected">批量修改分组(已选)</MudMenuItem>
</MudMenu>
@if (selectedChannels.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info" Class="ml-2">已选 @selectedChannels.Count</MudChip>
}
else
{
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="ml-2">频道 (@totalCount)</MudText>
}
</MudStack>
<MudCard>
<MudCardContent>
<MudTable ServerData="LoadChannelsServerData" Hover="true" Breakpoint="Breakpoint.Sm" Loading="@loading"
Class="tp-table"
MultiSelection="true" @bind-SelectedItems="selectedChannels" @ref="_table">
<ToolBarContent>
<MudStack Spacing="1">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Style="flex-wrap: wrap;">
<MudText Typo="Typo.h6">频道 (@totalCount)</MudText>
@if (selectedChannels.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info">已选 @selectedChannels.Count</MudChip>
}
<MudSpacer />
<MudTextField @bind-Value="searchString" Placeholder="搜索频道..." Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"
Immediate="true" @bind-Value:after="OnSearchChanged" />
</MudStack>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Style="flex-wrap: wrap;">
<MudSelect @bind-Value="filterAccount" @bind-Value:after="OnFiltersChanged" Label="筛选账号" Variant="Variant.Outlined" Dense="true" Class="mr-2" Style="min-width: 220px;">
<MudSelectItem Value="0">全部账号</MudSelectItem>
@foreach (var account in accounts)
{
<MudSelectItem Value="@account.Id">@FormatAccountLabel(account)</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="filterType" @bind-Value:after="OnFiltersChanged" Label="频道类型" Variant="Variant.Outlined" Dense="true" Class="mr-2" Style="min-width: 120px;">
<MudSelectItem Value='@("all")'>全部</MudSelectItem>
<MudSelectItem Value='@("public")'>公开</MudSelectItem>
<MudSelectItem Value='@("private")'>私密</MudSelectItem>
</MudSelect>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@(loading || filterAccount <= 0)" OnClick="SyncCurrentAccountChannels" Size="Size.Small">
同步当前账号数据
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.Sync"
Disabled="@loading" OnClick="SyncAllAccountsChannels" Size="Size.Small">
同步全部账号数据
</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Primary" StartIcon="@SelectionToggleIcon"
Disabled="@(loading || channels.Count == 0)" OnClick="CycleSelectionToggle" Size="Size.Small">
@SelectionToggleText
</MudButton>
<MudMenu Dense="true" Disabled="@loading">
<ActivatorContent>
<MudButton Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.MoreHoriz"
Disabled="@loading" Size="Size.Small">
批量操作
</MudButton>
</ActivatorContent>
<ChildContent>
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchInviteSelected">批量邀请(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchSetAdminsSelected">批量设置管理员(已选)</MudMenuItem>
<MudMenuItem Disabled="@(selectedChannels.Count == 0)" OnClick="OpenBatchSetGroupSelected">批量修改分组(已选)</MudMenuItem>
</ChildContent>
</MudMenu>
</MudStack>
</MudStack>
</ToolBarContent>
<HeaderContent>
<MudTh>频道名称</MudTh>
<MudTh>用户名</MudTh>
@@ -130,16 +129,20 @@
</MudTd>
<MudTd DataLabel="最后同步"><PanelTime Value="context.SyncedAt" /></MudTd>
<MudTd DataLabel="操作">
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small">
<MudMenuItem Icon="@Icons.Material.Filled.Info" OnClick="@(async () => await ShowDetails(context))">查看详情</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Edit" OnClick="@(async () => await EditChannel(context))">编辑频道</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.PersonAdd" OnClick="@(async () => await OpenInvite(context))">邀请成员</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.AdminPanelSettings" OnClick="@(async () => await OpenSetAdmins(context))">设置管理员</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.PersonRemove" OnClick="@(async () => await KickUser(context))">踢人</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Link" OnClick="@(async () => await CopyLinkAsync(context))">复制链接</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Delete" IconColor="Color.Error" OnClick="@(() => DeleteChannel(context.Id))">删除频道</MudMenuItem>
</MudMenu>
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Style="flex-wrap: wrap;">
<MudIconButton Icon="@Icons.Material.Filled.Info" Size="Size.Small" Color="Color.Info"
OnClick="@(async () => await ShowDetails(context))" Title="查看详情" />
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" Color="Color.Primary"
OnClick="@(async () => await EditChannel(context))" Title="编辑频道" />
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small" Dense="true">
<MudMenuItem Icon="@Icons.Material.Filled.PersonAdd" OnClick="@(async () => await OpenInvite(context))">邀请成员</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.AdminPanelSettings" OnClick="@(async () => await OpenSetAdmins(context))">设置管理员</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.PersonRemove" OnClick="@(async () => await KickUser(context))">踢人</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Filled.Link" OnClick="@(async () => await CopyLinkAsync(context))">复制链接</MudMenuItem>
<MudDivider />
<MudMenuItem Icon="@Icons.Material.Filled.Delete" IconColor="Color.Error" OnClick="@(() => DeleteChannel(context.Id))">删除频道</MudMenuItem>
</MudMenu>
</MudStack>
</MudTd>
</RowTemplate>
<NoRecordsContent>