本文主要介绍如何使用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.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </ItemGroup>
- </Project><Project Sdk="Microsoft.NET.Sdk.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </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.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </ItemGroup>
- </Project>
复制代码
- 该项目只有一个Wasm程序入口文件Program.cs
- ├─Program.cs -> Wasm程序入口。
复制代码 4.4. JxcLite.Web项目
- 添加JxcLite.Web类库,引用JxcLite.Core和JxcLite.Wasm项目,工程文件如下:
- <Project Sdk="Microsoft.NET.Sdk.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </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>
- <PackageReference Include="Known" Version="3.*" />
- </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商品编码CodeText50Y商品名称NameText200Y商品类别CategoryText50Y规格型号ModelText500产地ProducerText50计量单位UnitText50Y采购单价BuyPriceNumber18,2销售单价SalePriceNumber18,2安全库存SafeQtyNumber备注NoteTextArea附件FilesText5006.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 QueryGoodsesAsync(PagingCriteria criteria) { // 分页查询排序和导出共用,查询条件自动拼接 return Database.Query(criteria).ToPageAsync(); } public Task GetGoodsesAsync() { return Database.Query().Where(d => d.CompNo == CurrentUser.CompNo).ToListAsync(); } public async Task DeleteGoodsesAsync(List infos) { if (infos == null || infos.Count == 0) return Result.Error(Language.SelectOneAtLeast); var database = Database; var oldFiles = new List(); var result = await database.TransactionAsync(Language.Delete, async db => { foreach (var item in infos) {<Project Sdk="Microsoft.NET.Sdk.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </ItemGroup>
- </Project>await db.DeleteFilesAsync(item.Id, oldFiles);<Project Sdk="Microsoft.NET.Sdk.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </ItemGroup>
- </Project>await db.DeleteAsync(item.Id); } }); if (result.IsValid) AttachFile.DeleteFiles(oldFiles); return result; } public async Task SaveGoodsAsync(UploadInfo info) { var database = Database; var model = await database.QueryByIdAsync(info.Model.Id); model ??= new JxGoods(); model.FillModel(info.Model); var vr = model.Validate(Context); if (vr.IsValid) { if (await database.ExistsAsync(d => d.Id != model.Id && d.Code == model.Code))<Project Sdk="Microsoft.NET.Sdk.Razor">
- <ItemGroup>
- <PackageReference Include="Known" Version="3.*" />
- </ItemGroup>
- </Project>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总结
以下是对文档的总结,重点提取了框架使用、项目结构和开发模式的核心内容:
项目概述
- 目标:使用Known框架开发跨平台进销存管理系统(支持Web版和单机桌面版)
- 源码地址:https://gitee.com/known/JxcLite
核心需求
- 基础数据:商品/供应商/客户管理
- 进销存流程:采购进货/退货、销售出货/退货(支持月结/现金结算)
- 报表功能:库存查询、明细账、利润表
- 多端支持:单机桌面版(WinForm) + 云Web版(Blazor)
项目结构
项目作用关键依赖JxcLite前端公共层(配置/模型/页面)Known 3.*JxcLite.Core后端业务层(实体/服务/数据访问)Known.Core 3.*JxcLite.WasmWebAssembly前端入口Blazor WebAssemblyJxcLite.Web云Web服务端集成Core+WasmJxcLite.WinForm单机桌面版WinForm + Razor组件框架特性
- 前后端分离:
- 前端:Razor组件 + 特性标注(如[Column]定义列表字段,[Form]配置表单)
- 后端:自动依赖注入([Service]/[WebApi]) + 简易ORM(Database类)
- 多端适配:
- Web端:通过AddApplicationWeb()配置
- 桌面端:通过AddApplicationWin()配置
- 高效开发:
- 代码生成:支持单表业务CRUD自动生成
- 客户端代理:[Client]特性自动生成HTTP调用代码
开发示例(商品模块)
- // 前端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; }
- }
复制代码
- 服务层:
- 接口声明 IBaseDataService
- 客户端实现 BaseDataClient(HTTP调用)
- 服务端实现 BaseDataService(数据库操作)
- 页面组件:
- [Route("/bds/goods")]
- [Menu("基础数据", "商品信息")]
- public class GoodsList : BaseTablePage<GoodsInfo> {
- [Action] public void New() => Table.NewForm(...); // 按钮绑定方法
- }
复制代码 关键配置
配置文件作用AppConfig.cs前端全局配置(模块/路由/服务)AppModule.cs定义一级功能模块(菜单)AppCore.cs后端服务配置(数据库/依赖注入)总结
- 架构优势:
- 一套代码同时支持 Web 和 桌面端
- 通过Known框架简化Blazor全栈开发(UI配置化、服务自动化)
- 开发模式:
- 前端:基于特性的声明式UI + 组件化路由
- 后端:仓储模式(SQL集中管理) + 事务封装
- 适用场景:
适合需要快速开发跨平台企业应用(如ERP、进销存等)的.NET团队。
完整实现需参考源码,尤其是JxcLite.Core的业务逻辑和JxcLite/Pages的组件设计。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |