经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Bootstrap » 查看文章
[硬核] Bootstrap Blazor Table 综合演示例子
来源:cnblogs  作者:AlexChow  时间:2023/1/16 9:17:45  对本文有异议

知识点:

1.导入导出
2.分页功能
3.增删改查
4.批量删除
5.批量编辑(审核)
6.列排序与列搜索
7.顶部搜索实现所有列搜索
8.高级搜索实现多条件搜索
9.顶部与刷新与视图列
10.实现文本类型明细行
11.列的统计
12.隐藏列,时间日期列格式化
13.新窗口打开
14.随机数据
15.自由编辑
16.清空数据
17.模板下载

截图

基础工程

表格组件导出 Excel Word Html Pdf

注入FreeSqlDataService服务,支持全数据导出

更新包

  1. <PackageReference Include="BootstrapBlazor" Version="7.2.3-beta03" />
  2. <PackageReference Include="Densen.FreeSql.Extensions.BootstrapBlazor" Version="7.*" />

Program.cs 添加代码

  1. using Densen.DataAcces.FreeSql;
  2. builder.Services.AddSingleton(typeof(FreeSqlDataService<>));
  3. builder.Services.ConfigureJsonLocalizationOptions(op =>
  4. {
  5. // 忽略文化信息丢失日志
  6. op.IgnoreLocalizerMissing = true;
  7. });

Index.razor添加一个 TabItem

Tab 顺便改为懒加载

  1. <Tab IsLazyLoadTabItem="true">
  2. ...
  3. <TabItem Text="综合演示">
  4. <ImpExpIII />
  5. </TabItem>
  6. </Tab>

添加打印预览 Pages\_Host.cshtml

< / body > 前加一句

  1. <script>
  2. function printDiv() {
  3. window.print();
  4. }
  5. </script>

数据实体类 Data\SalesChannels.cs

