XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

STHApplication

【MAUI】寄当家——安卓端交易管理系统

公开
关注 0 Fork 0 Star 0
UTF-8
using JiDangJia.Core;

namespace JiDangJia.Views;

public sealed class ManualFinancePage : ContentPage
{
    private readonly BusinessService service;
    private readonly FieldSet fields;
    private readonly VerticalStackLayout categories=Ui.Stack();
    private readonly Button income,expense;
    private readonly Dictionary<string,string> selections=new();
    private string direction="EXPENSE";
    public ManualFinancePage(BusinessService service)
    {
        this.service=service;Title="手工记账";
        fields=new(new(){["occurDate"]=Display.Day(DateTime.Today),["operatorId"]=service.Owner.Id},
            [new("amount","金额(元)",FieldKind.Number,true),new("occurDate","发生日期",FieldKind.Date,true),new("remark","备注",FieldKind.Notes)]);
        income=Ui.Button("收入",()=>Select("INCOME"),false);expense=Ui.Button("支出",()=>Select("EXPENSE"));
        var directions=new Grid{ColumnDefinitions=[new(GridLength.Star),new(GridLength.Star)],ColumnSpacing=8};directions.Add(income);directions.Add(expense,1);
        var body=Ui.Stack(directions,Ui.Card(categories),Ui.Card(fields.View),
            Ui.Text("资方利息可在资金成本页面结算。已自动生成的流水,请勿再次手工记账。",11,Ui.Muted),Ui.Button("确认记账",Save));
        body.Padding=new Thickness(18,16,18,28);Content=new ScrollView{Content=body};
    }
    protected override void OnAppearing(){base.OnAppearing();RenderCategories();}
    private Task Select(string value){direction=value;RenderCategories();return Task.CompletedTask;}
    private void RenderCategories()
    {
        income.Background=direction=="INCOME"?Ui.GoldBrush:new SolidColorBrush(Ui.Cream);income.TextColor=direction=="INCOME"?Ui.Ink:Ui.Bronze;
        expense.Background=direction=="EXPENSE"?Ui.GoldBrush:new SolidColorBrush(Ui.Cream);expense.TextColor=direction=="EXPENSE"?Ui.Ink:Ui.Bronze;
        var choices=FinanceCategories.Read(service.Db,direction);var selected=selections.GetValueOrDefault(direction,"");
        if(!choices.Any(r=>r.Text("code")==selected)){selected="";selections.Remove(direction);}
        categories.Clear();categories.Add(Ui.Section("财务分类 *"));
        var manage=Ui.Button("管理分类 · 修改 / 停用",()=>Navigation.PushAsync(new FinanceCategoryPage(service,direction)),false);manage.HeightRequest=42;categories.Add(manage);
        var grid=new Grid{ColumnDefinitions=[new(GridLength.Star),new(GridLength.Star),new(GridLength.Star)],ColumnSpacing=6,RowSpacing=6};
        for(int i=0;i<choices.Count;i++)
        {
            if(i%3==0)grid.RowDefinitions.Add(new(GridLength.Auto));
            var row=choices[i];var code=row.Text("code");
            var button=Ui.Button(row.Text("label"),()=>{selections[direction]=code;RenderCategories();return Task.CompletedTask;},selected==code);
            button.HeightRequest=40;button.FontSize=12;button.Padding=new Thickness(5,0);button.CornerRadius=10;button.LineBreakMode=LineBreakMode.TailTruncation;
            SemanticProperties.SetDescription(button,row.Text("label")+(selected==code?",已选择":""));grid.Add(button,i%3,i/3);
        }
        int added=choices.Count;if(added%3==0)grid.RowDefinitions.Add(new(GridLength.Auto));
        var add=Ui.Button("+ 新增分类",()=>Navigation.PushAsync(new FinanceCategoryEditor(service,direction,created:code=>selections[direction]=code)),false);add.HeightRequest=40;add.FontSize=12;add.Padding=new Thickness(3,0);add.CornerRadius=10;add.BorderColor=Ui.Gold;add.BorderWidth=1;grid.Add(add,added%3,added/3);
        categories.Add(grid);
        categories.Add(Ui.Text(selected.Length>0?"已选:"+choices.First(r=>r.Text("code")==selected).Text("label"):choices.Count>0?"请选择一个财务分类":"暂无启用分类,请在管理分类中新增或启用。",11,Ui.Muted));
    }
    private async Task Save()
    {
        var category=selections.GetValueOrDefault(direction,"");if(category.Length==0)throw new ArgumentException("请选择财务分类");
        var row=fields.Read();row["type"]=direction;row["category"]=category;
        await Task.Run(()=>service.Book(row));await DisplayAlertAsync("已保存","收支已计入财务流水。","完成");await Navigation.PopAsync();
    }
}

