Known框架实战演练——进销存业务单据

本文介绍如何实现进销存管理系统的业务单据模块,业务单据模块包括采购进货单、采购退货单、销售出货单、销售退货单4个菜单页面。由于进销单据字段大同小异,因此设计共用一个页面组件类。

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.csJxBillList.cs两个实体类文件,实体类代码可以直接复制模块管理中由模型设置生成的代码。文章中只简单描述一下实体类的定义,具体代码参见开源,代码定义如下:

csharp 复制代码
namespace JxcLite.Entities;

/// <summary>
/// 业务单据表头信息类。
/// </summary>
public class JxBillHead : EntityBase { }

/// <summary>
/// 业务单据表体信息类。
/// </summary>
public class JxBillList : EntityBase { }

3. 建表脚本

打开JxcLite.Web项目Resources文件夹下的Tables.sql资源文件,复制粘贴由【模块管理-模型设置】中生成的建表脚本。文章中只简单描述一下建表脚本,具体脚本参见开源,内容如下:

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访问方法,包括分页查询、批量删除实体、保存实体。具体方法定义如下:

csharp 复制代码
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,文章中只简单描述一下实现类的定义和继承,具体实现参见开源,定义如下:

csharp 复制代码
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方法中注册服务类,前端组件可以通过依赖注入工厂创建服务的实例。代码如下:

csharp 复制代码
public static class AppWeb
{
    public static void AddJxcLiteCore(this IServiceCollection services)
    {
        services.AddScoped<IBillService, BillService>();
    }
}

6. 数据依赖

JxcLite.Web项目Repositories文件夹下面添加业务单据模块数据依赖类,文件名定义为BillRepository.cs,文章中只简单描述一下依赖类的定义,具体实现参见开源,定义如下:

csharp 复制代码
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单据列表组件,该组件是进销单及退货单的列表组件共用类,具体实现参见开源,部分代码如下:

csharp 复制代码
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,用于弹窗选择客户和供应商信息,具体实现参见开源,部分代码如下:

csharp 复制代码
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,用于弹窗选择商品信息,具体实现参见开源,部分代码如下:

csharp 复制代码
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.csTypeTables.cs文件,添加业务单据表头类型表单组件和业务单据表体类型表格组件,代码如下:

csharp 复制代码
namespace JxcLite.Client.Shared;

public class BillHeadTypeForm : AntForm<JxBillHead> { }

public class BillListTypeTable : AntTable<JxBillList> { }

再在JxcLite.Client项目Pages\BillData文件夹下面添加BillForm.razorBillForm.razor.cs文件,由于单据表单组件有点复杂,代码较长,所以采用razor语法来实现,该组件是进销单及退货单的列表组件共用类,具体实现参见开源,部分代码如下:

html 复制代码
@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" AllowClear
                           Type="@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>
csharp 复制代码
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,该组件是打印业务单据内容组件,具体实现参见开源,部分代码如下:

csharp 复制代码
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) {}
}
相关推荐
W清风大侠M2 天前
基于 Blazor 实现的电梯运行监测系统
blazor
known3 天前
基于 Blazor 实现的电梯运行监测系统
blazor·known
functionMC4 天前
在Vue/Nuxt、React/Next/TanstackStart、RazorPages折腾一圈后,还是回到了Blazor,但这回有SSR+HTMX+Alpine的加持
blazor·alpine·htmx
jay神21 天前
基于SpringBoot的宠物生命周期信息管理系统
java·数据库·spring boot·后端·web开发·宠物·管理系统
Cilsoft 秦汉信息科技23 天前
通用销售订单管理软件
vue·管理系统·erp·客户管理·销售订单
Cilsoft 秦汉信息科技23 天前
VUE服务行业ERP系统
vue·管理系统·erp·售后服务·维修管理
Cilsoft 秦汉信息科技23 天前
VUE制造业ERP系统
vue·管理系统·erp·制造业·生产管理
Cilsoft 秦汉信息科技23 天前
VUE 跨境外贸管理系统
管理系统·跨境电商·客户管理·企业数字化·外贸erp
jay神1 个月前
基于团队模式的C程序设计课程辅助教学管理系统
java·spring boot·vue·web开发·管理系统
千鼎数字孪生-可视化1 个月前
三化落地:信息化、数字化、数据化都是啥,是什么关系。
数字化·管理系统