查看代码
  1. using BootstrapBlazor.Components;
  2. using DocumentFormat.OpenXml.Wordprocessing;
  3. using FreeSql.DataAnnotations;
  4. using Magicodes.ExporterAndImporter.Excel;
  5. using OfficeOpenXml.Table;
  6. using System.ComponentModel;
  7. using System.ComponentModel.DataAnnotations;
  8. namespace b14table.Data;
  9. [ExcelImporter(IsLabelingError = true)]
  10. [ExcelExporter(Name = "导入商品中间表", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
  11. [AutoGenerateClass(Searchable = true, Filterable = true, Sortable = true, ShowTips = true)]
  12. public class SalesChannels
  13. {
  14. [AutoGenerateColumn(Ignore = true)]
  15. [Column(IsIdentity = true)]
  16. [DisplayName("序号")]
  17. public int ID { get; set; }
  18. [AutoGenerateColumn(ComponentType = typeof(ColorPicker), Width = 30)]
  19. [DisplayName("级别")]
  20. public string? Background { get; set; }
  21. [AutoGenerateColumn(FormatString = "yyyy-MM-dd")]
  22. [DisplayName("日期")]
  23. public DateTime Date { get; set; }
  24. [Required(ErrorMessage = "{0}不能为空")]
  25. [DisplayName("名称")]
  26. public string? Name { get; set; }
  27. [DisplayName("项目数量")]
  28. public int Projects { get; set; }
  29. [DisplayName("交单数量")]
  30. public int Orders { get; set; }
  31. [DisplayName("结单数量")]
  32. public int Checkouts { get; set; }
  33. // 编辑界面无法显示小数, 以后再思考
  34. [DisplayName("结单率")]
  35. [AutoGenerateColumn(Readonly = true)]
  36. public string? CheckoutRates { get => GetCheckoutRates(Checkouts, Orders); set => checkoutRates = value; }
  37. string? checkoutRates;
  38. [DisplayName("合格数量")]
  39. public int Qualifieds { get; set; }
  40. [DisplayName("合格率")]
  41. [AutoGenerateColumn(Readonly = true)]
  42. public string? QualifiedRates { get => GetQualifiedRates(Qualifieds, Checkouts); set => qualifiedRates = value; }
  43. string? qualifiedRates;
  44. [DisplayName("总价值")]
  45. public int Total { get; set; }
  46. [DisplayName("应收款")]
  47. public int Receivables { get; set; }
  48. [DisplayName("已收款")]
  49. public int Received { get; set; }
  50. [AutoGenerateColumn(FormatString = "HH:mm:ss")]
  51. [DisplayName("修改日期")]
  52. public DateTime ModifiedDate { get; set; } = DateTime.Now;
  53. [AutoGenerateColumn(TextEllipsis = true, Visible = false, ShowTips = true, ComponentType = typeof(Textarea))]
  54. [DisplayName("备注")]
  55. public string? Remark { get; set; }
  56. [AutoGenerateColumn(Visible = false, ComponentType = typeof(BootstrapInput<decimal>), Width = 80)]
  57. [DisplayName("Test1")]
  58. public decimal Test1 { get; set; }
  59. private string GetCheckoutRates(int checkouts, int orders) => orders > 0 ? (checkouts /(double) orders).ToString("P2") : "0%";
  60. private string GetQualifiedRates(int qualifieds, int checkouts) => checkouts > 0 ? (qualifieds / (double)checkouts).ToString("P2") : "0%";
  61. }

页面 Pages\ImpExpIII.razor

查看代码
  1. @page "/impexpiii"
  2. @using b14table.Data
  3. @using static Blazor100.Service.ImportExportsService
  4. <PageTitle>综合演示</PageTitle>
  5. <InputFile OnChange="OnChange" style="max-width:400px" class="form-control" />
  6. <br />
  7. <Table @ref="list1"
  8. TItem="SalesChannels"
  9. IsPagination="true"
  10. IsStriped="true"
  11. IsBordered="true"
  12. IsDetails="true"
  13. AutoGenerateColumns="true"
  14. ShowSearch="true"
  15. ShowEmpty="true"
  16. SearchMode="SearchMode.Top"
  17. ShowToolbar="true"
  18. ShowExtendButtons="true"
  19. DataService="DataService"
  20. OnQueryAsync="DataService.QueryAsync"
  21. OnSaveAsync="DataService.SaveAsync"
  22. OnDeleteAsync="DataService.DeleteAsync"
  23. DoubleClickToEdit="@DoubleClickToEdit"
  24. IsMultipleSelect="true"
  25. ShowLineNo="true"
  26. IsExcel="@IsExcel"
  27. ShowDetailRow="_ => true"
  28. ShowCardView="true"
  29. ShowColumnList="true"
  30. ShowFooter="true"
  31. ScrollingDialogContent="true"
  32. EditDialogIsDraggable="true"
  33. EditDialogSize="Size.ExtraLarge"
  34. EditDialogShowMaximizeButton="true"
  35. ShowExportButton
  36. OnExportAsync="ExportAsync"
  37. PageItemsSource="new int[] {10, 20, 50, 100, 200, 500, 1000 }">
  38. <SearchTemplate>
  39. <GroupBox Title="搜索">
  40. <div class="row g-3 form-inline">
  41. <div class="col-12 col-sm-6">
  42. <BootstrapInput @bind-Value="@context.Name" maxlength="50" ShowLabel="true" />
  43. </div>
  44. <div class="col-12 col-sm-6">
  45. <BootstrapInput @bind-Value="@context.Date" maxlength="500" ShowLabel="true" />
  46. </div>
  47. </div>
  48. </GroupBox>
  49. </SearchTemplate>
  50. <DetailRowTemplate>
  51. <div>备注: @context.Remark </div>
  52. </DetailRowTemplate>
  53. <TableFooter Context="context1">
  54. <TableFooterCell Text="当前页小计:" colspan="4" />
  55. <TableFooterCell Text="总价值" colspan="3" />
  56. <TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Total)" />
  57. <TableFooterCell Text="应收款" colspan="3" />
  58. <TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Receivables)" />
  59. <TableFooterCell Text="已收款" colspan="3" />
  60. <TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Received)" />
  61. </TableFooter>
  62. <TableToolbarTemplate>
  63. <TableToolbarButton TItem="SalesChannels" Color="Color.Primary" Text="自由编辑" OnClick="@IsExcelToggle" />
  64. <TableToolbarButton TItem="SalesChannels" Color="Color.Warning" Text="随机数据" IsAsync OnClick="@GetDatasAsync" />
  65. <TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="导入" IsAsync OnClick="@ImportExcel" />
  66. <TableToolbarButton TItem="SalesChannels" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />
  67. <TableToolbarButton TItem="SalesChannels" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />
  68. <TableToolbarButton TItem="SalesChannels" Color="Color.Success" Text="打印" IsAsync OnClickCallback="@PrintPreview" />
  69. <TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="新窗口打开" IsAsync OnClick="@新窗口打开" />
  70. <TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="批量审批" IsAsync OnClickCallback="@批量审批" />
  71. </TableToolbarTemplate>
  72. <ExportButtonDropdownTemplate>
  73. <h6 class="dropdown-header">当前页数据</h6>
  74. <div class="dropdown-item" @onclick="_=>ExportExcelAsync(list1.Rows)">
  75. <i class="fas fa-file-excel"></i>
  76. <span>Excel</span>
  77. </div>
  78. <div class="dropdown-item" @onclick="_=>ExportWordAsync(list1.Rows)">
  79. <i class="fas fa-file-word"></i>
  80. <span>Word</span>
  81. </div>
  82. <div class="dropdown-item" @onclick="_=>ExportHtmlAsync(list1.Rows)">
  83. <i class="fa-brands fa-html5"></i>
  84. <span>Html</span>
  85. </div>
  86. <div class="dropdown-item" @onclick="_=>ExportPDFAsync(list1.Rows)">
  87. <i class="fas fa-file-pdf"></i>
  88. <span>PDF</span>
  89. </div>
  90. <div class="dropdown-divider"></div>
  91. <h6 class="dropdown-header">全部数据</h6>
  92. <div class="dropdown-item" @onclick="_=>ExportExcelAsync(DataService.GetAllItems())">
  93. <i class="fas fa-file-excel"></i>
  94. <span>Excel</span>
  95. </div>
  96. <div class="dropdown-item" @onclick="_=>ExportWordAsync(DataService.GetAllItems())">
  97. <i class="fas fa-file-word"></i>
  98. <span>Word</span>
  99. </div>
  100. <div class="dropdown-item" @onclick="_=>ExportHtmlAsync(DataService.GetAllItems())">
  101. <i class="fa-brands fa-html5"></i>
  102. <span>Html</span>
  103. </div>
  104. <div class="dropdown-item" @onclick="_=>ExportPDFAsync(DataService.GetAllItems())">
  105. <i class="fas fa-file-pdf"></i>
  106. <span>PDF</span>
  107. </div>
  108. </ExportButtonDropdownTemplate>
  109. </Table>

