基于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="..\JxcLite\JxcLite.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="..\JxcLite\JxcLite.csproj" />
</ItemGroup>
</Project>
- 该项目只有一个Wasm程序入口文件
Program.cs
├─Program.cs -> Wasm程序入口。
4.4. JxcLite.Web项目
- 添加
JxcLite.Web类库,引用JxcLite.Core和JxcLite.Wasm项目,工程文件如下:
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<ProjectReference Include="..\JxcLite.Core\JxcLite.Core.csproj" />
<ProjectReference Include="..\JxcLite.Wasm\JxcLite.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.Core\JxcLite.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总结
以下是对文档的总结,重点提取了框架使用、项目结构和开发模式的核心内容:
项目概述
- 目标:使用
Known框架开发跨平台进销存管理系统(支持Web版和单机桌面版) - 源码地址:https://gitee.com/known/JxcLite
核心需求
- 基础数据:商品/供应商/客户管理
- 进销存流程:采购进货/退货、销售出货/退货(支持月结/现金结算)
- 报表功能:库存查询、明细账、利润表
- 多端支持:单机桌面版(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组件 |
框架特性
- 前后端分离:
- 前端:
Razor组件+特性标注(如[Column]定义列表字段,[Form]配置表单) - 后端:
自动依赖注入([Service]/[WebApi]) +简易ORM(Database类)
- 前端:
- 多端适配:
- Web端:通过
AddApplicationWeb()配置 - 桌面端:通过
AddApplicationWin()配置
- Web端:通过
- 高效开发:
- 代码生成:支持单表业务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的组件设计。
基于Blazor实现的简易进销存管理系统的更多相关文章
- 文献综述十五:基于b/s中小型超市进销存管理系统的研究与设计
一.基本信息 标题:基于b/s中小型超市进销存管理系统的研究与设计 时间:2015 出版源:湘西财经大学 文件分类:对超市管理系统的研究 二.研究背景 在竞争日益激烈的行业中,尽可能降低运营成本,逐步 ...
- Access-简易进销存管理系统
p{ font-size: 15px; } .alexrootdiv>div{ background: #eeeeee; border: 1px solid #aaa; width: 99%; ...
- Net通用进销存管理系统 + 开发文档+ 使用说明
通用进销存管理系统 + 开发文档+ 使用说明Net源码下载 包括下面的模块基础资料模块采购管理模块库存管理模块商务管理模块营业管理模块维修管理模块会员管理模块财务管理模块 Net通用进销存管理系统 + ...
- Java实例学习——企业进销存管理系统(4)
Java实例学习——企业进销存管理系统(4) (本实例为书上实例,我所记录的是我的学习过程) 开始时间:2月12日 完成时间:暂未完成 2月18日——系统主窗体设计 只看了学习视频 2月19日—— 回 ...
- Java实例学习——企业进销存管理系统(3)
Java实例学习--企业进销存管理系统(3) (本实例为书上实例,我所记录的是我的学习过程) 开始时间:2月12日 完成时间:暂未完成 2月16日-公共类(Item公共类,数据模型公共类,Dao公共类 ...
- Java实例学习——企业进销存管理系统(2)
Java实例学习--企业进销存管理系统(2) (本实例为书上实例,我所记录的是我的学习过程) 开始时间:2月12日 完成时间:暂未完成 2月15日-系统登录 对于昨天新建的12个Java包不能完全显示 ...
- Java实例学习——企业进销存管理系统(1)
Java实例学习——企业进销存管理系统(1) (本实例为书上实例,我所记录的是我的学习过程) 开始时间:2月12日 完成时间:暂未完成 2月12日—选择企业进销存管理系统 选择企业进销存管理系统这一实 ...
- 进销存管理系统, 刚学C++
各位大神们.有什么补充的能够评论一下吗? #include<iostream> #include<string> using namespace std; int G=0;// ...
- java进销存管理系统的设计与实现-springboot源码
开发环境: Windows操作系统 开发工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 数据库 项目简介: 系统前段页面采用jsp + JavaScrip ...
- 浩瀚PDA开单器-结束手工开单模式【百货、商超】PDA安卓智能手持POS 进销存管理系统移动收银管理软件
移动销售终端:先进的跨平台技术,支持智能PDA等移动终端提供移动销售开单.移动POS.移动查询货品.移动盘点等功能. 移动开单器的操作说明 第一步:选客户 Ø 用户在空白开单主页左划屏幕 ...
随机推荐
- 第六章: SEO与交互指标 二
上一篇文章地址 5. 提升用户参与度 提高用户参与度不仅有利于SEO,还能增加转化率和用户留存. 5.1 内容结构优化 使用吸引人的标题和小标题: 使用数字列表.问题形式或"如何" ...
- tkela二次开发之lay文件解析
在tekla的一些配置文件中绝大都是本文格式存储的,如.dim:.ad:.vi;.tpl等文件:但是其中.lay文件却是一个例外:这个文件用txt开打时里面是会有乱码的. 我们知道这个文件是在软件的界 ...
- 如何实现RAG与MCP集成
1.概述 在人工智能的创新浪潮中,检索增强生成(RAG)技术以其高效调用外部知识.提升生成内容准确性的能力备受瞩目,而模型上下文协议(MCP)则为不同模型间的交互与协同提供了标准框架.当 RAG 的知 ...
- 通义灵码2.5+qwen3——节假日抢票不用愁,基于12306-MCP实现个人火车票智能查询小助手!
在日常生活中,12306 是中国铁路售票系统的官方平台.为了提升购票效率.自动化查询余票信息以及获取车站代码等功能,我们希望通过使用智能体编程方式,结合 MCP(Model-as-a-Servic ...
- 高性能且低成本的 Goroutine 池库-Ants
本文分享自天翼云开发者社区<高性能且低成本的 Goroutine 池库-Ants>,作者:李****佳 在 Go 语言中,虽然原生支持并发的 Goroutine 提供了强大的并发能力,但在 ...
- 2. LangChain4j-AIServices,原来调用AI这么简单?
1. 简介 上一章节我们讲了如何使用LangChain4J的底层组件来进行AI的交互,如 ChatLanguageModel.ChatMessage.ChatMemory 等. 在这个层面上工作非常灵 ...
- 【Zookeeper】ZooKeeper集群搭建与选举原理终极指南(Docker版 + 三角色详解)
ZooKeeper集群搭建与选举原理终极指南(Docker版 + 三角色详解) 一.环境准备(Docker版) 1. 服务器准备(3台节点) # 所有节点执行 sudo apt-get update ...
- .NET 10 引入 后量子密码学 (PQC)
.NET 10 预览版 5 悄悄引入了对基于新定稿行业标准的后量子加密(PQC)的支持,这标志着帮助开发人员保护应用程序免受未来量子驱动攻击的早期举措.后量子密码学 (PQC) 支持是一项坚定地展望未 ...
- Java源码分析系列笔记-18.Semaphore
目录 1. 是什么 2. 原理分析 2.1. uml 3. 公平信号量 3.1. 是什么 3.2. 使用 3.3. 原理分析 3.3.1. 构造方法 3.3.1.1. 公平Sync 3.3.2. ac ...
- Blazor学习之旅 (13) Razor类库的使用
在上一篇我们学习了Blazor和JavaScript的互操作性,这一篇我们了解下如何创建和使用Razor类库. 什么是Razor类库? 我们都知道,在.NET应用程序中,我们可以通过NuGet来安装各 ...