Files
Store.Management/Source/Store.Management/Views/Dialogs/UserBillingDialog.xaml.cs
T
2026-11-13 19:19:33 +08:00

129 lines
5.0 KiB
C#

using Store.Management.Framework.ViewModels;
using Prism.Commands;
using Prism.Services.Dialogs;
using Store.Management.Api.Transport;
using Store.Management.Api.Users;
using Store.Management.Framework.Controls;
using Store.Management.Framework.Services;
using NumericUpDown = HandyControl.Controls.NumericUpDown;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Input;
namespace Store.Management.Views.Dialogs;
public partial class UserBillingDialog : UserControl
{
public UserBillingDialog() => InitializeComponent();
private void OnAmountValueChanged(object sender, HandyControl.Data.FunctionEventArgs<double> e)
{
if (sender is NumericUpDown { IsKeyboardFocusWithin: true, DataContext: UserBillingDialogViewModel.BillingField field })
{
field.Value = (decimal)e.Info;
}
}
private void OnAmountTextChanged(object sender, TextChangedEventArgs e)
{
// 显式输入与控件初始值相同的金额时,Value 不会触发变化。
if (sender is NumericUpDown { IsKeyboardFocusWithin: true, DataContext: UserBillingDialogViewModel.BillingField field }
&& e.OriginalSource is TextBox input
&& decimal.TryParse(input.Text, NumberStyles.Number, CultureInfo.CurrentCulture, out decimal amount)
&& amount == field.Value)
{
field.Value = amount;
}
}
}
public sealed class UserBillingDialogViewModel(IUserService userService) : ConfirmDialogViewModel<UserItemViewModel>
{
public sealed class BillingField(string label, decimal? original, decimal minimum,
Action<UserBillingUpdateRequest, decimal> apply, bool integer = false)
{
private readonly decimal? originalValue = original;
public string Label { get; } = label;
public decimal? EnteredValue { get; private set; } = original;
public decimal Value
{
get => EnteredValue ?? minimum;
set => EnteredValue = value;
}
public decimal Minimum => Math.Min(originalValue ?? minimum, minimum);
public decimal Maximum => Math.Max(originalValue ?? minimum, integer ? int.MaxValue : 999999m);
public int DecimalPlaces => integer ? 0 : 2;
public decimal Increment => integer ? 1m : 0.01m;
internal bool ApplyChange(UserBillingUpdateRequest request)
{
if (EnteredValue is not decimal value || value == originalValue)
{
return false;
}
decimal maximum = integer ? int.MaxValue : 999999m;
if (value < minimum || value > maximum || decimal.Round(value, DecimalPlaces) != value)
{
throw new FormatException($"{Label}范围为 {minimum} 至 {maximum}" + (integer ? ",请输入整数。" : ",最多两位小数。"));
}
apply(request, value);
return true;
}
}
public BillingField[] Fields { get; private set => SetProperty(ref field, value); } = [];
public override void OnDialogOpened(IDialogParameters parameters)
{
base.OnDialogOpened(parameters);
Title = $"计费配置 · {Parameter.UserName}";
Fields =
[
new("店铺每月续费积分(积分/月)", Parameter.ShopPointsPerMonth, 30m, (request, value) => request.ShopPointsPerMonth = (int)value, integer: true),
new("中转仓快递费(元/单)", Parameter.PostagePerOrder, 2.20m, (request, value) => request.PostagePerOrder = value),
new("中转仓退货快递费(元/单)", Parameter.RefundPostagePerOrder, 2.50m, (request, value) => request.RefundPostagePerOrder = value),
new("礼物单附加费(元/单)", Parameter.GiftOemAmountPerOrder, 0m, (request, value) => request.GiftOemAmountPerOrder = value),
new("物流同步费(元/单)", Parameter.SyncLogisticsPerOrder, 0m, (request, value) => request.SyncLogisticsPerOrder = value)
];
}
public override bool CanCloseDialog() => !IsLoading;
public override ICommand ConfirmCommand => field ??= new AsyncDelegateCommand(SaveAsync);
private async Task SaveAsync()
{
var request = new UserBillingUpdateRequest { Id = Parameter.Id };
try
{
bool changed = false;
foreach (BillingField field in Fields)
{
changed |= field.ApplyChange(request);
}
if (!changed)
{
OnRequestClose(new DialogResult(ButtonResult.Cancel));
return;
}
ErrorMsg = "";
IsLoading = true;
await userService.UpdateBillingAsync(request);
}
catch (FormatException ex)
{
ErrorMsg = ex.Message;
return;
}
catch (ApiException ex)
{
ErrorMsg = ex.Message;
return;
}
finally
{
IsLoading = false;
}
OnRequestClose(new DialogResult(ButtonResult.OK));
}
}