页面代码 Pages\ImpExpIII.razor

查看代码
  1. using AmeBlazor.Components;
  2. using b14table.Data;
  3. using Blazor100.Service;
  4. using BootstrapBlazor.Components;
  5. using Densen.DataAcces.FreeSql;
  6. using DocumentFormat.OpenXml.Spreadsheet;
  7. using Microsoft.AspNetCore.Components;
  8. using Microsoft.AspNetCore.Components.Forms;
  9. using Microsoft.JSInterop;
  10. using System.Diagnostics.CodeAnalysis;
  11. using static Blazor100.Service.ImportExportsService;
  12. namespace b14table.Pages
  13. {
  14. public partial class ImpExpIII
  15. {
  16. [Inject]
  17. IWebHostEnvironment? HostEnvironment { get; set; }
  18. [Inject]
  19. [NotNull]
  20. NavigationManager? NavigationManager { get; set; }
  21. [Inject]
  22. [NotNull]
  23. ImportExportsService? ImportExportsService { get; set; }
  24. [Inject]
  25. [NotNull]
  26. ToastService? ToastService { get; set; }
  27. [Inject]
  28. [NotNull]
  29. FreeSqlDataService<SalesChannels>? DataService { get; set; }
  30. [NotNull]
  31. Table<SalesChannels>? list1 { get; set; }
  32. [Parameter] public int Footercolspan1 { get; set; } = 3;
  33. [Parameter] public int Footercolspan2 { get; set; } = 2;
  34. [Parameter] public int Footercolspan3 { get; set; }
  35. [Parameter] public int FootercolspanTotal { get; set; } = 2;
  36. [Parameter] public string? FooterText { get; set; } = "合计:";
  37. [Parameter] public string? FooterText2 { get; set; }
  38. [Parameter] public string? FooterText3 { get; set; }
  39. [Parameter] public string? FooterTotal { get; set; }
  40. /// <summary>
  41. /// 获得/设置 IJSRuntime 实例
  42. /// </summary>
  43. [Inject]
  44. [NotNull]
  45. protected IJSRuntime? JsRuntime { get; set; }
  46. [Parameter] public string? 新窗口打开Url { get; set; } = "https://localhost:7292/";
  47. // 由于使用了FreeSql ORM 数据服务,可以直接取对象
  48. [Inject]
  49. [NotNull]
  50. IFreeSql? fsql { get; set; }
  51. [Inject] ToastService? toastService { get; set; }
  52. [Inject] SwalService? SwalService { get; set; }
  53. public bool IsExcel { get; set; }
  54. public bool DoubleClickToEdit { get; set; } = true;
  55. protected string UploadPath = "";
  56. protected string? uploadstatus;
  57. long maxFileSize = 1024 * 1024 * 15;
  58. string? tempfilename;
  59. private AggregateType Aggregate { get; set; }
  60. protected async Task GetDatasAsync()
  61. {
  62. var datas = GetDemoDatas();
  63. await fsql.Insert<SalesChannels>().AppendData(datas).ExecuteAffrowsAsync();
  64. await list1!.QueryAsync();
  65. }
  66. protected override async void OnAfterRender(bool firstRender)
  67. {
  68. if (firstRender)
  69. {
  70. UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "uploads");
  71. if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath);
  72. await list1!.QueryAsync();
  73. }
  74. }
  75. protected override async Task OnAfterRenderAsync(bool firstRender)
  76. {
  77. if (firstRender)
  78. {
  79. //懒的人,直接初始化一些数据用用
  80. var res = fsql.Select<SalesChannels>().Count();
  81. if (res == 0)
  82. {
  83. var datas = GetDemoDatas();
  84. await fsql.Insert<SalesChannels>().AppendData(datas).ExecuteAffrowsAsync();
  85. await list1!.QueryAsync();
  86. }
  87. }
  88. }
  89. public List<SalesChannels> GetDemoDatas()
  90. {
  91. var list = new List<SalesChannels>();
  92. for (int i = 0; i < 100; i++)
  93. {
  94. try
  95. {
  96. var total = Random.Shared.Next(100, 3000);
  97. list.Add(new SalesChannels()
  98. {
  99. ID = i,
  100. Name = "渠道" + i,
  101. Date = DateTime.Now,
  102. Projects = Random.Shared.Next(10, 55),
  103. Orders = Random.Shared.Next(3, 10),
  104. Qualifieds = i,
  105. Total = total,
  106. Receivables = total - i,
  107. Received = i,
  108. Remark= $"{i} 明细行内嵌套另外一个 Table 组件,由于每行都要关联子表数据,出于性能的考虑,此功能采用 懒加载 模式,即点击展开按钮后,再对嵌套 Table 进行数据填充,通过 ShowDetailRow 回调委托可以控制每一行是否显示明细行,本例中通过 Complete 属性来控制是否显示明细行,可通过翻页来测试本功能"
  109. });
  110. }
  111. catch (Exception e)
  112. {
  113. System.Console.WriteLine(e.Message);
  114. }
  115. }
  116. return list;
  117. }
  118. private Task IsExcelToggle()
  119. {
  120. IsExcel = !IsExcel;
  121. DoubleClickToEdit = !IsExcel;
  122. StateHasChanged();
  123. return Task.CompletedTask;
  124. }
  125. public async Task<bool> Export模板Async()
  126. {
  127. await Export();
  128. return true;
  129. }
  130. private async Task<bool> ExportExcelAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Excel);
  131. private async Task<bool> ExportPDFAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Pdf);
  132. private async Task<bool> ExportWordAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Word);
  133. private async Task<bool> ExportHtmlAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Html);
  134. private async Task<bool> ExportAutoAsync(IEnumerable<SalesChannels> items, ExportType exportType = ExportType.Excel)
  135. {
  136. if (items == null || !items.Any())
  137. {
  138. await ToastService.Error("提示", "无数据可导出");
  139. return false;
  140. }
  141. var option = new ToastOption()
  142. {
  143. Category = ToastCategory.Information,
  144. Title = "提示",
  145. Content = $"导出正在执行,请稍等片刻...",
  146. IsAutoHide = false
  147. };
  148. // 弹出 Toast
  149. await ToastService.Show(option);
  150. await Task.Delay(100);
  151. // 开启后台进程进行数据处理
  152. await Export(items?.ToList(), exportType);
  153. // 关闭 option 相关联的弹窗
  154. option.Close();
  155. // 弹窗告知下载完毕
  156. await ToastService.Show(new ToastOption()
  157. {
  158. Category = ToastCategory.Success,
  159. Title = "提示",
  160. Content = $"导出成功,请检查数据",
  161. IsAutoHide = false
  162. });
  163. return true;
  164. }
  165. private async Task Export(List<SalesChannels>? items = null, ExportType exportType = ExportType.Excel)
  166. {
  167. try
  168. {
  169. if (items == null || !items.Any())
  170. {
  171. ToastService?.Error($"导出", $"{exportType}出错,无数据可导出");
  172. return;
  173. }
  174. var fileName = items == null ? "模板" : typeof(SalesChannels).Name;
  175. var fullName = Path.Combine(UploadPath, fileName);
  176. fullName = await ImportExportsService.Export(fullName, items, exportType);
  177. fileName = (new System.IO.FileInfo(fullName)).Name;
  178. ToastService?.Success("提示", fileName + "已生成");
  179. //下载后清除文件
  180. NavigationManager.NavigateTo($"uploads/{fileName}", true);
  181. _ = Task.Run(() =>
  182. {
  183. Thread.Sleep(50000);
  184. System.IO.File.Delete(fullName);
  185. });
  186. }
  187. catch (Exception e)
  188. {
  189. ToastService?.Error($"导出", $"{exportType}出错,请检查. {e.Message}");
  190. }
  191. }
  192. public async Task<bool> EmptyAll()
  193. {
  194. fsql.Delete<SalesChannels>().Where(a => 1 == 1).ExecuteAffrows();
  195. await ToastService!.Show(new ToastOption()
  196. {
  197. Category = ToastCategory.Success,
  198. Title = "提示",
  199. Content = "已清空数据",
  200. });
  201. await list1!.QueryAsync();
  202. return true;
  203. }
  204. private async Task ImportExcel()
  205. {
  206. if (string.IsNullOrEmpty(tempfilename))
  207. {
  208. ToastService?.Error("提示", "请正确选择文件上传");
  209. return;
  210. }
  211. var option = new ToastOption()
  212. {
  213. Category = ToastCategory.Information,
  214. Title = "提示",
  215. Content = "导入文件中,请稍等片刻...",
  216. IsAutoHide = false
  217. };
  218. // 弹出 Toast
  219. await ToastService!.Show(option);
  220. await Task.Delay(100);
  221. // 开启后台进程进行数据处理
  222. var isSuccess = await MockImportExcel();
  223. // 关闭 option 相关联的弹窗
  224. option.Close();
  225. // 弹窗告知下载完毕
  226. await ToastService.Show(new ToastOption()
  227. {
  228. Category = isSuccess ? ToastCategory.Success : ToastCategory.Error,
  229. Title = "提示",
  230. Content = isSuccess ? "操作成功,请检查数据" : "出现错误,请重试导入或者上传",
  231. IsAutoHide = false
  232. });
  233. await list1!.QueryAsync();
  234. }
  235. private async Task<bool> MockImportExcel()
  236. {
  237. var items_temp = await ImportExportsService!.ImportFormExcel<SalesChannels>(tempfilename!);
  238. if (items_temp.items == null)
  239. {
  240. ToastService?.Error("提示", "文件导入失败: " + items_temp.error);
  241. return false;
  242. }
  243. //items = SmartCombine(items_temp, items).ToList(); 新数据和老数据合并处理,略100字
  244. await fsql.Insert<SalesChannels>().AppendData(items_temp!.items.ToList()).ExecuteAffrowsAsync();
  245. return true;
  246. }
  247. protected async Task OnChange(InputFileChangeEventArgs e)
  248. {
  249. if (e.File == null) return;
  250. tempfilename = Path.Combine(UploadPath, e.File.Name);
  251. await using FileStream fs = new(tempfilename, FileMode.Create);
  252. using var stream = e.File.OpenReadStream(maxFileSize);
  253. await stream.CopyToAsync(fs);
  254. //正式工程此处是回调,简化版必须InvokeAsync一下,自由发挥
  255. _ = Task.Run(async () => await InvokeAsync(async () => await ImportExcel()));
  256. }
  257. /// <summary>
  258. /// 导出数据方法
  259. /// </summary>
  260. /// <param name="Items"></param>
  261. /// <param name="opt"></param>
  262. /// <returns></returns>
  263. protected async Task<bool> ExportAsync(IEnumerable<SalesChannels> Items, QueryPageOptions opt)
  264. {
  265. var ret = await ExportExcelAsync(Items);
  266. return ret;
  267. }
  268. public Task PrintPreview(IEnumerable<SalesChannels> item)
  269. {
  270. //实际工程自己完善js打印
  271. JsRuntime.InvokeVoidAsync("printDiv");
  272. return Task.CompletedTask;
  273. }
  274. private Task 新窗口打开()
  275. {
  276. if (string.IsNullOrEmpty(新窗口打开Url))
  277. {
  278. ToastService?.Error("提示", "Url为空!");
  279. return Task.CompletedTask;
  280. }
  281. JsRuntime.NavigateToNewTab(新窗口打开Url);
  282. return Task.CompletedTask;
  283. }
  284. public async Task 批量审批(IEnumerable<SalesChannels> items)
  285. {
  286. items.ToList().ForEach(a =>
  287. {
  288. a.Checkouts = a.Orders;
  289. a.Receivables = 0;
  290. a.Received = a.Total;
  291. a.ModifiedDate = DateTime.Now;
  292. });
  293. var res = await fsql.Update<SalesChannels>().SetSource(items).ExecuteAffrowsAsync();
  294. await SwalService!.Show(new SwalOption()
  295. {
  296. Title = res == 0 ? "提示: 操作失败" : "提示: 操作成功"
  297. });
  298. if (res != 0) await list1!.QueryAsync();
  299. }
  300. }
  301. }

预览

输入图片说明

源代码

https://gitee.com/densen2014/Blazor100/tree/master/b04table

https://github.com/densen2014/Blazor100/tree/master/b04table

项目地址

https://gitee.com/LongbowEnterprise/BootstrapBlazor

项目Wiki

https://gitee.com/LongbowEnterprise/BootstrapBlazor/wikis/QuickStart/[硬核] Table 综合演示例子?sort_id=7452536

原文链接:https://www.cnblogs.com/densen2014/p/17053020.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号