Enterprise-level component library based on Bootstrap and Blazor

star nuget master download license repo commit

Table 表格

用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。

自定义列名

通过设置 Text 增加列头显示名称

Demo

表格组件 TableColumns 模板中的字段采用的是根据绑定模型的 DisplayName 标签值来自动显示的,如果要自定义显示名称请设置 Text 属性

Loading...

带选择列表格

通过设置 IsMultipleSelect=true 增加表格第一列为选择列

Demo
Loading...

带显示文字的选择列表格

通过设置 ShowCheckboxText=true 表格第一列显示文字为 选择

Demo
Loading...

选择框列

RowTemplate 内部组件 TableCell 设置 Checkbox 并设置相关数据绑定即可,本示例中通过数据绑定将选择框组件与值进行绑定

Demo
Loading...

自定义各列宽度

通过设置 TableColumn Width 属性,来控制列宽度,行内按钮操作列宽度由 ExtendButtonColumnWidth 属性控制

Demo

本例中继续上一个例子,实现了自定义四个功能按钮,并且扩展到行内,点击各个按钮时均有相对应的回调委托方法,TableToolbarButton 采用的是 Delegate 方式完成数据交换,点击工具栏按钮时设置 OnClickCallback 委托方法即可获取表内选中的行数据集合

Loading...

自定义列数据模板

自定义 TableColumn 列的 Template 模板来实现任意 UI

Demo

本例中列 DateTime 值根据 Complete 值是否为 true 显示不同颜色

本例中列 Complete 根据 Complete 值自定义显示为 Checkbox 组件

Template 模板自带 Context 相关联上下文,其值为 TableColumnContext 类型

  • Value 为当前绑定列的数据值
  • Row 为当前绑定列所在行的数据值
Loading...

自定义列数据格式

列绑定时通过指定 FormatString 或者 Formatter 回调委托来实现单元格数值格式化

Demo

本例中列 DateTime 值根据 FormatString 将值格式化为 yyyy-MM-dd 年月日格式

本例中列 Count 值根据 Formatter 将值格式化为 0.00 保留两位小数格式

Loading...

列数据对齐方式

列绑定时通过指定 Align 属性设置对齐方式

Demo

本例中列 DateTime 列设置为居中对齐 Alignment.Center

本例中列 Count 列设置为右侧对齐 Alignment.Right

Loading...

根据屏幕宽度自动显示/隐藏列

通过指定 ShownWithBreakPoint 属性设置在不同宽度下是否显示

Demo

ShownWithBreakPoint 枚举值为:

  • None 未设置均显示
  • Small 屏幕大于等于 576px 时显示
  • Medium 屏幕大于等于 768px 时显示
  • Large 屏幕大于等于 992px 时显示
  • ExtraLarge 屏幕大于等于 1200px 时显示

本例中列 Count 列设置为 BreakPoint.Large 即屏幕在大于 992px 时才显示

注意:

由于 Table 组件默认是支持移动端适配,所以小屏幕时采用的是卡片式模式,本例中显式设置使用 RenderModel="TableRenderModel.Table" 模式

Loading...

自定义显示/隐藏列

通过指定 ShowColumnList 属性设置列是否显示

Demo

ShowColumnList 默认值为 false,显式指定为 true 后工具栏出现相应列调整按钮

TableColumn 增加 Visiable 属性,其默认值为 true,显示设置为 false 时不显示此列

此例中 数量 列通过设置 Visible 未显示,可以通过列控制按钮进行显示设置

Loading...

允许列调整

通过指定 AllowResizing 设置表格列允许调整宽度

Demo
Loading...

自定义列模板

通过指定 AllowResizing 设置表格列允许调整宽度

Demo
Loading...

自动生成列

通过指定 AutoGenerateColumns 属性值为 true,开启根据绑定模型自动生成列信息功能

Demo

