基于Blazor实现的简易进销存管理系统

本文主要介绍如何使用Known开发框架来开发Blazor项目,下面我们用简易进销存管理系统作为示例来分析和设计,文中的代码为关键示例代码,不能直接运行,如要运行查看效果,可在码云上下载完整项目源码运行。

源码地址:https://gitee.com/known/JxcLite

1. 系统需求

  • 可以维护商品信息库,采购进货单可以从中选择商品,销售出货从库存中选择商品;
  • 采购进货和销售出货支持月结和现金结算,月结的单据需要与客户和供应商对账单;
  • 采购和销售需支持退货;
  • 提供库存查询、进出退货明细、利润表等报表功能;
  • 支持单机桌面版和云Web版。

2. 功能模块

  • 基础数据:包含数据字典、组织结构、商品信息、供应商、客户管理。
  • 进货管理:包含采购进货单、采购退货单。
  • 销货管理:包含销售出货单、销售退货单。
  • 库存管理:包含商品库存查询。
  • 财务管理:包含客户对账单、供应商对账单。
  • 统计报表:包含进货明细表、进退货明细表、销货明细表、销退货明细表、商品利润表。
  • 系统管理:包含角色管理、用户管理、系统附件、系统日志。

3. 项目结构

├─JxcLite          -> 包含配置、常量、枚举、模型、服务接口、路由、页面。 ├─JxcLite.Core     -> 后端类库,包含实体、业务逻辑、数据访问。 ├─JxcLite.Wasm     -> 项目WebAssembly,Auto模式前端程序。 ├─JxcLite.Web      -> 项目Web App,云Web程序。 ├─JxcLite.WinForm  -> 项目WinForm App,单机桌面程序。 ├─JxcLite.sln      -> 项目解决方案文件。 

4. 框架搭建

打开VS2022创建一个空的解决方案JxcLite.sln,然后再添加各个项目。

4.1. JxcLite项目

  • 添加JxcLite类库,引用Known 3.*,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk.Razor">     <ItemGroup>         <PackageReference Include="Known" Version="3.*" />     </ItemGroup> </Project> 
  • 项目文件结构
├─wwwroot         -> 静态文件夹,包含css、img、js,桌面和Web共用资产。 ├─Apps            -> 移动端页面文件夹。 ├─Models          -> 前后端数据交互模型文件夹。 ├─Pages           -> PC端页面文件夹。 ├─Services        -> 前后端数据交互服务接口和Http客户端文件夹。 ├─Shared          -> 模块共享组件文件夹。 ├─_Imports.razor  -> 全局命名空间引用文件。 ├─AppConfig.cs    -> 系统配置类。 ├─AppConstant.cs  -> 系统所有常量类文件。 ├─AppEnums.cs     -> 系统所有枚举文件。 ├─AppModule.cs    -> 系统一级模块配置类。 ├─Routes.razor    -> 系统路由组件。 

4.2. JxcLite.Core项目

  • 添加JxcLite.Core类库,引用JxcLite项目和Known.Core 3.*等库,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk">     <ItemGroup>         <PackageReference Include="Known.Cells" Version="1.*" />         <PackageReference Include="Known.Core" Version="3.*" />         <ProjectReference Include="..JxcLiteJxcLite.csproj" />     </ItemGroup> </Project> 
  • 项目文件结构
├─Entities      -> 实体类文件夹。 ├─Extensions    -> 后端业务扩展类文件夹。 ├─Imports       -> 数据导入类文件夹。 ├─Repositories  -> 数据访问类文件夹,SQL语句都写在此处。 ├─Services      -> 业务逻辑服务实现类文件夹。 ├─_Imports.cs   -> 全局命名空间引用文件。 ├─AppCore.cs    -> 后端配置类。 

4.3. JxcLite.Wasm项目

  • 添加JxcLite.Wasm类库,引用JxcLite项目和WebAssembly等库,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">     <ItemGroup>         <ProjectReference Include="..JxcLiteJxcLite.csproj" />     </ItemGroup> </Project> 
  • 该项目只有一个Wasm程序入口文件Program.cs
├─Program.cs  -> Wasm程序入口。 

4.4. JxcLite.Web项目

  • 添加JxcLite.Web类库,引用JxcLite.CoreJxcLite.Wasm项目,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk.Web">     <ItemGroup>         <ProjectReference Include="..JxcLite.CoreJxcLite.Core.csproj" />         <ProjectReference Include="..JxcLite.WasmJxcLite.Wasm.csproj" />     </ItemGroup> </Project> 
  • 项目文件结构
