Known框架實戰演練——進銷存業務單據

known發表於2024-07-24

本文介紹如何實現進銷存管理系統的業務單據模組,業務單據模組包括採購進貨單、採購退貨單、銷售出貨單、銷售退貨單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.csJxBillList.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.csTypeTables.cs檔案,新增業務單據表頭型別表單元件和業務單據表體型別表格元件,程式碼如下:

namespace JxcLite.Client.Shared;

public class BillHeadTypeForm : AntForm<JxBillHead> { }

public class BillListTypeTable : AntTable<JxBillList> { }

再在JxcLite.Client專案Pages\BillData資料夾下面新增BillForm.razorBillForm.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" 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>
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) {}
}

相關文章