本例中通过设置 AutoGenerateColumns 值为 true 开启自动生成列功能,默认绑定模型实体类所有属性全部生成,实体类可以通过 AutoGenerateColumnAttribute 标签类进行功能设置,如:

  • Ignore 表示忽略此属性,即不生成
  • Readonly 表示只读
  • 更多属性详见 源码
本例中通过 [AutoGenerateColumn(Order = 1, FormatString = "yyyy-MM-dd")] 标签格式化 日期 列;通过代码中设置模板列对 Complete 列进行自定义使用 Switch 组件进行渲染;通过 [AutoGenerateColumn(Order = 10)] 标签中的 Order 对显示顺序进行设定

Loading...
@page "/tables/column"

<h3>Table 表格</h3>

<h4>用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。</h4>

<Block Title="自定义列名" Introduction="通过设置 <code>Text</code> 增加列头显示名称">
    <p>
        表格组件 <code>TableColumns</code> 模板中的字段采用的是根据绑定模型的 <code>DisplayName</code> 标签值来自动显示的,如果要自定义显示名称请设置 <code>Text</code> 属性
    </p>
    <Table TItem="Foo" Items="@Items.Take(3)">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Text="自定义列名1" Width="180" />
            <TableColumn @bind-Field="@context.Name" Text="自定义列名2" />
            <TableColumn @bind-Field="@context.Address" Text="自定义列名3" />
        </TableColumns>
    </Table>
</Block>

<Block Title="带选择列表格" Introduction="通过设置 <code>IsMultipleSelect=true</code> 增加表格第一列为选择列">
    <Table TItem="Foo" Items="@Items.Take(3)" IsMultipleSelect="true">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" />
        </TableColumns>
    </Table>
</Block>

<Block Title="带显示文字的选择列表格" Introduction="通过设置 <code>ShowCheckboxText=true</code> 表格第一列显示文字为 <b>选择</b>">
    <Table TItem="Foo" Items="@Items.Take(3)" IsMultipleSelect="true" ShowCheckboxText="true">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" />
        </TableColumns>
    </Table>
</Block>

<Block Title="选择框列" Introduction="<code>RowTemplate</code> 内部组件 <code>TableCell</code> 设置 <code>Checkbox</code> 并设置相关数据绑定即可,本示例中通过数据绑定将选择框组件与值进行绑定">
    <Table TItem="Foo" Items="@Items.Take(3)">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Complete">
                <Template Context="value">
                    <Checkbox Value="@value.Value" IsDisabled="true"></Checkbox>
                </Template>
            </TableColumn>
        </TableColumns>
    </Table>
</Block>

<Block Title="自定义各列宽度" Introduction="通过设置 <code>TableColumn</code> <code>Width</code> 属性,来控制列宽度,行内按钮操作列宽度由 <code>ExtendButtonColumnWidth</code> 属性控制">
    <p>本例中继续上一个例子,实现了自定义四个功能按钮,并且扩展到行内,点击各个按钮时均有相对应的回调委托方法,<code>TableToolbarButton</code> 采用的是 <code>Delegate</code> 方式完成数据交换,点击工具栏按钮时设置 <code>OnClickCallback</code> 委托方法即可获取表内选中的行数据集合</p>
    <Table TItem="Foo" @ref="TableRows" SelectedRows="@SelectedRows"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true"
           ShowToolbar="true" ShowDefaultButtons="false" ShowSearch="false" IsMultipleSelect="true"
           ShowExtendButtons="true" ExtendButtonColumnWidth="240"
           OnQueryAsync="@OnQueryAsync">
        <TableToolbarTemplate>
            <TableToolbarButton TItem="Foo" Color="Color.Primary" Icon="fa fa-fw fa-edit" Text="明细" OnClickCallback="@CustomerButton" />
            <TableToolbarButton TItem="Foo" Color="Color.Success" Icon="fa fa-fw fa-edit" Text="编辑" OnClickCallback="@CustomerButton" />
            <TableToolbarButton TItem="Foo" Color="Color.Warning" Icon="fa fa-fw fa-edit" Text="权限" OnClickCallback="@CustomerButton" />
            <TableToolbarButton TItem="Foo" Color="Color.Danger" Icon="fa fa-fw fa-edit" Text="审批" OnClickCallback="@CustomerButton" />
        </TableToolbarTemplate>
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
        </TableColumns>
        <RowButtonTemplate>
            <TableCellButton Size="Size.ExtraSmall" Color="Color.Primary" Icon="fa fa-edit" Text="明细" OnClickCallback="@(() => OnRowButtonClick(context))" />
            <TableCellButton Size="Size.ExtraSmall" Color="Color.Success" Icon="fa fa-edit" Text="编辑" OnClickCallback="@(() => OnRowButtonClick(context))" />
            <TableCellButton Size="Size.ExtraSmall" Color="Color.Warning" Icon="fa fa-edit" Text="权限" OnClickCallback="@(() => OnRowButtonClick(context))" />
            <TableCellButton Size="Size.ExtraSmall" Color="Color.Danger" Icon="fa fa-edit" Text="审批" OnClickCallback="@(() => OnRowButtonClick(context))" />
            <PopConfirmButton Text="确认" Color="Color.Info" Icon="fa fa-edit" Size="Size.ExtraSmall" OnConfirm="@(() => OnRowButtonClick(context))" />
        </RowButtonTemplate>
    </Table>