├─wwwroot          -> 静态文件夹。 ├─_Imports.razor   -> 全局命名空间引用文件。 ├─App.razor        -> 主程序。 ├─appsettings.json -> 配置文件。 ├─Program.cs       -> Web程序入口。 

4.5. JxcLite.WinForm项目

  • 添加JxcLite.WinForm类库,引用JxcLite.Core项目,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk.Razor">     <ItemGroup>         <ProjectReference Include="..JxcLite.CoreJxcLite.Core.csproj" />     </ItemGroup> </Project> 
  • 项目文件结构
├─wwwroot        -> 静态文件夹,包含css、img、index.html。 ├─_Imports.razor -> 全局命名空间引用文件。 ├─App.razor      -> 主程序路由。 ├─AppSetting.cs  -> 程序设置类。 ├─Dialog.cs      -> WinForm对话框类。 ├─favicon.ico    -> 图标。 ├─MainForm.cs    -> 主窗体。 ├─Program.cs     -> 桌面程序入口。 

5. 项目配置

5.1. 前端配置

  • 前端配置写在JxcLite项目的AppConfig.cs文件中,示例如下:
public static class AppConfig {     public static string AppId => "JxcLite";     public static string AppName => "进销存管理系统";      // 添加应用程序配置,云Web、Wasm和桌面需要调用     public static void AddApplication(this IServiceCollection services, AppType type) {         var assembly = typeof(AppConfig).Assembly;         Config.AddModule(assembly);          services.AddKnown(option => { }); // 添加Known         services.AddModules();            // 添加一级模块         services.ConfigUI();              // 配置界面     }      // 添加Wasm模式的Http客户端,Wasm需要调用     public static void AddApplicationClient(this IServiceCollection services, Action<ClientOption> action) {         var assembly = typeof(AppConfig).Assembly;         services.AddKnownClient(action);  // 添加Known客户端         services.AddClients(assembly);    // 自动注入Auto模式客户端实现     } } 
  • 系统一级模块配置写在JxcLite项目的AppModule.cs文件中,示例如下:
static class AppModule {     // 添加模块菜单     internal static void AddModules(this IServiceCollection services) {         Config.Modules.AddItem("0", AppConstant.Import, "进货管理", "import", 2);         Config.Modules.AddItem("0", AppConstant.Export, "销货管理", "export", 3);         Config.Modules.AddItem("0", AppConstant.Inventory, "库存管理", "block", 4);         Config.Modules.AddItem("0", AppConstant.Finance, "财务管理", "pay-circle", 5);         Config.Modules.AddItem("0", AppConstant.Report, "统计报表", "bar-chart", 6);     } } 

5.2. 后端配置

