Known框架实战演练——进销存业务单据
本文介绍如何实现进销存管理系统的业务单据模块,业务单据模块包括采购进货单、采购退货单、销售出货单、销售退货单4个菜单页面。由于进销单据字段大同小异,因此设计共用一个页面组件类。
- 项目代码:JxcLite
- 开源地址: https://gitee.com/known/JxcLite
1. 配置模块
运行项目,在【系统管理-模块管理】中配置如下模块菜单,配置教程参考之前的教程。
| 一级模块 | 二级模块 | 代码 | 图标 | Url | 描述 |
|---|---|---|---|---|---|
| 进货管理 | Import | import | |||
| 采购进货单 | ImportList | unordered-list | /bms/ImportList | 查询和维护采购进货单信息。 | |
| 采购退货单 | ImportReturn | unordered-list | /bms/ImportReturn | 查询和维护采购退货单信息。 | |
| 销货管理 | Export | export | |||
| 销售出货单 | ExportList | unordered-list | /bms/ExportList | 查询和维护销售出货单信息。 | |
| 销售退货单 | ExportReturn | unordered-list | /bms/ExportReturn | 查询和维护销售退货单信息。 |
2. 实体类
在JxcLite项目Entities文件夹下面添加JxBillHead.cs和JxBillList.cs两个实体类文件,实体类代码可以直接复制模块管理中由模型设置生成的代码。文章中只简单描述一下实体类的定义,具体代码参见开源,代码定义如下:
namespace JxcLite.Entities;/// <summary>
/// 业务单据表头信息类。
/// </summary>
public class JxBillHead : EntityBase { }/// <summary>
/// 业务单据表体信息类。
/// </summary>
public class JxBillList : EntityBase { }
3. 建表脚本
打开JxcLite.Web项目Resources文件夹下的Tables.sql资源文件,复制粘贴由【模块管理-模型设置】中生成的建表脚本。文章中只简单描述一下建表脚本,具体脚本参见开源,内容如下:
CREATE TABLE [JxBillHead] ([Id] varchar(50) NOT NULL PRIMARY KEY,...[Files] nvarchar(500) NULL
);CREATE TABLE [JxBillList] ([Id] varchar(50) NOT NULL PRIMARY KEY,...[Note] ntext NULL
);
4. 服务接口
在JxcLite项目Services文件夹下面添加业务单据模块服务接口,文件名定义为IBillService.cs,该接口定义前后端交互的Api访问方法,包括分页查询、批量删除实体、保存实体。具体方法定义如下:
namespace JxcLite.Services;public interface IBillService : IService
{//分页查询业务单据信息Task<PagingResult<JxBillHead>> QueryBillsAsync(PagingCriteria criteria);//根据单据类型获取默认单据信息Task<JxBillHead> GetDefaultBillAsync(string type);//根据表头ID获取单据表体信息列表Task<List<JxBillList>> GetBillListsAsync(string headId);//批量删除业务单据信息Task<Result> DeleteBillsAsync(List<JxBillHead> models);//保存业务单据信息Task<Result> SaveBillAsync(UploadInfo<JxBillHead> info);
}
5. 服务实现
在JxcLite.Web项目Services文件夹下面添加业务单据模块服务接口的实现类,文件名定义为BillService.cs,文章中只简单描述一下实现类的定义和继承,具体实现参见开源,定义如下:
namespace JxcLite.Web.Services;class BillService(Context context) : ServiceBase(context), IBaseDataService
{public Task<PagingResult<JxBillHead>> QueryBillsAsync(PagingCriteria criteria) { }public Task<JxBillHead> GetDefaultBillAsync(string type) { }public Task<List<JxBillList>> GetBillListsAsync(string headId) { }public Task<Result> DeleteBillsAsync(List<JxBillHead> models) { }public Task<Result> SaveBillAsync(UploadInfo<JxBillHead> info) { }
}
双击打开JxcLite.Web项目中的AppWeb.cs文件,在AddJxcLiteCore方法中注册服务类,前端组件可以通过依赖注入工厂创建服务的实例。代码如下:
public static class AppWeb
{public static void AddJxcLiteCore(this IServiceCollection services){services.AddScoped<IBillService, BillService>();}
}
6. 数据依赖
在JxcLite.Web项目Repositories文件夹下面添加业务单据模块数据依赖类,文件名定义为BillRepository.cs,文章中只简单描述一下依赖类的定义,具体实现参见开源,定义如下:
namespace JxcLite.Web.Repositories;class BillRepository
{internal static Task<PagingResult<JxBillHead>> QueryBillsAsync(Database db, PagingCriteria criteria) { }internal static Task<List<JxBillList>> GetBillListsAsync(Database db, string headId) { }//根据前缀获取最大业务单号internal static Task<string> GetMaxBillNoAsync(Database db, string prefix) { }
}
7. 列表页面
在JxcLite.Client项目Pages\BillData文件夹下面添加BillList.cs单据列表组件,该组件是进销单及退货单的列表组件共用类,具体实现参见开源,部分代码如下:
namespace JxcLite.Client.Pages.BillData;public class BillList : BaseTablePage<JxBillHead>
{private IBillService Service;//取得业务单据类型(进货、进退货、销货、销退货),由具体单据页面重写该类型protected virtual string Type { get; }protected override async Task OnPageInitAsync(){await base.OnPageInitAsync();Service = await CreateServiceAsync<IBillService>();//创建服务Table.FormType = typeof(BillForm);//自定义表单类型Table.OnQuery = QueryBillsAsync; //查询方法//下面是设置列表栏位显示的模板Table.Column(c => c.Status).Template((b, r) => b.Tag(r.Status));Table.Column(c => c.BillDate).Type(FieldType.Date);}//新增public async void New(){var row = await Service.GetDefaultBillAsync(Type);Table.NewForm(Service.SaveBillAsync, row);}//编辑public async void Edit(JxBillHead row){row.Lists = await Service.GetBillListsAsync(row.Id);Table.EditForm(Service.SaveBillAsync, row);}//批量删除和删除public void DeleteM() => Table.DeleteM(Service.DeleteBillsAsync);public void Delete(JxBillHead row) => Table.Delete(Service.DeleteBillsAsync, row);//复制和退货public void Copy() => Table.SelectRow(async row => {});public void Return() => Table.SelectRow(async row => {});//打印public void Print() => Table.SelectRow(async row =>{row.Lists = await Service.GetBillListsAsync(row.Id);//BillPrint为业务单据打印组件await JS.PrintAsync<BillPrint>(f => f.Set(c => c.Model, row));});//导出public async void Export() => await ExportDataAsync();private Task<PagingResult<JxBillHead>> QueryBillsAsync(PagingCriteria criteria){//设置单据类型查询条件criteria.SetQuery(nameof(JxBillHead.Type), QueryType.Equal, Type);return Service.QueryBillsAsync(criteria);}
}
8. 供应商和客户选择框
在JxcLite.Client项目Shared文件夹下面添加PartnerPicker.cs,该组件继承BasePicker,用于弹窗选择客户和供应商信息,具体实现参见开源,部分代码如下:
namespace JxcLite.Client.Shared;public class PartnerPicker : BasePicker<JxPartner>
{private IBaseDataService Service;private TableModel<JxPartner> Table;//取得弹框选择的数据列表public override List<JxPartner> SelectedItems => Table.SelectedRows?.ToList();//取得或设置商业伙伴类型(客户、供应商)[Parameter] public string Type { get; set; }protected override async Task OnInitAsync() {}protected override void BuildContent(RenderTreeBuilder builder) => builder.Table(Table);
}
9. 商品信息选择框
在JxcLite.Client项目Shared文件夹下面添加GoodsPicker.cs,该组件继承BasePicker,用于弹窗选择商品信息,具体实现参见开源,部分代码如下:
namespace JxcLite.Client.Shared;public class GoodsPicker : BasePicker<JxGoods>
{private IBaseDataService Service;private TableModel<JxGoods> Table;//取得弹框选择的数据列表public override List<JxGoods> SelectedItems => Table.SelectedRows?.ToList();protected override async Task OnInitAsync() {}protected override void BuildContent(RenderTreeBuilder builder) => builder.Table(Table);
}
10. 表单组件
首先在JxcLite.Client项目Shared文件夹下面添加TypeForms.cs和TypeTables.cs文件,添加业务单据表头类型表单组件和业务单据表体类型表格组件,代码如下:
namespace JxcLite.Client.Shared;public class BillHeadTypeForm : AntForm<JxBillHead> { }public class BillListTypeTable : AntTable<JxBillList> { }
再在JxcLite.Client项目Pages\BillData文件夹下面添加BillForm.razor和BillForm.razor.cs文件,由于单据表单组件有点复杂,代码较长,所以采用razor语法来实现,该组件是进销单及退货单的列表组件共用类,具体实现参见开源,部分代码如下:
@inherits BaseForm<JxBillHead><BillHeadTypeForm Form="Model"><AntRow><DataItem Span="6" Label="业务单号" Required><AntInput Disabled @bind-Value="@context.BillNo" /></DataItem><DataItem Span="6" Label="单证状态"><KTag Text="@context.Status" /></DataItem><DataItem Span="6" Label="单证日期" Required><AntDatePicker @bind-Value="@context.BillDate" /></DataItem><DataItem Span="6" Label="商业伙伴" Required><PartnerPicker Value="@context.Partner" AllowClearType="@GetPartnerPickerType(context)" /></DataItem></AntRow>
</BillHeadTypeForm>
<KToolbar><KTitle Text="商品明细" /><div>@if (!Model.IsView){<Button Type="@ButtonType.Primary" Icon="plus" OnClick="OnAdd">添加</Button>}</div>
</KToolbar>
<BillListTypeTable DataSource="Model.Data.Lists" HidePagination ScrollX="1300px" ScrollY="200px"><IntegerColumn Title="序号" Field="@context.SeqNo" Width="60" Fixed="left" /><StringColumn Title="商品编码" Width="120" Fixed="left"><AntInput @bind-Value="@context.Code" Style="width:100px" /></StringColumn><StringColumn Title="金额" Width="100"><AntDecimal @bind-Value="@context.Amount" OnChange="e=>OnGoodsChange(3, context)" /></StringColumn>@if (!Model.IsView){<ActionColumn Title="操作" Align="ColumnAlign.Center" Width="100" Fixed="right"><Tag Color="red-inverse" OnClick="e=>OnDelete(context)">删除</Tag></ActionColumn>}<SummaryRow><SummaryCell Fixed="left">合计</SummaryCell><SummaryCell>@Model.Data.Lists.Sum(l => l.Amount)</SummaryCell><SummaryCell />@if (!Model.IsView){<SummaryCell />}</SummaryRow>
</BillListTypeTable>
namespace JxcLite.Client.Pages.BillData;partial class BillForm
{private KUpload upload;private static string GetPartnerPickerType(JxBillHead model) {}private async void OnFilesChanged(List<FileDataInfo> files) {}private void OnAdd() {}private void OnDelete(JxBillList row) => Model.Data.Lists.Remove(row);private void OnGoodsChange(int field, JxBillList row) {}
}
11. 打印组件
在JxcLite.Client项目Pages\BillData文件夹下面添加BillPrint.cs,该组件是打印业务单据内容组件,具体实现参见开源,部分代码如下:
namespace JxcLite.Client.Pages.BillData;class BillPrint : ComponentBase
{//业务单据实体对象[Parameter] public JxBillHead Model { get; set; }protected override void BuildRenderTree(RenderTreeBuilder builder){BuildStyle(builder);//构建样式表,打印时调用浏览器的预览,选打印机打印BuildForm(builder); //构建打印表单}private static void BuildStyle(RenderTreeBuilder builder){builder.Markup(@"<style>
.bill-print {position:relative;}
</style>");}private void BuildForm(RenderTreeBuilder builder) {}
}
相关文章:
Known框架实战演练——进销存业务单据
本文介绍如何实现进销存管理系统的业务单据模块,业务单据模块包括采购进货单、采购退货单、销售出货单、销售退货单4个菜单页面。由于进销单据字段大同小异,因此设计共用一个页面组件类。 项目代码:JxcLite开源地址: https://git…...
解决npm依赖树冲突的方法以及npm ERR! code ERESOLVE错误的解决方案
一、问题描述 在使用ng new myapp --skip-install 构建Angular 项目后,尝试用npm install 安装依赖的时候报了以下错误。 (base) PS C:\Users\Administrator\Desktop\agtest\myapp> npm i npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependenc…...
Spring Boot + Spring Batch + Quartz 整合定时批量任务
博客主页: 南来_北往 系列专栏:Spring Boot实战 前言 最近一周,被借调到其他部门,赶一个紧急需求,需求内容如下: PC网页触发一条设备升级记录(下图),后台要定时批量设备更…...
C++STL简介(二)
目录 1.模拟实现string 1.string基本属性和大体框架 2.基本函数 2.1size() 2.2 [] 2.3 begin() 和end() 2.4capacity() 2.5 reserve 2.6push_back 2.7 append 2.8 2.9insert 2.10find 2.11substr 2.12 2.12 < …...
嵌入式高频面试题100道及参考答案(3万字长文)
目录 解释嵌入式系统的定义和主要特点 描述微处理器与微控制器的主要区别 什么是ARM体系结构?它在嵌入式系统中有哪些优势? 解释GPIO(通用输入输出)的工作原理 什么是ADC和DAC?它们在嵌入式系统中的作用是什么? 解释中断的概念及其在实时系统中的重要性 描述SPI(串…...
python爬虫-事件触发机制
今天想爬取一些政策,从政策服务 (smejs.cn) 这个网址爬取,html源码找不到链接地址,通过浏览器的开发者工具,点击以下红框 分析预览可知想要的链接地址的id有了,进行地址拼接就行 点击标头可以看到请求后端服务器的api地…...
LeetCode-day27-3106. 满足距离约束且字典序最小的字符串
LeetCode-day27-3106. 满足距离约束且字典序最小的字符串 题目描述示例示例1:示例2:示例3: 思路代码 题目描述 给你一个字符串 s 和一个整数 k 。 定义函数 distance(s1, s2) ,用于衡量两个长度为 n 的字符串 s1 和 s2 之间的距…...
C++中的static_cast函数
static_cast 是 C 中的一个类型转换操作符,用于在编译时进行类型转换。它主要用于基本数据类型之间的转换,以及类的指针或引用之间的向上转换(将派生类指针或引用转换为基类指针或引用)和某些情况下的向下转换(将基类指…...
从零开始学习网络安全渗透测试之基础入门篇——(二)Web架构前后端分离站Docker容器站OSS存储负载均衡CDN加速反向代理WAF防护
Web架构 Web架构是指构建和管理Web应用程序的方法和模式。随着技术的发展,Web架构也在不断演进。当前,最常用的Web架构包括以下几种: 单页面应用(SPA): 特点:所有用户界面逻辑和数据处理都包含…...
2679. 矩阵中的和
两种方法: 第一种:先对二维列表的每一列进行排序,然后对每一列的数据进行逐个比较,找出最大值。 class Solution:def matrixSum(self, nums: list[list[int]]) -> int:result0mlen(nums)nlen(nums[0])for i in range(m):nums…...
Unity Playables:下一代动画与音频序列
Unity的Playables API是一种灵活的系统,用于创建和控制动画、音频以及其他形式的连续媒体序列。它为开发者提供了一种全新的方法来处理游戏中的时间序列,包括动画、音频、特效等。本文将探讨Playables的基本概念、如何使用Playables API实现动画…...
matlab仿真 模拟调制(下)
(内容源自详解MATLAB/SIMULINK 通信系统建模与仿真 刘学勇编著第五章内容,有兴趣的读者请阅读原书) clear all ts0.001; t0:ts:10-ts; fs1/ts; dffs/length(t); msgrandi([-3 3],100,1); msg1msg*ones(1,fs/10); msg2reshape(ms…...
RabbitMQ是什么?
RabbitMQ是一个开源的消息代理软件(Message Broker),它实现了高级消息队列协议(AMQP,Advanced Message Queuing Protocol),并支持多种消息传递协议。它最初由英国的Rabbit Technologies开发&…...
追问试面试系列:分布式id
hi 大家好,欢迎来到追问试面试系列:分布式id 面试中可能面试官不会直接问你分布式id问题,基本上都是因为你在某些面试题回答中提到了,所以就开始追问分布式id相关问题。 先看面试题 ● 面试官:什么是分布式id? ● 面试官:举个例子说说 ● 面试官:什么叫分库分表? ●…...
护网紧急情况应对指南:Linux 应急响应手册
继上一篇:护网紧急情况应对指南:Windows版v1.2全新升级版 之后 收到小伙伴后台要Linux应急手册,今天给大家安排上。 《Linux应急手册》是一本为Linux系统管理员和运维工程师量身打造的实用指南,旨在帮助他们快速应对各种突发状况…...
WEB攻防-通用漏洞-SQL 读写注入-MYSQLMSSQLPostgreSQL
什么是高权限注入 高权限注入指的是攻击者通过SQL注入漏洞,利用具有高级权限的数据库账户(如MYSQL的root用户、MSSQL的sa用户、PostgreSQL的dba用户)执行恶意SQL语句。这些高级权限账户能够访问和修改数据库中的所有数据,甚至执行…...
【前端学习笔记】CSS基础一
一、什么是CSS 1.CSS 介绍 CSS(Cascading Style Sheets,层叠样式表)是一种用来控制网页布局和设计外观的样式语言。它使得开发者可以分离网页的内容(HTML)和表现形式(样式),提高了…...
Github遇到的问题解决方法总结(持续更新...)
1.github每次push都需要输入用户名和token的解决方法 push前,执行下面命令 : git config --global credential.helper store 之后再输入一次用户名和token之后,就不用再输入了。 2.git push时遇到“fatal: unable to access https://githu…...
数字信封+数字签名工具类测试样例(Java实现)
加解密过程 加密: 生成加密方SM2密钥对用于签名使用生成的SM2私钥生成数字签名生成SM4对称密钥对明文进行对称加密使用与解密方提前约定好的SM2公钥对第三步中的SM4对称密钥进行非对称加密把【加密方SM2公钥】、【数字签名】、【SM4对称加密后的密文】和【SM2非对…...
The Schematic workflow failed. See above.
在使用 ng new 新建Angular项目的时候会报一个错误:The Schematic workflow failed. See above. 解决办法: 只需要在后面加上 --skip-install 参数,就不会报错了。 ng new myapp --skip-install...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...
MLP实战二:MLP 实现图像数字多分类
任务 实战(二):MLP 实现图像多分类 基于 mnist 数据集,建立 mlp 模型,实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入,可视化图形数字; 2、完成数据预处理:图像数据维度转换与…...
标注工具核心架构分析——主窗口的图像显示
🏗️ 标注工具核心架构分析 📋 系统概述 主要有两个核心类,采用经典的 Scene-View 架构模式: 🎯 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 🔧 关键函数&…...
Shell 解释器 bash 和 dash 区别
bash 和 dash 都是 Unix/Linux 系统中的 Shell 解释器,但它们在功能、语法和性能上有显著区别。以下是它们的详细对比: 1. 基本区别 特性bash (Bourne-Again SHell)dash (Debian Almquist SHell)来源G…...