</Block>

<Block Title="自定义列数据模板" Introduction="自定义 <code>TableColumn</code> 列的 <code>Template</code> 模板来实现任意 UI">
    <p>
        本例中列 <code>DateTime</code> 值根据 <code>Complete</code> 值是否为 <code>true</code> 显示不同颜色
    </p>
    <p>
        本例中列 <code>Complete</code> 根据 <code>Complete</code> 值自定义显示为 <code>Checkbox</code> 组件
    </p>
    <p><code>Template</code> 模板自带 <code>Context</code> 相关联上下文,其值为 <code>TableColumnContext</code> 类型</p>
    <ul>
        <li><code>Value</code> 为当前绑定列的数据值</li>
        <li><code>Row</code> 为当前绑定列所在行的数据值</li>
    </ul>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180">
                <Template Context="value">
                    @if (((Foo)value.Row).Complete)
                    {
                        <div class="text-success">@value.Value</div>
                    }
                    else
                    {
                        <div class="text-danger">@value.Value</div>
                    }
                </Template>
            </TableColumn>
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Complete" Width="100">
                <Template Context="value">
                    <Checkbox Value="@value.Value" IsDisabled="true"></Checkbox>
                </Template>
            </TableColumn>
        </TableColumns>
    </Table>
</Block>

<Block Title="自定义列数据格式" Introduction="列绑定时通过指定 <code>FormatString</code> 或者 <code>Formatter</code> 回调委托来实现单元格数值格式化">
    <p>
        本例中列 <code>DateTime</code> 值根据 <code>FormatString</code> 将值格式化为 <code>yyyy-MM-dd</code> 年月日格式
    </p>
    <p>
        本例中列 <code>Count</code> 值根据 <code>Formatter</code> 将值格式化为 <code>0.00</code> 保留两位小数格式
    </p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Count" Formatter="@IntFormatter" />
        </TableColumns>
    </Table>
</Block>

<Block Title="列数据对齐方式" Introduction="列绑定时通过指定 <code>Align</code> 属性设置对齐方式">
    <p>
        本例中列 <code>DateTime</code> 列设置为居中对齐 <code>Alignment.Center</code>
    </p>
    <p>
        本例中列 <code>Count</code> 列设置为右侧对齐 <code>Alignment.Right</code>
    </p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" Align="Alignment.Center" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Count" Formatter="@IntFormatter" Width="60" Align="Alignment.Right" />
        </TableColumns>
    </Table>
</Block>