  • 后端配置写在JxcLite.Core项目的AppCore.cs文件中,示例如下:
public static class AppCore {     // 添加PC云Web端,云Web端需要调用     public static void AddApplicationWeb(this IServiceCollection services, Action<CoreOption> action) {         services.AddApplicationCore();         services.AddKnownWeb(option => SetOption(option, action));     }      // 添加单机桌面端,桌面端需要调用     public static void AddApplicationWin(this IServiceCollection services, Action<CoreOption> action) {         services.AddApplicationCore();         services.AddKnownWin(option => SetOption(option, action));     }      // Web端使用程序静态文件,云Web端需要调用     public static void UseApplication(this WebApplication app) {         app.UseKnown();     }      private static void AddApplicationCore(this IServiceCollection services) {         var assembly = typeof(AppCore).Assembly;         services.AddServices(assembly); // 自动注入服务接口后端实现         services.AddKnownCells();       // 添加Excel操作插件     }      private static void SetOption(CoreOption option, Action<CoreOption> action) {         action?.Invoke(option);         option.Database = db => {             var connString = "Data Source=JxcLite.db;"; // 配置数据库连接             db.AddSQLite<Microsoft.Data.Sqlite.SqliteFactory>(connString);         };     } } 

6. 模块示例

项目模块较多,大部分单表业务模块CRUD可以同通过框架开发中心的代码生成模块进行生成。本文只举商品信息模块为例,其他模块可查看项目源码进行学习。

6.1. 数据模型

名称 代码 类型 长度 必填
商品信息 JxGoods
商品编码 Code Text 50 Y
商品名称 Name Text 200 Y
商品类别 Category Text 50 Y
规格型号 Model Text 500
产地 Producer Text 50
计量单位 Unit Text 50 Y
采购单价 BuyPrice Number 18,2
销售单价 SalePrice Number 18,2
安全库存 SafeQty Number
备注 Note TextArea
附件 Files Text 500

6.2. 信息类

信息类一是作为前后端数据交互的模型,即数据传输对象DTO,二是通过[Column][Form]特性配置列表和表单界面。商品信息类示例如下:

[DisplayName("商品信息")] public class GoodsInfo {     /// 取得或设置商品编码。     [Required]     [MaxLength(50)]     [Column(Width = 120, IsViewLink = true)] // IsViewLink为列表查看连接字段     [Form(Row = 1, Column = 1)] // Form配置表单字段     [DisplayName("商品编码")] // DisplayName配置显示名称     public string Code { get; set; }      /// 取得或设置商品名称。     [Column(Width = 120, IsQuery = true)] // 配置查询条件     public string Name { get; set; }      /// 取得或设置商品类别。     [Form(Row = 1, Column = 3, Type = nameof(FieldType.Select))] // 配置下拉框     [Category(AppConstant.GoodsType)]  // 下拉框数据字典     public string Category { get; set; } } 

6.3. 实体类

实体类是数据库表的映射,框架默认内置Database简易ORM,商品实体类示例如下:

public class JxGoods : EntityBase { // 使用内置ORM需要继承EntityBase     [DisplayName("商品编码")]     [Required]     [MaxLength(50)]     public string Code { get; set; }      [DisplayName("商品名称")]     [Required]     [MaxLength(200)]     public string Name { get; set; } } 

6.4. 页面组件

页面组件用户配置模块菜单、通过[Action]特性定义模块操作按钮,商品列表页面组件示例如下:

[Route("/bds/goods")] // 页面路由 [Menu(Constants.BaseData, "商品信息", "ordered-list", 4)] // 配置模块菜单 public class GoodsList : BaseTablePage<GoodsInfo> {     private IBaseDataService Service;      protected override async Task OnInitPageAsync() {         await base.OnInitPageAsync();         Service = await CreateServiceAsync<IBaseDataService>();         Table.Form = new FormInfo { Width = 800 };         Table.OnQuery = Service.QueryGoodsesAsync;     }      // Action配置按钮,带参数的方法为表格操作列,不带参数的为工具条按钮     [Action] public void New() => Table.NewForm(Service.SaveGoodsAsync, new GoodsInfo());     [Action] public void DeleteM() => Table.DeleteM(Service.DeleteGoodsesAsync);     [Action] public void Edit(GoodsInfo row) => Table.EditForm(Service.SaveGoodsAsync, row);     [Action] public void Delete(GoodsInfo row) => Table.Delete(Service.DeleteGoodsesAsync, row);     [Action] public Task Import() => Table.ShowImportAsync();     [Action] public Task Export() => Table.ExportDataAsync(); } 

6.5. 服务接口

服务接口定义前后端数据交互的操作方法,如增删改查导。商品服务示例如下:

public interface IBaseDataService : IService {     // 分页查询和导出     Task<PagingResult<GoodsInfo>> QueryGoodsesAsync(PagingCriteria criteria);     Task<List<GoodsInfo>> GetGoodsesAsync(); // 查询     Task<Result> DeleteGoodsesAsync(List<GoodsInfo> infos);  // 删除     Task<Result> SaveGoodsAsync(UploadInfo<GoodsInfo> info); // 保存 }  [Client] // 配置Client,自动注入接口的客户端实现 class BaseDataClient(HttpClient http) : ClientBase(http), IBaseDataService {     public Task<PagingResult<GoodsInfo>> QueryGoodsesAsync(PagingCriteria criteria) {         return Http.QueryAsync<GoodsInfo>("/BaseData/QueryGoodses", criteria);     }      public Task<List<GoodsInfo>> GetGoodsesAsync() {         return Http.GetAsync<List<GoodsInfo>>("/BaseData/GetGoodses");     }      public Task<Result> DeleteGoodsesAsync(List<GoodsInfo> infos) {         return Http.PostAsync("/BaseData/DeleteGoodses", infos);     }      public Task<Result> SaveGoodsAsync(UploadInfo<GoodsInfo> info) {         return Http.PostAsync("/BaseData/SaveGoods", info);     } } 

6.6. 服务实现

服务实现提供前后端数据交互接口的具体业务逻辑实现。商品服务实现示例如下:

[WebApi, Service] // 配置WebApi和自动注入接口的服务端实现 class BaseDataService(Context context) : ServiceBase(context), IBaseDataService {     public Task<PagingResult<GoodsInfo>> QueryGoodsesAsync(PagingCriteria criteria) {         // 分页查询排序和导出共用,查询条件自动拼接         return Database.Query<JxGoods>(criteria).ToPageAsync<GoodsInfo>();     }      public Task<List<GoodsInfo>> GetGoodsesAsync() {         return Database.Query<JxGoods>().Where(d => d.CompNo == CurrentUser.CompNo).ToListAsync<GoodsInfo>();     }      public async Task<Result> DeleteGoodsesAsync(List<GoodsInfo> infos) {         if (infos == null || infos.Count == 0)             return Result.Error(Language.SelectOneAtLeast);          var database = Database;         var oldFiles = new List<string>();         var result = await database.TransactionAsync(Language.Delete, async db => {             foreach (var item in infos) {                 await db.DeleteFilesAsync(item.Id, oldFiles);                 await db.DeleteAsync<JxGoods>(item.Id);             }         });         if (result.IsValid) AttachFile.DeleteFiles(oldFiles);         return result;     }      public async Task<Result> SaveGoodsAsync(UploadInfo<GoodsInfo> info) {         var database = Database;         var model = await database.QueryByIdAsync<JxGoods>(info.Model.Id);         model ??= new JxGoods();         model.FillModel(info.Model);          var vr = model.Validate(Context);         if (vr.IsValid) {             if (await database.ExistsAsync<JxGoods>(d => d.Id != model.Id && d.Code == model.Code))                 vr.AddError($"商品[{model.Code}]已存在!");         }         if (!vr.IsValid) return vr;          var fileFiles = info.Files?.GetAttachFiles(nameof(JxGoods.Files), "GoodsFiles");         return await database.TransactionAsync(Language.Save, async db => {             await db.AddFilesAsync(fileFiles, model.Id, key => model.Files = key);             await db.SaveAsync(model);             info.Model.Id = model.Id;         }, info.Model);     } } 

7. DeepSeek总结

以下是对文档的总结,重点提取了框架使用、项目结构和开发模式的核心内容:


项目概述


核心需求

  1. 基础数据:商品/供应商/客户管理
  2. 进销存流程:采购进货/退货、销售出货/退货(支持月结/现金结算)
  3. 报表功能:库存查询、明细账、利润表
  4. 多端支持:单机桌面版(WinForm) + 云Web版(Blazor)

项目结构

项目 作用 关键依赖
JxcLite 前端公共层(配置/模型/页面) Known 3.*
JxcLite.Core 后端业务层(实体/服务/数据访问) Known.Core 3.*
JxcLite.Wasm WebAssembly前端入口 Blazor WebAssembly
JxcLite.Web 云Web服务端 集成Core+Wasm
JxcLite.WinForm 单机桌面版 WinForm + Razor组件

框架特性

  1. 前后端分离
    • 前端:Razor组件 + 特性标注(如[Column]定义列表字段,[Form]配置表单)
    • 后端:自动依赖注入[Service]/[WebApi]) + 简易ORMDatabase类)
  2. 多端适配
    • Web端:通过AddApplicationWeb()配置
    • 桌面端:通过AddApplicationWin()配置
  3. 高效开发
    • 代码生成:支持单表业务CRUD自动生成
    • 客户端代理:[Client]特性自动生成HTTP调用代码

开发示例(商品模块)

  1. 数据模型
   // 前端DTO(带UI特性)    [DisplayName("商品信息")]    public class GoodsInfo {        [Column(Width = 120, IsViewLink = true)]         [Form(Row = 1, Column = 1)]        public string Code { get; set; } //商品编码    }        // 数据库实体    public class JxGoods : EntityBase {        public string Code { get; set; }    } 
  1. 服务层
    • 接口声明 IBaseDataService
    • 客户端实现 BaseDataClient(HTTP调用)
    • 服务端实现 BaseDataService(数据库操作)
  2. 页面组件
   [Route("/bds/goods")]    [Menu("基础数据", "商品信息")]    public class GoodsList : BaseTablePage<GoodsInfo> {        [Action] public void New() => Table.NewForm(...); // 按钮绑定方法    } 

关键配置

配置文件 作用
AppConfig.cs 前端全局配置(模块/路由/服务)
AppModule.cs 定义一级功能模块(菜单)
AppCore.cs 后端服务配置(数据库/依赖注入)

总结

  1. 架构优势
    • 一套代码同时支持 Web桌面端
    • 通过Known框架简化Blazor全栈开发(UI配置化、服务自动化)
  2. 开发模式
    • 前端:基于特性的声明式UI + 组件化路由
    • 后端:仓储模式(SQL集中管理) + 事务封装
  3. 适用场景
    适合需要快速开发跨平台企业应用(如ERP、进销存等)的.NET团队。

完整实现需参考源码,尤其是JxcLite.Core的业务逻辑和JxcLite/Pages的组件设计。

发表评论

评论已关闭。

相关文章