当前位置:网站首页>BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

2022-06-27 00:05:00 站长号

接上篇 BootstrapBlazor实战 Chart 图表使用(1)

13.添加必备的库

使用 nuget.org 进行 BootstrapBlazor 组件安装, FreeSql库,Newtonsoft.Json

dotnet add b06chart package Densen.FreeSql.Extensions.BootstrapBlazordotnet add b06chart package FreeSql.Provider.Sqlitedotnet 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


BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

@namespace [email protected] (!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'


BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

@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'


BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

@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


BootstrapBlazor + FreeSql实战 Chart 图表使用(2)

@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没整理干净. 望大家有更好的方案,在评论区多多指正,我一定虚心学习, 共同进步.

项目源码

[Github] https://github.com/densen2014/Blazor100

[Gitee] https://gitee.com/densen2014/Blazor100

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。

AlexChow

今日头条 | 博客园 | 知乎 | Gitee | GitHub

原网站

版权声明
本文为[站长号]所创,转载请带上原文链接,感谢
https://www.seoxiehui.cn/article-358305-1.html