|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
|
|
using Sln.Wcs.Repository.service.@base;
|
|
|
|
|
using Sln.Wcs.UI.Views.Base;
|
|
|
|
|
|
|
|
|
|
namespace Sln.Wcs.UI.ViewModels.Base;
|
|
|
|
|
|
|
|
|
|
public interface ICrudPageViewModel
|
|
|
|
|
{
|
|
|
|
|
void Load();
|
|
|
|
|
Avalonia.Controls.Control CreateView();
|
|
|
|
|
string PageTitle { get; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract partial class CrudPageViewModel<T> : ObservableObject, ICrudPageViewModel where T : class, new()
|
|
|
|
|
{
|
|
|
|
|
protected readonly IBaseService<T> _service;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private ObservableCollection<T> _items = new();
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private T? _selectedItem;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private string _searchText = string.Empty;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private string _pageTitle = string.Empty;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private string _statusText = string.Empty;
|
|
|
|
|
|
|
|
|
|
public abstract List<FieldConfig> FieldConfigs { get; }
|
|
|
|
|
public abstract Avalonia.Controls.Control CreateView();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Expression to search by name/code field. Override to customize.
|
|
|
|
|
/// Returns null to skip filtering (load all).
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected abstract Expression<Func<T, bool>>? BuildSearchExpression(string search);
|
|
|
|
|
|
|
|
|
|
protected CrudPageViewModel(IBaseService<T> service)
|
|
|
|
|
{
|
|
|
|
|
_service = service;
|
|
|
|
|
AddCommand = new AsyncRelayCommand(Add);
|
|
|
|
|
EditCommand = new AsyncRelayCommand(Edit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
public void Load()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
List<T> list;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(SearchText))
|
|
|
|
|
{
|
|
|
|
|
list = _service.Query();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var exp = BuildSearchExpression(SearchText);
|
|
|
|
|
list = exp != null ? _service.Query(exp) : _service.Query();
|
|
|
|
|
}
|
|
|
|
|
Items = new ObservableCollection<T>(list);
|
|
|
|
|
StatusText = $"共 {list.Count} 条记录";
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
StatusText = $"加载失败: {ex.Message}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AsyncRelayCommand AddCommand { get; }
|
|
|
|
|
public AsyncRelayCommand EditCommand { get; }
|
|
|
|
|
|
|
|
|
|
private async System.Threading.Tasks.Task Add()
|
|
|
|
|
{
|
|
|
|
|
var entity = new T();
|
|
|
|
|
var editor = new EntityEditWindow();
|
|
|
|
|
var result = await editor.ShowDialog(entity, FieldConfigs, false, GetMainWindow());
|
|
|
|
|
if (result)
|
|
|
|
|
{
|
|
|
|
|
_service.Insert(entity);
|
|
|
|
|
Load();
|
|
|
|
|
StatusText = "新增成功";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async System.Threading.Tasks.Task Edit()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedItem is null) return;
|
|
|
|
|
var editor = new EntityEditWindow();
|
|
|
|
|
var result = await editor.ShowDialog(SelectedItem, FieldConfigs, true, GetMainWindow());
|
|
|
|
|
if (result)
|
|
|
|
|
{
|
|
|
|
|
_service.Update(SelectedItem);
|
|
|
|
|
Load();
|
|
|
|
|
StatusText = "编辑成功";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void Delete()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedItem is null) return;
|
|
|
|
|
var prop = typeof(T).GetProperty("objId") ?? typeof(T).GetProperty("ObjId");
|
|
|
|
|
if (prop is null) return;
|
|
|
|
|
var id = prop.GetValue(SelectedItem);
|
|
|
|
|
_service.DeleteById(id!);
|
|
|
|
|
Load();
|
|
|
|
|
StatusText = "删除成功";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void Search()
|
|
|
|
|
{
|
|
|
|
|
Load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Avalonia.Controls.Window GetMainWindow()
|
|
|
|
|
{
|
|
|
|
|
return (Avalonia.Controls.Window)Avalonia.Application.Current!
|
|
|
|
|
.ApplicationLifetime!.GetType()
|
|
|
|
|
.GetProperty("MainWindow")!
|
|
|
|
|
.GetValue(Avalonia.Application.Current.ApplicationLifetime)!;
|
|
|
|
|
}
|
|
|
|
|
}
|