<Block Title="根据屏幕宽度自动显示/隐藏列" Introduction="通过指定 <code>ShownWithBreakPoint</code> 属性设置在不同宽度下是否显示">
    <p>
        <code>ShownWithBreakPoint</code> 枚举值为:
    </p>
    <ul class="ul-demo">
        <li><code>None</code> 未设置均显示</li>
        <li><code>Small</code> 屏幕大于等于 <code>576px</code> 时显示</li>
        <li><code>Medium</code> 屏幕大于等于 <code>768px</code> 时显示</li>
        <li><code>Large</code> 屏幕大于等于 <code>992px</code> 时显示</li>
        <li><code>ExtraLarge</code> 屏幕大于等于 <code>1200px</code> 时显示</li>
    </ul>
    <p>
        本例中列 <code>Count</code> 列设置为 <code>BreakPoint.Large</code> 即屏幕在大于 <code>992px</code> 时才显示
    </p>
    <p>注意:</p>
    <p>由于 <code>Table</code> 组件默认是支持移动端适配,所以小屏幕时采用的是卡片式模式,本例中显式设置使用 <code>RenderModel="TableRenderModel.Table"</code> 模式</p>
    <Table TItem="Foo" RenderModel="TableRenderModel.Table"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" Align="Alignment.Center" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Count" ShownWithBreakPoint="BreakPoint.Large" Formatter="@IntFormatter" Width="60" />
        </TableColumns>
    </Table>
</Block>

<Block Title="自定义显示/隐藏列" Introduction="通过指定 <code>ShowColumnList</code> 属性设置列是否显示">
    <p><code>ShowColumnList</code> 默认值为 false,显式指定为 true 后工具栏出现相应列调整按钮</p>
    <p><code>TableColumn</code> 增加 <code>Visiable</code> 属性,其默认值为 true,显示设置为 false 时不显示此列</p>
    <p>此例中 <b>数量</b> 列通过设置 <code>Visible</code> 未显示,可以通过列控制按钮进行显示设置</p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true"
           ShowToolbar="true" ShowAddButton="false" ShowEditButton="false" ShowDeleteButton="false"
           ShowExtendButtons="false" ShowColumnList="true"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" Text="时间" />
            <TableColumn @bind-Field="@context.Name" Text="姓名" />
            <TableColumn @bind-Field="@context.Address" Text="地址" Width="290" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" Visible="false" />
            <TableColumn @bind-Field="@context.Complete" ComponentType="@typeof(Switch)" />
        </TableColumns>
    </Table>
</Block>

<Block Title="允许列调整" Introduction="通过指定 <code>AllowResizing</code> 设置表格列允许调整宽度">
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource" AllowResizing="true"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Count" />
        </TableColumns>
    </Table>
</Block>

<Block Title="自定义列模板" Introduction="通过指定 <code>AllowResizing</code> 设置表格列允许调整宽度">
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource" AllowResizing="true"
           IsStriped="true" IsBordered="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" />
            <TableColumn @bind-Field="@context.Name" Width="100" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Count" />
            <TableColumn @bind-Field="@context.Id" Text="">
                <Template Context="v">
                    <PopConfirmButton Text="Test" Size="Size.ExtraSmall" />
                </Template>
            </TableColumn>
        </TableColumns>
    </Table>
</Block>

<Block Title="自动生成列" Introduction="通过指定 <code>AutoGenerateColumns</code> 属性值为 <code>true</code>,开启根据绑定模型自动生成列信息功能">
    <p>
        本例中通过设置 <code>AutoGenerateColumns</code> 值为 <code>true</code> 开启自动生成列功能,默认绑定模型实体类所有属性全部生成,实体类可以通过 <code>AutoGenerateColumnAttribute</code> 标签类进行功能设置,如:
        <ul class="ul-demo">
            <li><code>Ignore</code> 表示忽略此属性,即不生成</li>
            <li><code>Readonly</code> 表示只读</li>
            <li>更多属性详见 <a href="https://gitee.com/LongbowEnterprise/BootstrapBlazor/blob/master/src/BootstrapBlazor/Attributes/AutoGenerateColumnAttribute.cs" target="_blank">源码</a></li>
        </ul>
        本例中通过 <code>[AutoGenerateColumn(Order = 1, FormatString = "yyyy-MM-dd")]</code> 标签格式化 <code>日期</code> 列;通过代码中设置模板列对 <code>Complete</code> 列进行自定义使用 <code>Switch</code> 组件进行渲染;通过 <code>[AutoGenerateColumn(Order = 10)]</code> 标签中的 <code>Order</code> 对显示顺序进行设定
    </p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" AutoGenerateColumns="true"
           ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
           OnQueryAsync="@OnQueryAsync">
    </Table>