public sealed class FinanceCategoryPage : ContentPage
{
    private readonly BusinessService service;
    private readonly VerticalStackLayout body=Ui.Stack();
    private string direction;
    public FinanceCategoryPage(BusinessService service,string direction="INCOME")
    {
        this.service=service;this.direction=direction;Title="财务分类";body.Padding=18;Content=new ScrollView{Content=body};
    }
    protected override void OnAppearing(){base.OnAppearing();Render();}
    private void Render()
    {
        body.Clear();var rows=FinanceCategories.Read(service.Db,direction,false);
        var tabs=new Grid{ColumnDefinitions=[new(GridLength.Star),new(GridLength.Star)],ColumnSpacing=8};
        tabs.Add(Ui.Button("收入分类",()=>{direction="INCOME";Render();return Task.CompletedTask;},direction=="INCOME"));
        tabs.Add(Ui.Button("支出分类",()=>{direction="EXPENSE";Render();return Task.CompletedTask;},direction=="EXPENSE"),1);body.Add(tabs);
        body.Add(Ui.Spread(Ui.Text(rows.Count+" 个分类",12,Ui.Muted),Ui.Button("+ 新增分类",()=>Navigation.PushAsync(new FinanceCategoryEditor(service,direction)),false)));
        body.Add(Ui.Text("停用后不再供手工记账选择,已有流水继续保留。",12,Ui.Muted));
        foreach(var row in rows)
        {
            var enabled=new Switch{IsToggled=row.Int("enabled")==1,OnColor=Ui.Bronze};bool updating=false;
            enabled.Toggled+=async(_,e)=>
            {
                if(updating)return;enabled.IsEnabled=false;
                try{service.EnableFinanceCategory(row.Id,e.Value);row["enabled"]=e.Value?1:0;}
                catch(Exception ex){updating=true;enabled.IsToggled=row.Int("enabled")==1;updating=false;await DisplayAlertAsync("操作未完成",ex.Message,"知道了");}
                finally{enabled.IsEnabled=true;}
            };
            var name=Ui.Text(row.Text("label"),15,bold:true);name.MaxLines=2;
            var card=Ui.Stack(Ui.Spread(name,enabled),Ui.Spread(Ui.Text("排序 "+row.Int("sortOrder"),11,Ui.Muted),Ui.Button("编辑",()=>Navigation.PushAsync(new FinanceCategoryEditor(service,direction,row)),false)));card.Spacing=6;
            body.Add(Ui.Card(card,padding:new Thickness(14,10)));
        }
    }
}

public sealed class FinanceCategoryEditor : ContentPage
{
    public FinanceCategoryEditor(BusinessService service,string direction,DbRow? initial=null,Action<string>? created=null)
    {
        Title=initial is null?"新增财务分类":"编辑财务分类";
        var row=initial is null?new DbRow{["type"]=direction,["enabled"]=1,["sortOrder"]=0}:new DbRow(initial);
        var fields=new FieldSet(row,[new("label","分类名称",Required:true),new("sortOrder","排序",FieldKind.Number,true),new("enabled","启用",FieldKind.Toggle)]);
        ((Entry)fields.Inputs["label"]).MaxLength=30;
        var body=Ui.Stack(Ui.Card(Ui.Stack(Ui.Pill(direction=="INCOME"?"收入分类":"支出分类"),fields.View)),Ui.Button("保存分类",async()=>
        {
            var value=fields.Read();var saved=service.SaveFinanceCategory(value);created?.Invoke(service.Db.Find("FinanceCategory",saved)!.Text("code"));await DisplayAlertAsync("已保存","分类已保存。","完成");await Navigation.PopAsync();
        }));body.Padding=18;Content=new ScrollView{Content=body};
    }
}