BootstrapBlazor+FreeSql实战 Chart 图表使用(2)
2022-04-04 08:09
866 查看
接上篇 BootstrapBlazor实战 Chart 图表使用(1)
13.添加必备的库
使用 nuget.org 进行 BootstrapBlazor 组件安装, FreeSql库,Newtonsoft.Json
dotnet add b06chart package Densen.FreeSql.Extensions.BootstrapBlazor dotnet add b06chart package FreeSql.Provider.Sqlite dotnet add b06chart package Newtonsoft.Json
14. 数据服务
添加FreeSql服务到
Program.cs到 在
builder.Services.AddBootstrapBlazor();之前加入
builder.Services.AddFreeSql(option => { //demo演示的是Sqlite驱动,FreeSql支持多种数据库,MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/翰高/华为GaussDB/MsAccess option.UseConnectionString(FreeSql.DataType.Sqlite, "Data Source=test.db;") //也可以写到配置文件中 #if DEBUG //开发环境:自动同步实体 .UseAutoSyncStructure(true) .UseNoneCommandParameter(true) //调试sql语句输出 .UseMonitorCommand(cmd => System.Console.WriteLine(cmd.CommandText)) #endif ; });
15. 添加实体类Model/OrdersEntry.cs
using BootstrapBlazor.Components; using FreeSql.DataAnnotations; using Newtonsoft.Json; using System.ComponentModel; using System.Linq; namespace Blazor100.Data; public partial class Orders { /// <summary> /// 流水号 /// </summary> [AutoGenerateColumn(Editable = false, DefaultSort = true, DefaultSortOrder = SortOrder.Desc, Order = 1)] [JsonProperty, Column(IsIdentity = true)] [DisplayName("流水号")] public int OrderID { get; set; } /// <summary> /// 单据日期 /// </summary> [AutoGenerateColumn(FormatString = "yyyy-MM-dd", ComponentType = typeof(DatePickerBody))] [JsonProperty] [DisplayName("日期")] public DateTime OrderDate { get; set; } /// <summary> /// 合计金额 /// </summary> [AutoGenerateColumn(FormatString = "N2", Align = Alignment.Right)] [JsonProperty, Column(DbType = "decimal(19,4)")] [DisplayName("合计")] public decimal SubTotal { get; set; } [AutoGenerateColumn(Ignore = true)] [Navigate(nameof(OrderID))] public virtual List<OrderDetails>? OrderDetailss { get; set; } } } /// <summary> /// 订单详单 /// </summary> public partial class OrderDetails { [JsonProperty, Column(IsIdentity = true)] public int ID { get; set; } [JsonProperty] public int OrderID { get; set; } [JsonProperty, Column(StringLength = -1)] [DisplayName("条码")] public string? BarCode { get; set; } [AutoGenerateColumn(FormatString = "N0", Align = Alignment.Center)] [JsonProperty, Column(DbType = "numeric(18,3)")] [DisplayName("数量")] public decimal Quantity { get; set; } [AutoGenerateColumn(Ignore = true)] [Navigate(nameof(OrderID))] public virtual Orders Orders { get; set; } }
16. 添加命名空间引用Shared/_Imports.razor
@using Blazor100.Data
17.添加NavLink到Shared/NavMenu.razor
<div class="nav-item px-3"> <NavLink class="nav-link" href="DayReport"> 月报 </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="TopSales"> 排行榜 </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="YearsCharts"> 年报 </NavLink> </div>
18.将组件Chart封装,添加文件Components/ChartsBase.razor
@namespace b06chart @if (!IsHideSelectores) { <span> @Year 年</span> <span> @Month 月</span> <span> 合计 : @(Total.ToString("N2")) @TotalString2 @TotalString3 </span> } <div class="text-center mt-2 chart"> @if (!IsHideSelectores && UseDateTimeRangeValue) { <DateTimeRange @bind-Value="@DateTimeRangeValue1" OnConfirm="OnConfirm" OnClearValue="OnClear" /> } <div class="btn-group"> @if (!IsHideSelectores) { for (int i = DateTime.Now.Year - 7; i <= DateTime.Now.Year; i++) { var year = i; <Button Color="Color.Primary" IsOutline="@(Year!=year)" Text="@year.ToString()" OnClick="(()=>SetYear(year))" /> } } <Button Color="Color.Primary" IsOutline="true" OnClick="SwitchChart"><i class="fa @(IsLineChart?"fa-bar-chart":"fa-line-chart")"></i><span>切换</span></Button> <Button Color="Color.Primary" IsOutline="true" OnClick="SwitchStacked"><i class="fa @(IsStacked?"fa-toggle-on":"fa-toggle-off")"></i><span>@(IsStacked? "合并" : "不合并")</span></Button> <Button Color="Color.Primary" IsOutline="true" OnClick="e=>ReloadChart(true)"><i class="fa fa-refresh"></i><span>刷新</span></Button> </div> </div> @if (!IsHideSelectores && IsShowMonthSelector) { <div class="text-center mt-2 chart"> <div class="btn-group"> @{ for (int i = 1; i <= 12; i++) { var month = i; <Button Color="Color.Primary" IsOutline="@(Month!=month)" Text="@month.ToString()" OnClick="(()=>SetMonth(month))" /> } } <Button Color="Color.Primary" IsOutline="true" OnClick="PreMonth"><i class="fa fa-calendar-minus-o"></i><span>上月</span></Button> <Button Color="Color.Primary" IsOutline="true" OnClick="NextMonth"><i class="fa fa-calendar-plus-o"></i><span>下月</span></Button> <Button Color="Color.Primary" IsOutline="true" OnClick="SetNow"><i class="fa fa-calendar-check-o"></i><span>本月</span></Button> </div> </div> } <div style="width: calc(80%);display: block;margin: 0 auto;"> @if (Show) { if (!IsLineChart) { <Chart ChartType="ChartType.Bar" OnInitAsync="OnInit" @ref="BarChart" Width="" /> } else { <Chart OnInitAsync="OnInit" @ref="LineChart" /> } } </div>
添加后置代码
Components/ChartsBase.razor.cs
using BootstrapBlazor.Components; using Microsoft.AspNetCore.Components; using System.Diagnostics.CodeAnalysis; namespace b06chart { public partial class ChartsBase { private Chart? LineChart { get; set; } private Chart? BarChart { get; set; } /// <summary> /// 设定当前年份 /// </summary> [Parameter] public int Year { get; set; } = DateTime.Now.Year; /// <summary> /// 设定当前月份 /// </summary> [Parameter] public int Month { get; set; } = DateTime.Now.Month; /// <summary> /// 设定图表抬头 /// </summary> [Parameter] public string TitleCharts { get; set; } = "日报表"; /// <summary> /// 设定X轴文本 /// </summary> [Parameter] public string XAxesText { get; set; } = "天数"; /// <summary> /// 设定Y轴文本 /// </summary> [Parameter] public string YAxesText { get; set; } = "数值"; /// <summary> /// 图表类型:是=LineChart,否=BarChart /// </summary> [Parameter] public bool IsLineChart { get; set; } /// <summary> /// 使用默认数据 /// </summary> [Parameter] public bool IsDemo { get; set; } /// <summary> /// 显示月份选择器 /// </summary> [Parameter] public bool IsShowMonthSelector { get; set; } = true; [Parameter] public EventCallback<ChartDataSource> OnInitCallback { get; set; } [Parameter] public EventCallback<ChartDataSource> 数据生成Callback { get; set; } [Parameter] public decimal Total { get; set; } [Parameter] public string? TotalString2 { get; set; } [Parameter] public string? TotalString3 { get; set; } /// <summary> /// 隐藏选择器 /// </summary> [Parameter] public bool IsHideSelectores { get; set; } /// <summary> /// 使用/初始化日期选择控件日期 /// </summary> [Parameter] public bool UseDateTimeRangeValue { get; set; } /// <summary> /// 是否合并Bar显示 默认false /// </summary> public bool IsStacked { get; set; } /// <summary> /// 强刷显示控件控制,Hack一下 /// </summary> private bool Show { get; set; } = true; public int LastCount { get; set; } public bool FirstLoad { get; set; } = true; public bool ForceRefresh { get; set; } private string? ClickItemID { get; set; } private IEnumerable<string> Colors { get; set; } = new List<string>() { "Blue", "Green", "Red", "Orange", "Yellow", "Tomato", "Pink", "Violet" }; #region 日期选择控件 private DateTimeRangeValue DateTimeRangeValue1 { get; set; } = new DateTimeRangeValue(); DateTime 起始日期 = DateTime.Today.FirstDay(); DateTime 结束日期 = DateTime.Today.LastDay(); private Task OnConfirm(DateTimeRangeValue value) { 起始日期 = value.Start.FirstSecond(); 结束日期 = value.End.Year == 1 ? value.Start.LastSecond() : value.End.LastSecond(); Chart? chart = IsLineChart ? LineChart : BarChart; chart?.Update(ChartAction.Update); //StateHasChanged(); return Task.CompletedTask; } private Task OnClear(DateTimeRangeValue value) { 起始日期 = DateTime.Today.FirstDay(); 结束日期 = DateTime.Today.LastDay(); Chart? chart = IsLineChart ? LineChart : BarChart; chart?.Update(ChartAction.Update); //StateHasChanged(); return Task.CompletedTask; } /// <summary> /// 设置日期选择控件日期 /// </summary> /// <param name="_起始日期"></param> /// <param name="_结束日期"></param> /// <returns></returns> protected Task SetDates(DateTime _起始日期, DateTime _结束日期) { 起始日期 = _起始日期; 结束日期 = _结束日期; DateTimeRangeValue1.Start = 起始日期; DateTimeRangeValue1.End = 结束日期; return Task.CompletedTask; } #endregion protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (UseDateTimeRangeValue && firstRender) { DateTimeRangeValue1.Start = 起始日期; DateTimeRangeValue1.End = 结束日期; } } private Task OnAfterInit() { System.Console.WriteLine("Bar 初始化完毕"); return Task.CompletedTask; } /// <summary> /// 初始化 ChartDataSource /// </summary> /// <returns></returns> protected Task<ChartDataSource> OnInit() { var ds = new ChartDataSource(); if (!OnInitCallback.HasDelegate) { ds.Options.Title = TitleCharts; ds.Options.X.Title = XAxesText; ds.Options.X.Stacked = IsStacked; ds.Options.Y.Title = YAxesText; ds.Options.Y.Stacked = IsStacked; } else { OnInitCallback.InvokeAsync(ds); } //设置自定义颜色 ds.Options.Colors = new Dictionary<string, string>() { { "blue:", "rgb(54, 162, 235)" }, { "green:", "rgb(75, 192, 192)" }, { "red:", "rgb(255, 99, 132)" }, { "orange:", "rgb(255, 159, 64)" }, { "yellow:", "rgb(255, 205, 86)" }, { "tomato:", "rgb(255, 99, 71)" }, { "pink:", "rgb(255, 192, 203)" }, { "violet:", "rgb(238, 130, 238)" }, }; if (!数据生成Callback.HasDelegate) 数据生成(ds); else 数据生成Callback.InvokeAsync(ds); if (ds.Labels ==null || ds.Labels!.Count() == 0) { LastCount = 0; Show = false; return Task.FromResult(ds); } Show = true; ForceRefresh = LastCount == 0 || LastCount < ds.Labels!.Count(); LastCount = ds.Labels!.Count(); if (!FirstLoad && ForceRefresh) { ReloadChart(); ForceRefresh = false; } FirstLoad = false; return Task.FromResult(ds); } /// <summary> /// 数据生成,添加Labels和ChartDataset /// </summary> /// <param name="ds"></param> protected virtual void 数据生成(ChartDataSource ds) { } private Task SetYear(int year) { Chart? chart = IsLineChart ? LineChart : BarChart; Year = year; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task SetMonth(int month) { Chart? chart = IsLineChart ? LineChart : BarChart; Month = month; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task PreMonth() { Chart? chart = IsLineChart ? LineChart : BarChart; Year = Month - 1 >= 1 ? Year : Year - 1; Month = Month - 1 >= 1 ? Month - 1 : 12; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task NextMonth() { Chart? chart = IsLineChart ? LineChart : BarChart; Year = Month + 1 <= 12 ? Year : Year + 1; Month = Month + 1 <= 12 ? Month + 1 : 1; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task SetNow() { Chart? chart = IsLineChart ? LineChart : BarChart; Year = DateTime.Now.Year; Month = DateTime.Now.Month; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task RandomData() { Chart? chart = IsLineChart ? LineChart : BarChart; chart?.Update(ChartAction.Update); return Task.CompletedTask; } private Task SwitchChart() { IsLineChart = !IsLineChart; return Task.CompletedTask; } /// <summary> /// 切换合并显示 /// </summary> private void SwitchStacked() { IsStacked = !IsStacked; ReloadChart(); } /// <summary> /// 强刷控件,重新初始化控件外观 /// </summary> private async void ReloadChart(bool reloadData=false) { Chart? chart = IsLineChart ? LineChart : BarChart; if (reloadData) chart?.Update(ChartAction.Update); Show = false; await InvokeAsync(StateHasChanged); await Task.Delay(1); Show = true; await InvokeAsync(StateHasChanged); } } public static class DateTimeExtensions { public static DateTime FirstDay(this DateTime obj) => new DateTime(obj.Year, obj.Month, 1, 0, 0, 0); public static DateTime LastDay(this DateTime obj) => obj.FirstDay().AddMonths(1).AddDays(-1).LastSecond(); public static DateTime FirstSecond(this DateTime obj) => new DateTime(obj.Year, obj.Month, obj.Day, 0, 0, 0); public static DateTime LastSecond(this DateTime obj) => new DateTime(obj.Year, obj.Month, obj.Day, 23, 59, 59); } }
19.添加日报表页面`Pages/DayReport.razor'
@page "/DayReport" @namespace b06chart <Tab> <TabItem Text="日报表"> <ChartsBase @ref="charts" TitleCharts="日报表" 数据生成Callback="@((ds)=>数据生成(ds))" Total="@Total" TotalString2="@TotalString2" /> </TabItem> <TabItem Text="数据"> <Table TItem="Orders" IsPagination="true" IsStriped="true" IsBordered="true" AutoGenerateColumns="true" ShowSearch="true" ShowToolbar="true" ShowExtendButtons="true" DoubleClickToEdit=true ShowColumnList=true ShowCardView=true> </Table> </TabItem> </Tab>
添加后置代码
Pages/DayReport.razor.cs
using Blazor100.Data; using BootstrapBlazor.Components; using Microsoft.AspNetCore.Components; using System.Diagnostics.CodeAnalysis; namespace b06chart { public partial class DayReport { [Inject] [NotNull] IFreeSql? fsql { get; set; } [Inject] ToastService? toastService { get; set; } List<Orders> orders { get; set; } = new List<Orders>(); ChartsBase? charts; decimal Total { get; set; } string? TotalString2 { get; set; } private Task 数据生成(ChartDataSource ds) { var orders = fsql.Select<Orders>() .Where(a => a.OrderDate.Month == charts!. Month && a.OrderDate.Year == charts.Year) .GroupBy(a => new { a.OrderDate.Day }) .ToList(a => new { cou1 = a.Count(), OrderDate = a.Key.Day, Total = a.Sum(a.Value.SubTotal) }); orders = orders.OrderBy(a => a.OrderDate).ToList(); ds.Labels = orders.Select(a => a.OrderDate.ToString()); ds.Data.Add(new ChartDataset() { Label = $"单据数", Data = orders.Select(a => a.cou1).Cast<object>() }); ds.Data.Add(new ChartDataset() { Label = $"金额", Data = orders.Select(a => a.Total).Cast<object>() }); Total = orders.Select(a => a.Total).Sum(); return Task.CompletedTask; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { Orders.DemoDatas(fsql!); } } } }
20.添加年报表页面`Pages/YearsCharts.razor'
@page "/YearsCharts" @namespace b06chart <ChartsBase @ref="charts" TitleCharts="年报表" XAxesText="月" IsShowMonthSelector="false" 数据生成Callback="@((ds)=>数据生成(ds))" Total="@Total" />
添加后置代码
Pages/YearsCharts.razor.cs
using Blazor100.Data; using BootstrapBlazor.Components; using Microsoft.AspNetCore.Components; using System.Diagnostics.CodeAnalysis; namespace b06chart { public partial class YearsCharts { [Inject] [NotNull] IFreeSql? fsql { get; set; } [Inject] ToastService? toastService { get; set; } List<Orders> orders { get; set; } = new List<Orders>(); ChartsBase? charts; decimal Total { get; set; } string? TotalString2 { get; set; } private Task 数据生成(ChartDataSource ds) { var orders = fsql.Select<Orders>() .Where(a => a.OrderDate.Year == charts!.Year) .GroupBy(a => new { a.OrderDate.Month }) .ToList(a => new { cou1 = a.Count(), OrderDate = a.Key.Month, Total = a.Sum(a.Value.SubTotal) }); orders = orders.OrderBy(a => a.OrderDate).ToList(); ds.Labels = orders.Select(a => a.OrderDate.ToString()); ds.Data.Add(new ChartDataset() { Label = $"单据数", Data = orders.Select(a => a.cou1).Cast<object>() }); ds.Data.Add(new ChartDataset() { Label = $"金额", Data = orders.Select(a => a.Total).Cast<object>() }); Total = orders.Select(a => a.Total).Sum(); return Task.CompletedTask; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { Orders.DemoDatas(fsql!); } } } }
21.添加排行榜页面Pages/OrdersTopSalesCharts.razor
@page "/TopSales" @namespace b06chart <Tab> <TabItem Text="销售排行榜"> <ChartsBase @ref="charts" TitleCharts="销售排行榜" 数据生成Callback="@((ds)=>数据生成(ds))" Total="@Total" /> </TabItem> <TabItem Text="数据"> <Table TItem="OrderDetails" IsPagination="true" IsStriped="true" IsBordered="true" AutoGenerateColumns="true" ShowSearch="true" ShowToolbar="true" ShowExtendButtons="true" DoubleClickToEdit=true ShowColumnList=true ShowCardView=true> </Table> </TabItem> </Tab>
添加后置代码
Pages/OrdersTopSalesCharts.razor.cs
using Blazor100.Data; using BootstrapBlazor.Components; using Microsoft.AspNetCore.Components; namespace b06chart { public partial class OrdersTopSalesCharts { [Inject] IFreeSql? fsql { get; set; } [Inject] ToastService? toastService { get; set; } List<OrderDetails> orders { get; set; } = new List<OrderDetails>(); ChartsBase? charts; decimal Total { get; set; } private Task 数据生成(ChartDataSource ds) { var 起始日期 = (new DateTime(charts!.Year, charts.Month, 1)).FirstDay(); var 结束日期 = 起始日期.LastDay(); orders = fsql!.Select<OrderDetails>() .Where( a => a.Orders.OrderDate.Between(起始日期, 结束日期)) .GroupBy(a => a.BarCode ) .OrderByDescending(a => a.Sum(a.Value.Quantity)) .ToList(a => new OrderDetails { BarCode = a.Key, Quantity = a.Sum(a.Value.Quantity) } ); ds.Labels = orders.Select(a => $"{a.BarCode}"); ds.Data.Add(new ChartDataset() { Label = $"销售量", Data = orders.Select(a => a.Quantity).Cast<object>() }); Total = orders.Sum(a => a.Quantity); return Task.CompletedTask; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { Orders.DemoDatas(fsql!); } } } }
22.本次封装代码来源于本人实际项目,逻辑部分还存在很大优化的空间,目前还有个别bug没整理干净. 望大家有更好的方案,在评论区多多指正,我一定虚心学习, 共同进步.
项目源码
关联项目
FreeSql QQ群:4336577(已满)、8578575(已满)、52508226(在线)
BA & Blazor QQ群:795206915、675147445
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。
AlexChow
相关文章推荐
- 如何使用一个不错的图表组件WebChart(免费) 用c#编写
- 数据图表DBChart的使用
- 实战:ORACLE SQL Performance Analyzer的使用
- 在 Web 页面中使用图表(chart)表现数据
- jQuery 图表插件 jqChart 使用
- python使用open flash chart生成图表(基于pyofc2)
- pChart图表插件使用
- 在ASP中使用ASPChart组件生成图表
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 在.NET中不安装Office使用EPPlus生成带图表(Chart)的Excel报表
- 使用Open Flash Chart(OFC)制作图表(Struts2处理)
- PHP实战 新闻管理系统 使用到了bootstrap框架
- ajax读取数据后使用jqchart显示图表的方法
- Ionic中使用Chart.js进行图表展示以及在iOS/Android中的性能差异
- C#串口采集短信GSM chart图表使用示例 保存数据到access数据库和每日.txt文件并实时显示各参数曲线
- 使用freeChart 例子
- FusionChart图表控件使用说明
- Nevron Chart教程(2):多轴图表的使用---Nevron Chart图轴对接
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- AChartEngine使用View显示图表