</Block>
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace BootstrapBlazor.Shared.Pages.Table
{
    /// <summary>
    /// Table 组件列属性示例代码
    /// </summary>
    public partial class TablesColumn
    {
        private static readonly ConcurrentDictionary<Type, Func<IEnumerable<Foo>, string, SortOrder, IEnumerable<Foo>>> SortLambdaCache = new();

        [NotNull]
        private List<Foo>? Items { get; set; }

        [Inject]
        [NotNull]
        private IStringLocalizer<Foo>? Localizer { get; set; }

        [Inject]
        [NotNull]
        private ToastService? ToastService { get; set; }

        private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };

        /// <summary>
        /// OnInitialized 方法
        /// </summary>
        protected override void OnInitialized()
        {
            base.OnInitialized();

            Items = Foo.GenerateFoo(Localizer);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static Task<string> IntFormatter(object? d)
        {
            var data = (int?)d;
            return Task.FromResult(data?.ToString("0.00") ?? "");
        }

        private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
        {
            IEnumerable<Foo> items = Items;

            // 过滤
            var isFiltered = false;
            if (options.Filters.Any())
            {
                items = items.Where(options.Filters.GetFilterFunc<Foo>());
                isFiltered = true;
            }

            // 排序
            var isSorted = false;
            if (!string.IsNullOrEmpty(options.SortName))
            {
                var invoker = SortLambdaCache.GetOrAdd(typeof(Foo), key => LambdaExtensions.GetSortLambda<Foo>().Compile());
                items = invoker(items, options.SortName, options.SortOrder);
                isSorted = true;
            }

            // 设置记录总数
            var total = items.Count();

            // 内存分页
            items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();

            return Task.FromResult(new QueryData<Foo>()
            {
                Items = items,
                TotalCount = total,
                IsSorted = isSorted,
                IsFiltered = isFiltered,
                IsSearch = true
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="items"></param>
        private async Task CustomerButton(IEnumerable<Foo> items)
        {
            var cate = ToastCategory.Information;
            var title = "自定义按钮处理方法";
            var content = $"通过不同的函数区分按钮处理逻辑,参数 Items 为 Table 组件中选中的行数据集合,当前选择数据 {items.Count()} 条";
            await ToastService.Show(new ToastOption()
            {
                Category = cate,
                Title = title,
                Content = content
            });
        }

        private List<Foo> SelectedRows { get; set; } = new();

        [NotNull]
        private Table<Foo>? TableRows { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        private async Task OnRowButtonClick(Foo item)
        {
            var cate = ToastCategory.Success;
            var title = "行内按钮处理方法";
            var content = "通过不同的函数区分按钮处理逻辑,参数 Item 为当前行数据";
            await ToastService.Show(new ToastOption()
            {
                Category = cate,
                Title = title,
                Content = content
            });

            SelectedRows.Clear();
            SelectedRows.Add(item);
            await TableRows.QueryAsync();
        }
    }
}

B 站相关视频链接

[传送门]

交流群

QQ群:BootstrapAdmin & Blazor 795206915(满) 675147445 欢迎加群讨论
Themes
Bootstrap
Ant Design (完善中)
Bluma (完善中)
LayUI (完善中)
An error has occurred. This application may no longer respond until reloaded. Reload