This commit is contained in:
student 2024-10-04 15:41:04 +03:00
commit 1bcaac832a
258 changed files with 13722 additions and 0 deletions

13
App.axaml Normal file
View File

@ -0,0 +1,13 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="demo_trade.App"
xmlns:local="using:demo_trade"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

32
App.axaml.cs Normal file
View File

@ -0,0 +1,32 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using demo_trade.ViewModels;
using demo_trade.Views;
namespace demo_trade
{
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}
base.OnFrameworkInitializationCompleted();
}
}
}

BIN
Assets/avalonia-logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Category
{
public int CategoryId { get; set; }
public string? CategoryName { get; set; }
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Manufacturer
{
public int ManufacturerId { get; set; }
public string? ManufacturerName { get; set; }
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Order
{
public int Orderid { get; set; }
public string Orderstatus { get; set; } = null!;
public DateOnly Orderdeliverydate { get; set; }
public int Orderpickuppoint { get; set; }
public decimal? OrderSumCost { get; set; }
public string? ClientName { get; set; }
public virtual PickupPoint OrderpickuppointNavigation { get; set; } = null!;
public virtual ICollection<Orderproduct> Orderproducts { get; set; } = new List<Orderproduct>();
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Orderproduct
{
public int Orderid { get; set; }
public string Productarticlenumber { get; set; } = null!;
public int? ProductCount { get; set; }
public virtual Order Order { get; set; } = null!;
public virtual Product ProductarticlenumberNavigation { get; set; } = null!;
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class PickupPoint
{
public int PickupPointId { get; set; }
public string? PickupPointName { get; set; }
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Porductprovider
{
public int PorductproviderId { get; set; }
public string? PorductproviderName { get; set; }
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Product
{
public string Productarticlenumber { get; set; } = null!;
public string? Productname { get; set; }
public string? Productdescription { get; set; }
public byte[]? Productphoto { get; set; }
public decimal? Productcost { get; set; }
public short? Productdiscountamount { get; set; }
public int? Productquantityinstock { get; set; }
public string? Imagename { get; set; }
public int? UnitId { get; set; }
public int? Productmaxdiscount { get; set; }
public int? CategoryId { get; set; }
public int? ManufacturerId { get; set; }
public int? PorductproviderId { get; set; }
public virtual Category? Category { get; set; }
public virtual Manufacturer? Manufacturer { get; set; }
public virtual ICollection<Orderproduct> Orderproducts { get; set; } = new List<Orderproduct>();
public virtual Porductprovider? Porductprovider { get; set; }
public virtual Productunit? Unit { get; set; }
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Productunit
{
public int UnitId { get; set; }
public string UnitName { get; set; } = null!;
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class Role
{
public int Roleid { get; set; }
public string Rolename { get; set; } = null!;
public virtual ICollection<User> Users { get; set; } = new List<User>();
}

View File

@ -0,0 +1,225 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace demo_trade.Data.RemoteData.Entity;
public partial class TradeContext : DbContext
{
public TradeContext()
{
}
public TradeContext(DbContextOptions<TradeContext> options)
: base(options)
{
}
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Manufacturer> Manufacturers { get; set; }
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<Orderproduct> Orderproducts { get; set; }
public virtual DbSet<PickupPoint> PickupPoints { get; set; }
public virtual DbSet<Porductprovider> Porductproviders { get; set; }
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<Productunit> Productunits { get; set; }
public virtual DbSet<Role> Roles { get; set; }
public virtual DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
=> optionsBuilder.UseNpgsql("Host=localhost;Username=postgres;Database=trade;Password=Student");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>(entity =>
{
entity.HasKey(e => e.CategoryId).HasName("category_pkey");
entity.ToTable("category");
entity.Property(e => e.CategoryId)
.UseIdentityAlwaysColumn()
.HasColumnName("category_id");
entity.Property(e => e.CategoryName).HasColumnName("category_name");
});
modelBuilder.Entity<Manufacturer>(entity =>
{
entity.HasKey(e => e.ManufacturerId).HasName("manufacturer_pkey");
entity.ToTable("manufacturer");
entity.Property(e => e.ManufacturerId)
.UseIdentityAlwaysColumn()
.HasColumnName("manufacturer_id");
entity.Property(e => e.ManufacturerName).HasColumnName("manufacturer_name");
});
modelBuilder.Entity<Order>(entity =>
{
entity.HasKey(e => e.Orderid).HasName("Order_pkey");
entity.ToTable("Order");
entity.Property(e => e.Orderid)
.UseIdentityAlwaysColumn()
.HasColumnName("orderid");
entity.Property(e => e.Orderdeliverydate).HasColumnName("orderdeliverydate");
entity.Property(e => e.Orderpickuppoint).HasColumnName("orderpickuppoint");
entity.Property(e => e.Orderstatus).HasColumnName("orderstatus");
entity.Property(e => e.ClientName).HasColumnName("client_name");
entity.Property(e => e.OrderSumCost).HasColumnName("order_sum_cost");
entity.HasOne(d => d.OrderpickuppointNavigation).WithMany(p => p.Orders)
.HasForeignKey(d => d.Orderpickuppoint)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("Order_orderpickuppoint_fkey");
});
modelBuilder.Entity<Orderproduct>(entity =>
{
entity.HasKey(e => new { e.Orderid, e.Productarticlenumber }).HasName("orderproduct_pkey");
entity.ToTable("orderproduct");
entity.Property(e => e.Orderid).HasColumnName("orderid");
entity.Property(e => e.Productarticlenumber).HasColumnName("productarticlenumber");
entity.Property(e => e.ProductCount).HasColumnName("product_count");
entity.HasOne(d => d.Order).WithMany(p => p.Orderproducts)
.HasForeignKey(d => d.Orderid)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("orderproduct_orderid_fkey");
entity.HasOne(d => d.ProductarticlenumberNavigation).WithMany(p => p.Orderproducts)
.HasForeignKey(d => d.Productarticlenumber)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("orderproduct_productarticlenumber_fkey");
});
modelBuilder.Entity<PickupPoint>(entity =>
{
entity.HasKey(e => e.PickupPointId).HasName("pickup_point_pkey");
entity.ToTable("pickup_point");
entity.Property(e => e.PickupPointId)
.UseIdentityAlwaysColumn()
.HasColumnName("pickup_point_id");
entity.Property(e => e.PickupPointName).HasColumnName("pickup_point_name");
});
modelBuilder.Entity<Porductprovider>(entity =>
{
entity.HasKey(e => e.PorductproviderId).HasName("porductprovider_pkey");
entity.ToTable("porductprovider");
entity.Property(e => e.PorductproviderId)
.UseIdentityAlwaysColumn()
.HasColumnName("porductprovider_id");
entity.Property(e => e.PorductproviderName).HasColumnName("porductprovider_name");
});
modelBuilder.Entity<Product>(entity =>
{
entity.HasKey(e => e.Productarticlenumber).HasName("product_pkey1");
entity.ToTable("product");
entity.Property(e => e.Productarticlenumber).HasColumnName("productarticlenumber");
entity.Property(e => e.CategoryId).HasColumnName("category_id");
entity.Property(e => e.Imagename)
.HasMaxLength(50)
.HasColumnName("imagename");
entity.Property(e => e.ManufacturerId).HasColumnName("manufacturer_id");
entity.Property(e => e.PorductproviderId).HasColumnName("porductprovider_id");
entity.Property(e => e.Productcost)
.HasPrecision(19, 4)
.HasColumnName("productcost");
entity.Property(e => e.Productdescription).HasColumnName("productdescription");
entity.Property(e => e.Productdiscountamount).HasColumnName("productdiscountamount");
entity.Property(e => e.Productmaxdiscount).HasColumnName("productmaxdiscount");
entity.Property(e => e.Productname).HasColumnName("productname");
entity.Property(e => e.Productphoto).HasColumnName("productphoto");
entity.Property(e => e.Productquantityinstock).HasColumnName("productquantityinstock");
entity.Property(e => e.UnitId).HasColumnName("unit_id");
entity.HasOne(d => d.Category).WithMany(p => p.Products)
.HasForeignKey(d => d.CategoryId)
.HasConstraintName("product_category_id_fkey");
entity.HasOne(d => d.Manufacturer).WithMany(p => p.Products)
.HasForeignKey(d => d.ManufacturerId)
.HasConstraintName("product_manufacturer_id_fkey");
entity.HasOne(d => d.Porductprovider).WithMany(p => p.Products)
.HasForeignKey(d => d.PorductproviderId)
.HasConstraintName("product_porductprovider_id_fkey");
entity.HasOne(d => d.Unit).WithMany(p => p.Products)
.HasForeignKey(d => d.UnitId)
.HasConstraintName("product_unit_id_fkey1");
});
modelBuilder.Entity<Productunit>(entity =>
{
entity.HasKey(e => e.UnitId).HasName("productunit_pkey");
entity.ToTable("productunit");
entity.Property(e => e.UnitId)
.UseIdentityAlwaysColumn()
.HasColumnName("unit_id");
entity.Property(e => e.UnitName).HasColumnName("unit_name");
});
modelBuilder.Entity<Role>(entity =>
{
entity.HasKey(e => e.Roleid).HasName("Role_pkey");
entity.ToTable("Role");
entity.Property(e => e.Roleid)
.UseIdentityAlwaysColumn()
.HasColumnName("roleid");
entity.Property(e => e.Rolename).HasColumnName("rolename");
});
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.Userid).HasName("User_pkey");
entity.ToTable("User");
entity.Property(e => e.Userid)
.UseIdentityAlwaysColumn()
.HasColumnName("userid");
entity.Property(e => e.Userlogin).HasColumnName("userlogin");
entity.Property(e => e.Username).HasColumnName("username");
entity.Property(e => e.Userpassword).HasColumnName("userpassword");
entity.Property(e => e.Userpatronymic).HasColumnName("userpatronymic");
entity.Property(e => e.Userrole).HasColumnName("userrole");
entity.Property(e => e.Usersurname).HasColumnName("usersurname");
entity.HasOne(d => d.UserroleNavigation).WithMany(p => p.Users)
.HasForeignKey(d => d.Userrole)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("User_userrole_fkey");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace demo_trade.Data.RemoteData.Entity;
public partial class User
{
public int Userid { get; set; }
public string Usersurname { get; set; } = null!;
public string Username { get; set; } = null!;
public string Userpatronymic { get; set; } = null!;
public string Userlogin { get; set; } = null!;
public string Userpassword { get; set; } = null!;
public int Userrole { get; set; }
public virtual Role UserroleNavigation { get; set; } = null!;
}

View File

@ -0,0 +1,14 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public interface ILoginRepository: IDisposable
{
User? GetUserByLogin(string login);
}
}

View File

@ -0,0 +1,18 @@
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Order = demo_trade.Data.RemoteData.Entity.Order;
namespace demo_trade.Data.Repository
{
public interface IOrderManagerRepository: IDisposable
{
List<Order> GetAllOrders();
bool EditRangeOrders(List<OrderChanged> orders);
}
}

View File

@ -0,0 +1,16 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public interface IOrderRepository
{
List<Order> GetAllOrders();
int GetNumberForNewOrder();
Order CreateOrder(Order order, List<Orderproduct> orderproducts);
}
}

View File

@ -0,0 +1,15 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public interface IPickupRepository
{
List<PickupPoint> GetAllPickupPoints();
}
}

View File

@ -0,0 +1,18 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public interface IProductRepository : IDisposable
{
List<Product> GetProducts();
Boolean RemoveProductByArticleNumber(string articleNumber);
Product? UpdateProductByArticleNumber(Product product);
Product? GetProductByArticleNumber(string articleNumber);
void Save();
}
}

View File

@ -0,0 +1,27 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public class SQLLoginRepository : ILoginRepository
{
private TradeContext _tradeContext;
public SQLLoginRepository() {
_tradeContext = new TradeContext();
}
public void Dispose()
{
Dispose();
GC.SuppressFinalize(this);
}
public User? GetUserByLogin(string login)
{
return _tradeContext.Users.Where(user => user.Userlogin == login).FirstOrDefault();
}
}
}

View File

@ -0,0 +1,51 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public class SQLOrderClientRepository : IOrderRepository, IDisposable
{
private TradeContext _tradeContext;
public SQLOrderClientRepository() {
_tradeContext = new TradeContext();
}
public Order CreateOrder(Order order, List<Orderproduct> orderproducts)
{
using var transaction = _tradeContext.Database.BeginTransaction();
try {
var createdOrder = _tradeContext.Add(order);
_tradeContext.SaveChanges();
foreach (var product in orderproducts) {
_tradeContext.Add(new Orderproduct { Orderid = order.Orderid, Productarticlenumber = product.Productarticlenumber, ProductCount = product.ProductCount });
}
_tradeContext.SaveChanges();
transaction.Commit();
}
catch (Exception ex) {
}
return order;
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
public List<Order> GetAllOrders()
{
throw new NotImplementedException();
}
public int GetNumberForNewOrder()
{
return _tradeContext.Orders.Max(it => it.Orderid) + 1;
}
}
}

View File

@ -0,0 +1,52 @@
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Order = demo_trade.Data.RemoteData.Entity.Order;
namespace demo_trade.Data.Repository
{
public class SQLOrderManagerRepository : IOrderManagerRepository
{
private TradeContext _tradeContext;
public void Dispose()
{
GC.SuppressFinalize(this);
}
public SQLOrderManagerRepository() {
_tradeContext = new TradeContext();
}
public bool EditRangeOrders(List<OrderChanged> orders)
{
using var transaction = _tradeContext.Database.BeginTransaction();
try
{
foreach (var item in orders)
{
var order = _tradeContext.Orders.Find(item.OrderId);
if (item.OrderStatus == null) continue;
if (order.Orderstatus != item.OrderStatus) order.Orderstatus = item.OrderStatus;
if (item.OrderDeliveryDate == null) continue;
if (order.Orderdeliverydate != item.OrderDeliveryDate) order.Orderdeliverydate = item.OrderDeliveryDate.Value;
_tradeContext.SaveChanges();
}
transaction.Commit();
return true;
}
catch (Exception ex) {
return false;
}
}
public List<Order> GetAllOrders()
{
return _tradeContext.Orders.Include(it => it.Orderproducts).ThenInclude(it => it.ProductarticlenumberNavigation).Include(it => it.OrderpickuppointNavigation).ToList();
}
}
}

View File

@ -0,0 +1,22 @@
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public class SQLPickupRepository : IPickupRepository
{
private TradeContext _tradeContext;
public SQLPickupRepository() {
_tradeContext = new TradeContext();
}
public List<PickupPoint> GetAllPickupPoints()
{
return _tradeContext.PickupPoints.ToList();
}
}
}

View File

@ -0,0 +1,56 @@
using demo_trade.Data.RemoteData.Entity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Data.Repository
{
public class SQLProductRepository : IProductRepository
{
private TradeContext _tradeContext;
public SQLProductRepository() {
_tradeContext = new TradeContext();
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
public Product? GetProductByArticleNumber(string articleNumber)
{
return _tradeContext.Products.Where(it => articleNumber == it.Productarticlenumber).FirstOrDefault();
}
public List<Product> GetProducts()
{
return _tradeContext.Products.Include(manfucture => manfucture.Manufacturer).Select(it => it).ToList();
}
public bool RemoveProductByArticleNumber(string articleNumber)
{
Product? product = GetProductByArticleNumber(articleNumber);
if (product != null)
{
_tradeContext.Products.Remove(product);
return true;
}
return false;
}
public void Save()
{
_tradeContext.SaveChanges();
}
public Product? UpdateProductByArticleNumber(Product product)
{
_tradeContext.Entry(product).State = EntityState.Modified;
return product;
}
}
}

View File

@ -0,0 +1,41 @@
using demo_trade.Data.Repository;
using demo_trade.Models;
using demo_trade.UI.Presenters;
using demo_trade.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Domain
{
public class GuestProductUseCase
{
private IProductRepository _productRepository;
public GuestProductUseCase(IProductRepository productRepository) {
_productRepository = productRepository;
}
public List<ProductPresenter> GetProducts() => _productRepository
.GetProducts()
.Select(it => new ProductPresenter
{
ArticleNumber = it.Productarticlenumber,
Description = it.Productdescription,
Name = it.Productname,
DiscountAmount = it.Productdiscountamount,
Cost = it.Productcost == null ? 0 : Convert.ToDecimal(it.Productcost),
ProductMaxDiscount = it.Productmaxdiscount,
QuantityInStock = it.Productquantityinstock,
Manufacturer = new Manufacturer { Id = it.Manufacturer.ManufacturerId, Name = it.Manufacturer.ManufacturerName },
Image = !String.IsNullOrEmpty(it.Imagename) ?
ImageHelper.BASE_URL + "/" + it.Imagename
: ImageHelper.BASE_URL + "/" + "default.png"
,
}).ToList();
}
}

29
Domain/LoginUseCase.cs Normal file
View File

@ -0,0 +1,29 @@
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Data.Repository;
using demo_trade.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Domain
{
public class LoginUseCase
{
private ILoginRepository _loginRepository;
public LoginUseCase(ILoginRepository loginRepository) {
_loginRepository = loginRepository;
}
public User AutorizationByLoginAndPassword(UserLogin userLogin)
{
User? user = _loginRepository.GetUserByLogin(userLogin.Login);
if (user == null) throw new AuthenticationException("Пользователь не найден");
if (user.Userpassword != userLogin.Password) throw new AuthenticationException("Пароли не совпадают");
return user;
}
}
}

View File

@ -0,0 +1,40 @@
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Data.Repository;
using demo_trade.UI.Presenters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Domain
{
public class OrderClientUseCase
{
private IOrderRepository _orderRepository;
private IPickupRepository _pickupRepository;
public OrderClientUseCase(IOrderRepository orderRepository, IPickupRepository pickupRepository) {
_orderRepository = orderRepository;
_pickupRepository = pickupRepository;
}
public List<PickupPoint> GetPickupPoints() => _pickupRepository.GetAllPickupPoints();
public int GetNewOrderNumber() => _orderRepository.GetNumberForNewOrder();
public Models.Order? GenerateNewOrder(PickupPoint orderPickupPoint, List<OrderProductPresenter> products,decimal orderSumCost, string? clientName = null) {
int daysOrderCount = CheckProductsQuntity(products) ? 3 : 6;
Order order = new Order { Orderdeliverydate = DateOnly.FromDateTime(DateTime.Now.AddDays(daysOrderCount)), Orderpickuppoint = orderPickupPoint.PickupPointId, Orderstatus = "Новый", ClientName= clientName, OrderSumCost=orderSumCost};
List<Orderproduct> orderproducts = products.Select(it => new Orderproduct { Productarticlenumber = it.ArticleNumber, ProductCount = it.ProductCount }).ToList();
var resultOrder = _orderRepository.CreateOrder(order, orderproducts);
if (resultOrder != null) return new demo_trade.Models.Order { Orderid = resultOrder.Orderid, Orderdeliverydate = resultOrder.Orderdeliverydate, PickupPointName = orderPickupPoint.PickupPointName, Orderstatus = resultOrder.Orderstatus, ProductList =products, OrderClient=clientName, OrderSumCost=orderSumCost };
return null;
}
private bool CheckProductsQuntity(List<OrderProductPresenter> orderProducts) {
foreach (var product in orderProducts) {
if (product.QuantityInStock <= 3) return false;
}
return true;
}
}
}

View File

@ -0,0 +1,44 @@
using demo_trade.Data.Repository;
using demo_trade.Models;
using demo_trade.UI.Presenters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Domain
{
public class OrderManagerUseCase
{
private IOrderManagerRepository _orderRepository;
public OrderManagerUseCase(IOrderManagerRepository orderRepository) {
_orderRepository = orderRepository;
}
public void ChangeOrders(List<OrderChanged> orderChangeds) {
_orderRepository.EditRangeOrders(orderChangeds);
}
public List<OrderManager> GetOrders()
{
return _orderRepository.GetAllOrders().Select(it => new OrderManager {
OrderClient = it.ClientName,
Orderdeliverydate = it.Orderdeliverydate,
Orderid = it.Orderid,
Orderstatus = it.Orderstatus,
PickupPointName = it.OrderpickuppointNavigation.PickupPointName,
ProductList = String.Join("\n", it.Orderproducts.Select(product => String.Format("Article: {0} Count: {1} Stock: {2}",
product.Productarticlenumber,
product.ProductCount,
product.ProductarticlenumberNavigation.Productquantityinstock
)).ToList()),
OrderSumCost = it.OrderSumCost,
ProductStock = it.Orderproducts.Select(it => it.ProductarticlenumberNavigation).ToList()
}).ToList();
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Exceptions
{
class AutorizeException : Exception
{
public AutorizeException(string message) : base(message) { }
}
}

15
Models/Manufacturer.cs Normal file
View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
}

25
Models/Order.cs Normal file
View File

@ -0,0 +1,25 @@
using demo_trade.UI.Presenters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class Order
{
public int Orderid { get; set; }
public string Orderstatus { get; set; }
public string? OrderClient { get; set; } = null;
public DateOnly Orderdeliverydate { get; set; }
public string PickupPointName { get; set; }
public decimal OrderSumCost { get; set; }
public List<OrderProductPresenter> ProductList{ get; set; }
}
}

15
Models/OrderChanged.cs Normal file
View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class OrderChanged
{
public int OrderId { get; set; }
public string? OrderStatus { get; set; }
public DateOnly? OrderDeliveryDate { get; set; }
}
}

26
Models/OrderManager.cs Normal file
View File

@ -0,0 +1,26 @@
using demo_trade.UI.Presenters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class OrderManager
{
public int Orderid { get; set; }
public string Orderstatus { get; set; }
public string? OrderClient { get; set; } = null;
public DateOnly Orderdeliverydate { get; set; }
public string PickupPointName { get; set; }
public decimal? OrderSumCost { get; set; }
public string ProductList { get; set; }
public List<demo_trade.Data.RemoteData.Entity.Product> ProductStock { get; set; }
}
}

25
Models/Product.cs Normal file
View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class Product
{
public string ArticleNumber { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Cost { get; set; }
public short? DiscountAmount { get; set; }
public int? QuantityInStock { get; set; }
public int? ProductMaxDiscount { get; set; }
public Manufacturer Manufacturer { get; set; }
}
}

54
Models/Ticket.cs Normal file
View File

@ -0,0 +1,54 @@
using demo_trade.UI.Presenters;
using iText.IO.Font.Constants;
using iText.Kernel.Font;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using PdfFont = iText.Kernel.Font.PdfFont;
namespace demo_trade.Models
{
public class Ticket
{
public int OrderID { get; set; }
public string PickupPointName{ get; set; }
public decimal OrderSumCost{ get; set; }
public string? ClientName { get; set; } = null;
public DateOnly OrderDate { get; set; }
public DateOnly OrderDelivery { get; set; }
public List<OrderProductPresenter> Products { get; set; }
public int OrderCode { get; set; }
public void GeneratePDF(string path) {
using var document = new Document();
PdfWriter.GetInstance(document, new FileStream(path, FileMode.OpenOrCreate));
document.Open();
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
BaseFont baseFont = BaseFont.CreateFont("C:\\Windows\\Fonts\\arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font font = new Font(baseFont, iTextSharp.text.Font.DEFAULTSIZE, iTextSharp.text.Font.NORMAL);
Font fontCode = new Font(baseFont, iTextSharp.text.Font.DEFAULTSIZE, iTextSharp.text.Font.BOLD);
Paragraph paragraph = new Paragraph(String.Format("Order №{0} Create {1} Data delivery {2}\nПункт выдачи: {3}\nСумма заказа: {4}", OrderID, OrderDate, OrderDelivery, PickupPointName, OrderSumCost), font);
if (ClientName != null) paragraph.Add(String.Format("\nClient name: {0}", ClientName));
document.Add(paragraph);
foreach (OrderProductPresenter presenter in Products) {
document.Add(new Phrase(String.Format("Article: {0}, Name: {2}, Count: {1}\n", presenter.ArticleNumber, presenter.ProductCount, presenter.Name), font));
}
GenerateCode();
document.Add(new Paragraph(String.Format("Code: {0}", OrderCode), fontCode));
document.Close();
}
private void GenerateCode() {
OrderCode = new Random().Next(100, 999);
}
}
}

15
Models/UserLogin.cs Normal file
View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Models
{
public class UserLogin
{
public string Login { get; set; }
public string Password { get; set; }
}
}

21
Program.cs Normal file
View File

@ -0,0 +1,21 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
namespace demo_trade
{
internal sealed class Program
{
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
}

View File

@ -0,0 +1,27 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Converters
{
public class ItemEnableConverterByDate : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
DateOnly date = (DateOnly)value;
return date >= DateOnly.FromDateTime(DateTime.Now);
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@ -0,0 +1,28 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
using demo_trade.Data.RemoteData.Entity;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Converters
{
public class ItemColorOrderConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var products = (List<Product>)value;
return products.Where(it => it.Productquantityinstock < 3).ToList().Count > 0 ? new SolidColorBrush(Colors.Yellow) : new SolidColorBrush(Colors.White);
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@ -0,0 +1,30 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Converters
{
public class ItemComboboxConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
string status = (string)value;
return status == "Новый" ? 0: 1;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
int status = (int)value;
return status != 0 ? "Завершен" : "Новый";
}
}
}

View File

@ -0,0 +1,30 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tmds.DBus.Protocol;
namespace demo_trade.UI.Converters
{
public class ItemDateConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var date = (DateOnly)value;
return new DateTimeOffset(new DateTime(date.Year, date.Month, date.Day));
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var date = (DateTimeOffset)value;
return new DateOnly(date.Year, date.Month, date.Day);
}
}
}

View File

@ -0,0 +1,26 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Converters
{
public class ItemColorConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return (short?)value > 15? new SolidColorBrush(Colors.Yellow) : new SolidColorBrush(Colors.White);
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Presenters
{
public class OrderProductPresenter: ProductPresenter
{
public int ProductCount { get; set; }
public OrderProductPresenter(ProductPresenter productPresenter, int count) {
this.ArticleNumber = productPresenter.ArticleNumber;
this.ProductCount = count;
this.ProductMaxDiscount = productPresenter.ProductMaxDiscount;
this.QuantityInStock = productPresenter.QuantityInStock;
this.Manufacturer = productPresenter.Manufacturer;
this.Description = productPresenter.Description;
this.Name = productPresenter.Name;
this.Cost = productPresenter.Cost;
this.DiscountAmount = productPresenter.DiscountAmount;
this.Image = productPresenter.Image;
}
}
}

View File

@ -0,0 +1,36 @@
using Avalonia.Media;
using Avalonia.Media.Imaging;
using demo_trade.Models;
using System.Threading.Tasks;
namespace demo_trade.UI.Presenters
{
public class ProductPresenter
{
public string ArticleNumber { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Cost { get; set; }
public short? DiscountAmount { get; set; }
public int? QuantityInStock { get; set; }
public string Image { get; set; }
public int? ProductMaxDiscount { get; set; }
public decimal? CostWithDiscount { get => Cost - (Cost * DiscountAmount / 100); }
public Manufacturer Manufacturer { get; set; }
public SolidColorBrush ColorBackgroundItem { get => DiscountAmount < 15 ?
new SolidColorBrush(Color.FromRgb(255, 255, 255))
:
new SolidColorBrush(Color.FromRgb(255, 245, 0));
}
}
}

15
UI/Themes/Colors.cs Normal file
View File

@ -0,0 +1,15 @@
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.UI.Themes
{
public static class Colors
{
public static Color White = new Color(255, 255, 255, 255);
public static Color Green = new Color(255, 255, 245, 0);
}
}

37
Utils/ImageHelper.cs Normal file
View File

@ -0,0 +1,37 @@
using Avalonia.Media.Imaging;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.Utils
{
public static class ImageHelper
{
public static string BASE_URL = "http://localhost:5025/images";
public static async Task<Bitmap?> LoadFromRemoteByName(string imageName)
{
if (String.IsNullOrWhiteSpace(imageName)) imageName = "default.png";
using var httpClient = new HttpClient();
try
{
var response = await httpClient.GetAsync(BASE_URL + "/" + imageName);
var data = await response.Content.ReadAsByteArrayAsync();
var bimap = new Bitmap(new MemoryStream(data));
bimap.Save(imageName);
return new Bitmap(new MemoryStream(data));
}
catch (Exception ex)
{
return null;
}
}
}
}

23
ViewLocator.cs Normal file
View File

@ -0,0 +1,23 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using demo_trade.ViewModels;
using ReactiveUI;
using System;
namespace demo_trade
{
public class ViewLocator : ReactiveUI.IViewLocator
{
public IViewFor? ResolveView<T>(T? viewModel, string? contract = null) => viewModel switch
{
LoginViewModel context => new LoginControl { DataContext = context },
GuestProductViewModel context => new GuestProductControl { DataContext = context },
ClientProductViewModel context => new ClientProductControl{ DataContext = context },
OrderShowDialogViewModel context => new OrderShowDialog{ DataContext = context},
OrderManagerViewModel context => new OrderManagerControl { DataContext = context },
_ => throw new ArgumentOutOfRangeException(nameof(viewModel))
};
}
}

View File

@ -0,0 +1,179 @@
using Avalonia.Markup.Xaml.Templates;
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Data.Repository;
using demo_trade.Domain;
using demo_trade.Models;
using demo_trade.UI.Presenters;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using Tmds.DBus.Protocol;
namespace demo_trade.ViewModels
{
public class ClientProductViewModel : ViewModelBase, IRoutableViewModel
{
private GuestProductUseCase _guestProductUseCase;
public string? UrlPathSegment => Guid.NewGuid().ToString();
private User _user = new();
private bool _isManager = false;
public bool IsManager { get => _isManager; set => this.RaiseAndSetIfChanged(ref _isManager, value); }
private Dictionary<string, (ProductPresenter, int)> _productOrder = new();
public Dictionary<string, (ProductPresenter, int)> ProductOrder
{
get => _productOrder;
set => this.RaiseAndSetIfChanged(ref _productOrder, value);
}
public User AutorizedUser {
get => _user;
set => this.RaiseAndSetIfChanged(ref _user, value);
}
private List<ProductPresenter> _productOrderList = new();
public List<ProductPresenter> ProductOrderList
{
get => _productOrderList;
set => this.RaiseAndSetIfChanged(ref _productOrderList, value);
}
private bool _thereItemsInOrder = false;
public bool ThereItemsInOrder
{
get => _thereItemsInOrder;
set => this.RaiseAndSetIfChanged(ref _thereItemsInOrder, value);
}
private Dictionary<int, (int, int?)> _filterValues = new Dictionary<int, (int, int?)>() {
{0, (0, null)},
{1, (0, 10)},
{2, (10, 15)},
{3, (15, null)}
};
public ReactiveCommand<ProductPresenter, Unit> AddToOrderCommand { get; }
public ReactiveCommand<Unit, Unit> AttachToOrderCommand { get; }
public ReactiveCommand<Unit, Unit> AttachToOrderManagerCommand { get; }
private int _selectedFilterValue = 0;
private int _selectedSortValue = 0;
public int SelectedFilterValue
{
get => _selectedFilterValue;
set => this.RaiseAndSetIfChanged(ref _selectedFilterValue, value);
}
public int SelectedSortValue
{
get => _selectedSortValue;
set => this.RaiseAndSetIfChanged(ref _selectedSortValue, value);
}
private string _searchWord = string.Empty;
public string SearchWord
{
get => _searchWord;
set => this.RaiseAndSetIfChanged(ref _searchWord, value);
}
private string _statisticText = string.Empty;
public string StatisticText
{
get => _statisticText;
set => this.RaiseAndSetIfChanged(ref _statisticText, value);
}
private List<ProductPresenter> _dataSource = new();
private List<ProductPresenter> _products = new();
public List<ProductPresenter> Products
{
get => _products;
set => this.RaiseAndSetIfChanged(ref _products, value);
}
public IScreen HostScreen { get; }
public ClientProductViewModel(IScreen home, IProductRepository productRepository, User user)
{
AutorizedUser = user;
HostScreen = home;
if (AutorizedUser.Userrole == 1 || AutorizedUser.Userrole == 3) IsManager = true;
_guestProductUseCase = new GuestProductUseCase(productRepository);
_dataSource = _guestProductUseCase.GetProducts();
this.WhenAnyValue(search => search.SearchWord).Subscribe(_ => { DisplayList(); });
this.WhenAnyValue(selectedFilter => selectedFilter.SelectedFilterValue).Subscribe(_ => { DisplayList(); });
this.WhenAnyValue(selectedSort => selectedSort.SelectedSortValue).Subscribe(_ => { DisplayList(); });
DisplayList();
AddToOrderCommand = ReactiveCommand.Create<ProductPresenter>(product => {
if (ProductOrder.ContainsKey(product.ArticleNumber))
{
var values = ProductOrder[product.ArticleNumber];
ProductOrder[product.ArticleNumber] = (product, values.Item2 + 1);
}
else
{
ProductOrder.Add(product.ArticleNumber, (product, 1));
}
ThereItemsInOrder = ProductOrder.Keys.Count > 0;
});
AttachToOrderManagerCommand = ReactiveCommand.Create(
() =>
{
var orderManagerUseCase = new OrderManagerUseCase(new SQLOrderManagerRepository());
HostScreen.Router.Navigate.Execute(new OrderManagerViewModel(HostScreen, orderManagerUseCase));
}
);
ShowDialog = new Interaction<OrderShowDialogViewModel, bool>();
AttachToOrderCommand = ReactiveCommand.CreateFromTask(async () =>
{
var userOrderCase = new OrderClientUseCase(new SQLOrderClientRepository(), new SQLPickupRepository());
var order = new OrderShowDialogViewModel(ProductOrder, userOrderCase, user);
var result = await ShowDialog.Handle(order);
}
);
}
public Interaction<OrderShowDialogViewModel, bool> ShowDialog { get; }
private bool FilterByDiscount(short? discount)
{
if (discount == null) return false;
(int leftBound, int? rightBound) = _filterValues[SelectedFilterValue];
if (rightBound == null) return leftBound <= discount;
return leftBound <= discount && discount < rightBound;
}
private void DisplayList()
{
var temp = _dataSource;
if (SelectedFilterValue > 0)
{
temp = temp.Where(it => FilterByDiscount(it.DiscountAmount)).ToList();
}
if (!String.IsNullOrEmpty(SearchWord))
{
temp = temp.Where(it => it.Name.Contains(SearchWord, StringComparison.CurrentCultureIgnoreCase)).ToList();
}
if (SelectedSortValue == 1)
{
temp = temp.OrderByDescending(it => it.Cost).ToList();
}
else if (SelectedSortValue == 2)
{
temp = temp.OrderBy(it => it.Cost).ToList();
}
this.Products = temp;
StatisticText = String.Format("{0} из {1}", temp.Count, _dataSource.Count);
}
}
}

View File

@ -0,0 +1,142 @@
using Avalonia.Markup.Xaml.Templates;
using demo_trade.Data.Repository;
using demo_trade.Domain;
using demo_trade.Models;
using demo_trade.UI.Presenters;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.ViewModels
{
public class GuestProductViewModel : ViewModelBase, IRoutableViewModel
{
private GuestProductUseCase _guestProductUseCase;
private Dictionary<string, (ProductPresenter, int)> _productOrder = new();
public Dictionary<string, (ProductPresenter, int)> ProductOrder
{
get => _productOrder;
set => this.RaiseAndSetIfChanged(ref _productOrder, value);
}
private bool _thereItemsInOrder = false;
public bool ThereItemsInOrder {
get => _thereItemsInOrder;
set => this.RaiseAndSetIfChanged(ref _thereItemsInOrder, value);
}
public string? UrlPathSegment => Guid.NewGuid().ToString();
private Dictionary<int, (int, int?)> _filterValues = new Dictionary<int, (int, int?)>() {
{0, (0, null)},
{1, (0, 10)},
{2, (10, 15)},
{3, (15, null)}
};
public ReactiveCommand<ProductPresenter, Unit> AddToOrderCommand { get; }
public ReactiveCommand<Unit, Unit> AttachToOrderCommand { get; }
private int _selectedFilterValue = 0;
private int _selectedSortValue = 0;
public int SelectedFilterValue {
get => _selectedFilterValue;
set => this.RaiseAndSetIfChanged(ref _selectedFilterValue, value);
}
public int SelectedSortValue
{
get => _selectedSortValue;
set => this.RaiseAndSetIfChanged(ref _selectedSortValue, value);
}
private string _searchWord = string.Empty;
public string SearchWord {
get => _searchWord;
set => this.RaiseAndSetIfChanged(ref _searchWord, value);
}
private string _statisticText = string.Empty;
public string StatisticText
{
get => _statisticText;
set => this.RaiseAndSetIfChanged(ref _statisticText, value);
}
private List<ProductPresenter> _dataSource = new();
private List<ProductPresenter> _products = new();
public List<ProductPresenter> Products {
get => _products;
set => this.RaiseAndSetIfChanged(ref _products, value);
}
public IScreen HostScreen { get; }
public GuestProductViewModel(IScreen home, IProductRepository productRepository) {
HostScreen = home;
_guestProductUseCase = new GuestProductUseCase(productRepository);
_dataSource = _guestProductUseCase.GetProducts();
this.WhenAnyValue(search => search.SearchWord).Subscribe(_ => { DisplayList(); });
this.WhenAnyValue(selectedFilter => selectedFilter.SelectedFilterValue).Subscribe(_ => { DisplayList(); });
this.WhenAnyValue(selectedSort => selectedSort.SelectedSortValue).Subscribe(_ => { DisplayList(); });
DisplayList();
AddToOrderCommand = ReactiveCommand.Create<ProductPresenter>(product => {
if (ProductOrder.ContainsKey(product.ArticleNumber))
{
var values = ProductOrder[product.ArticleNumber];
ProductOrder[product.ArticleNumber] = (product, values.Item2 + 1);
}
else {
ProductOrder.Add(product.ArticleNumber, (product, 1));
}
ThereItemsInOrder = ProductOrder.Keys.Count > 0;
});
ShowDialog = new Interaction<OrderShowDialogViewModel, bool>();
AttachToOrderCommand = ReactiveCommand.CreateFromTask(async() =>
{
var userOrderCase = new OrderClientUseCase(new SQLOrderClientRepository(), new SQLPickupRepository());
var order = new OrderShowDialogViewModel(ProductOrder, userOrderCase);
var result = await ShowDialog.Handle(order);
}
);
}
private bool FilterByDiscount(short? discount) {
if (discount == null) return false;
(int leftBound, int? rightBound) = _filterValues[SelectedFilterValue];
if (rightBound == null) return leftBound <= discount;
return leftBound <= discount && discount < rightBound;
}
private void DisplayList() {
var temp = _dataSource;
if (SelectedFilterValue > 0) {
temp = temp.Where(it => FilterByDiscount(it.DiscountAmount)).ToList();
}
if (!String.IsNullOrEmpty(SearchWord)) {
temp = temp.Where(it => it.Name.Contains(SearchWord, StringComparison.CurrentCultureIgnoreCase)).ToList();
}
if (SelectedSortValue == 1)
{
temp = temp.OrderByDescending(it => it.Cost).ToList();
}
else if (SelectedSortValue == 2) {
temp = temp.OrderBy(it => it.Cost).ToList();
}
this.Products = temp;
StatisticText = String.Format("{0} из {1}", temp.Count, _dataSource.Count);
}
public Interaction<OrderShowDialogViewModel, bool> ShowDialog { get; }
}
}

View File

@ -0,0 +1,63 @@
using demo_trade.Data.Repository;
using demo_trade.Domain;
using demo_trade.Models;
using ReactiveUI;
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.ViewModels
{
public class LoginViewModel: ViewModelBase, IRoutableViewModel
{
private LoginUseCase _loginUseCase;
private string _errorMessage = string.Empty;
public string ErrorMessage { get => _errorMessage; set => this.RaiseAndSetIfChanged(ref _errorMessage, value); }
private UserLogin _userLogin = new();
public UserLogin UserLogin {
get => _userLogin;
set => this.RaiseAndSetIfChanged(ref _userLogin, value);
}
public ReactiveCommand<Unit, Unit> LoginCommand { get;}
public ReactiveCommand<Unit, Unit> GuestCommand { get; }
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
public IScreen HostScreen { get; }
public LoginViewModel(IScreen screen, ILoginRepository loginRepository) {
_loginUseCase = new LoginUseCase(loginRepository);
HostScreen = screen;
LoginCommand = ReactiveCommand.Create(() =>
{
try
{
var userLogin = _loginUseCase.AutorizationByLoginAndPassword(_userLogin);
SQLProductRepository sqlProductRepository = new SQLProductRepository();
HostScreen.Router.Navigate.Execute(new ClientProductViewModel(HostScreen, sqlProductRepository, userLogin));
}
catch (Exception ex) {
ErrorMessage = ex.Message;
}
}
);
GuestCommand = ReactiveCommand.Create(() => {
SQLProductRepository sqlProductRepository = new SQLProductRepository();
HostScreen.Router.Navigate.Execute(new GuestProductViewModel(HostScreen, sqlProductRepository));
});
}
}
}

View File

@ -0,0 +1,19 @@
using demo_trade.Data.Repository;
using ReactiveUI;
using System.Reactive;
namespace demo_trade.ViewModels
{
public partial class MainWindowViewModel : ReactiveObject, IScreen
{
public RoutingState Router { get; } = new RoutingState();
public MainWindowViewModel() {
SQLLoginRepository loginRepository = new SQLLoginRepository();
Router.Navigate.Execute(new LoginViewModel(this, loginRepository));
}
}
}

View File

@ -0,0 +1,81 @@
using demo_trade.Domain;
using demo_trade.Models;
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.ViewModels
{
public class OrderManagerViewModel : ViewModelBase, IRoutableViewModel
{
OrderManagerUseCase _orderManagerUseCase;
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
private ObservableCollection<OrderManager> _orders = new();
private Dictionary<int, OrderChanged> _changedOrdes = new();
private List<OrderManager> _dateSource = new();
public ObservableCollection<OrderManager> Orders { get => _orders; set => this.RaiseAndSetIfChanged(ref _orders, value); }
private int _selectedSortNumber = 0;
public int SelectedSortNumber { get => _selectedSortNumber; set => this.RaiseAndSetIfChanged(ref _selectedSortNumber, value); }
public IScreen HostScreen { get; }
public ReactiveCommand<Unit, Unit> ConfirmChangeCommand { get; }
public OrderManagerViewModel(IScreen screen, OrderManagerUseCase orderManagerUseCase)
{
_orderManagerUseCase = orderManagerUseCase;
_dateSource = _orderManagerUseCase.GetOrders();
this.WhenAnyValue(sort => sort.SelectedSortNumber).Subscribe(_ => DisplayList());
ConfirmChangeCommand = ReactiveCommand.Create(() => {
if (_changedOrdes.Values.Count == 0) return;
_orderManagerUseCase.ChangeOrders(_changedOrdes.Values.ToList());
});
HostScreen = screen;
}
private void DisplayList() {
var temp = _dateSource;
if (SelectedSortNumber == 1)
{
temp = temp.OrderByDescending(it => it.OrderSumCost).ToList();
}
else if (SelectedSortNumber == 2) temp = temp.OrderBy(it => it.OrderSumCost).ToList();
_orders.Clear();
foreach (var order in temp)
{
_orders.Add(order);
}
}
public void OrderDateChanged(int id, DateTimeOffset dateDelivery) {
if (dateDelivery.DateTime <= DateTime.Now) return;
if (_changedOrdes.ContainsKey(id)) {
_changedOrdes[id].OrderDeliveryDate = DateOnly.FromDateTime(dateDelivery.DateTime);
return;
}
_changedOrdes.Add(id, new OrderChanged { OrderDeliveryDate = DateOnly.FromDateTime(dateDelivery.DateTime), OrderId= id });
}
public void OrderStatusChanged(int id, int status)
{
if (status != 1) return;
if (_changedOrdes.ContainsKey(id))
{
_changedOrdes[id].OrderStatus = "Завершен";
return;
}
_changedOrdes.Add(id, new OrderChanged { OrderStatus = "Завершен", OrderId = id });
}
}
}

View File

@ -0,0 +1,119 @@
using Avalonia.Controls;
using demo_trade.Data.RemoteData.Entity;
using demo_trade.Domain;
using demo_trade.Models;
using demo_trade.UI.Presenters;
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace demo_trade.ViewModels
{
public class OrderShowDialogViewModel : ViewModelBase
{
private OrderClientUseCase _orderClientUseCase;
private PickupPoint _pickupPointSelected = new();
public PickupPoint PickupPointSelected { get => _pickupPointSelected; set => this.RaiseAndSetIfChanged(ref _pickupPointSelected, value); }
private Models.Order? orderComplete { get; set; } = null;
private string _userName = String.Empty;
public string UserName{ get => _userName; set => this.RaiseAndSetIfChanged(ref _userName, value); }
private int _numberOrder = 0;
public int NumberOrder { get => _numberOrder; set => this.RaiseAndSetIfChanged(ref _numberOrder, value); }
private int _selectedPointId = 0;
public int SelectedPointId { get => _selectedPointId; set => this.RaiseAndSetIfChanged(ref _selectedPointId, value); }
private List<PickupPoint> _pickupPoints = new();
public List<PickupPoint> PickupPoints { get => _pickupPoints; set => this.RaiseAndSetIfChanged(ref _pickupPoints, value); }
private Decimal _orderSumValue = 0;
public Decimal OrderSumValue { get => _orderSumValue; set => this.RaiseAndSetIfChanged(ref _orderSumValue, value); }
public ReactiveCommand<Unit, Unit> GenerateOrderCommand { get; }
private ObservableCollection<OrderProductPresenter> _productOrderList = new();
public ObservableCollection<OrderProductPresenter> ProductOrderList
{
get => _productOrderList;
set => this.RaiseAndSetIfChanged(ref _productOrderList, value);
}
public OrderShowDialogViewModel( Dictionary<string, (ProductPresenter, int)> orderProducts, OrderClientUseCase orderClientUseCase, User? user = null) {
_orderClientUseCase = orderClientUseCase;
_numberOrder = _orderClientUseCase.GetNewOrderNumber();
_pickupPoints = _orderClientUseCase.GetPickupPoints();
if (user != null)
{
UserName = String.Format("{0} {1} {2}", user.Usersurname, user.Username, user.Userpatronymic);
}
GenerateOrderCommand = ReactiveCommand.Create(() => {
string? clientName = null;
if(!String.IsNullOrEmpty(UserName)) clientName = UserName;
var resultOrder = _orderClientUseCase.GenerateNewOrder(PickupPointSelected, ProductOrderList.ToList(),OrderSumValue, clientName);
if (resultOrder != null) {
NumberOrder = resultOrder.Orderid + 1;
orderComplete = resultOrder;
}
});
foreach (var item in orderProducts.Values)
{
ProductOrderList.Add(new OrderProductPresenter(item.Item1, item.Item2));
}
this.WhenAnyValue(it => it.ProductOrderList).Subscribe(it => CalculateOrderSum());
}
public void NumericChange(string ArticleProduct, int value) {
ProductOrderList.First(it => it.ArticleNumber == ArticleProduct).ProductCount = value;
CalculateOrderSum();
if (value == 0)
{
ProductOrderList.Remove(ProductOrderList.First(it => it.ArticleNumber == ArticleProduct));
return;
}
}
public void SaveFile(string path) {
if (orderComplete == null) return;
Ticket ticket = new Ticket()
{
ClientName = orderComplete.OrderClient,
OrderID = orderComplete.Orderid,
OrderDate = DateOnly.FromDateTime(DateTime.Now),
OrderDelivery = orderComplete.Orderdeliverydate,
Products = orderComplete.ProductList,
PickupPointName = orderComplete.PickupPointName,
OrderSumCost = orderComplete.OrderSumCost
}
;
ticket.GeneratePDF(path);
}
private void CalculateOrderSum() {
var orderSum = ProductOrderList.Sum(product => {
if (product.CostWithDiscount != null) return product.CostWithDiscount * product.ProductCount;
return product.ProductCount * product.Cost;
});
if (orderSum != null) OrderSumValue = orderSum.Value;
}
}
}

View File

@ -0,0 +1,9 @@
using CommunityToolkit.Mvvm.ComponentModel;
using ReactiveUI;
namespace demo_trade.ViewModels
{
public class ViewModelBase : ReactiveObject
{
}
}

View File

@ -0,0 +1,74 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="using:demo_trade.ViewModels"
x:DataType="vm:ClientProductViewModel"
xmlns:conv="using:demo_trade.UI.Converters"
x:Class="demo_trade.ClientProductControl">
<UserControl.Resources>
<conv:ItemColorConverter x:Key="itemColorConverter"/>
</UserControl.Resources>
<Grid ColumnDefinitions="*" RowDefinitions="50, *, 50" ShowGridLines="True">
<StackPanel
Margin="5"
Orientation="Horizontal"
DockPanel.Dock="Top"
HorizontalAlignment="Center"
Grid.Row="0"
Spacing="10">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} {2}">
<Binding Path="AutorizedUser.Usersurname"/>
<Binding Path="AutorizedUser.Username"/>
<Binding Path="AutorizedUser.Userpatronymic"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding StatisticText}"/>
<TextBox Text="{Binding SearchWord}" MinWidth="200"/>
<ComboBox MinWidth="100" SelectedIndex="{Binding SelectedFilterValue}">
<ComboBoxItem>Все диапазоны</ComboBoxItem>
<ComboBoxItem>0-9.99%</ComboBoxItem>
<ComboBoxItem>10-14.99%</ComboBoxItem>
<ComboBoxItem>15% и болле</ComboBoxItem>
</ComboBox>
<ComboBox MinWidth="100" SelectedIndex="{Binding SelectedSortValue}">
<ComboBoxItem>отсут.</ComboBoxItem>
<ComboBoxItem>по убыв.</ComboBoxItem>
<ComboBoxItem>по возраст.</ComboBoxItem>
</ComboBox>
</StackPanel>
<ListBox ItemsSource="{Binding Products}" Padding="15" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel ContextMenu="" Orientation="Horizontal" Spacing="10" Background="{Binding DiscountAmount, Converter={StaticResource itemColorConverter}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding $parent[ListBox].((vm:ClientProductViewModel)DataContext).AddToOrderCommand}" CommandParameter="{Binding}" Header="Добавить в заказ"/>
</ContextMenu>
</StackPanel.ContextMenu>
<Image/>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Name, StringFormat='Название товара: {0}'}"/>
<TextBlock Text="{Binding Description, StringFormat='Описание товара: {0}'}"/>
<TextBlock Text="{Binding Manufacturer.Name, StringFormat='Производитель товара: {0}' }"/>
</StackPanel>
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding DiscountAmount, StringFormat='Скидка: {0}%'}"/>
</Border>
<TextBlock Text="{Binding Cost, StringFormat='Цена: {0}'}"/>
<TextBlock Text="{Binding CostWithDiscount, StringFormat='Цена с учетом скидки: {0}'}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Row="2">
<Button Content="Перейти к заказу" IsVisible="{Binding ThereItemsInOrder}" Command="{Binding AttachToOrderCommand}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
<Button Content="Управление заказами" IsVisible="{Binding IsManager}" Command="{Binding AttachToOrderManagerCommand}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,29 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
using System.Reactive.Disposables;
using System.Threading.Tasks;
namespace demo_trade;
public partial class ClientProductControl : ReactiveUserControl<ClientProductViewModel>
{
public ClientProductControl()
{
this.WhenActivated(disposables => disposables(ViewModel!.ShowDialog.RegisterHandler(DoShowOrderDialogAsync)));
AvaloniaXamlLoader.Load(this);
}
private async Task DoShowOrderDialogAsync(InteractionContext<OrderShowDialogViewModel, bool> interaction)
{
var dialog = new OrderShowDialog();
dialog.DataContext = interaction.Input;
var result = await dialog.ShowDialog<OrderShowDialogViewModel>(TopLevel.GetTopLevel(this) as Window);
interaction.SetOutput(true);
}
}

View File

@ -0,0 +1,65 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="using:demo_trade.ViewModels"
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
xmlns:conv="using:demo_trade.UI.Converters"
x:DataType="vm:GuestProductViewModel"
x:Class="demo_trade.GuestProductControl">
<UserControl.Resources>
<conv:ItemColorConverter x:Key="itemColorConverter"/>
</UserControl.Resources>
<Grid ColumnDefinitions="*" RowDefinitions="50, *, 50" ShowGridLines="True">
<StackPanel
Margin="5"
Orientation="Horizontal"
DockPanel.Dock="Top"
HorizontalAlignment="Center"
Grid.Row="0"
Spacing="10">
<TextBlock Text="{Binding StatisticText}"/>
<TextBox Text="{Binding SearchWord}" MinWidth="200"/>
<ComboBox MinWidth="100" SelectedIndex="{Binding SelectedFilterValue}">
<ComboBoxItem>Все диапазоны</ComboBoxItem>
<ComboBoxItem>0-9.99%</ComboBoxItem>
<ComboBoxItem>10-14.99%</ComboBoxItem>
<ComboBoxItem>15% и болле</ComboBoxItem>
</ComboBox>
<ComboBox MinWidth="100" SelectedIndex="{Binding SelectedSortValue}">
<ComboBoxItem>отсут.</ComboBoxItem>
<ComboBoxItem>по убыв.</ComboBoxItem>
<ComboBoxItem>по возраст.</ComboBoxItem>
</ComboBox>
</StackPanel>
<ListBox ItemsSource="{Binding Products}" Padding="15" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel ContextMenu="" Orientation="Horizontal" Spacing="10" Background="{Binding DiscountAmount, Converter={StaticResource itemColorConverter}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding $parent[ListBox].((vm:GuestProductViewModel)DataContext).AddToOrderCommand}" CommandParameter="{Binding}" Header="Добавить в заказ"/>
</ContextMenu>
</StackPanel.ContextMenu>
<Image asyncImageLoader:ImageLoader.Source="{Binding Image}" Height="50" Width="50"/>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Name, StringFormat='Название товара: {0}'}"/>
<TextBlock Text="{Binding Description, StringFormat='Описание товара: {0}'}"/>
<TextBlock Text="{Binding Manufacturer.Name, StringFormat='Производитель товара: {0}' }"/>
</StackPanel>
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding DiscountAmount, StringFormat='Скидка: {0}%'}"/>
</Border>
<TextBlock Text="{Binding Cost, StringFormat='Цена: {0}'}"/>
<TextBlock Text="{Binding CostWithDiscount, StringFormat='Цена с учетом скидки: {0}'}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Row="2">
<Button Content="Перейти к заказу" IsVisible="{Binding ThereItemsInOrder}" Command="{Binding AttachToOrderCommand}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,28 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
using System.Reactive.Disposables;
using System.Threading.Tasks;
namespace demo_trade;
public partial class GuestProductControl : ReactiveUserControl<GuestProductViewModel>
{
public GuestProductControl()
{
this.WhenActivated(disposables => disposables(ViewModel!.ShowDialog.RegisterHandler(DoShowOrderDialogAsync)));
AvaloniaXamlLoader.Load(this);
}
private async Task DoShowOrderDialogAsync(InteractionContext<OrderShowDialogViewModel, bool> interaction){
var dialog = new OrderShowDialog();
dialog.DataContext = interaction.Input;
var result = await dialog.ShowDialog<OrderShowDialogViewModel>(TopLevel.GetTopLevel(this) as Window);
interaction.SetOutput(true);
}
}

22
Views/LoginControl.axaml Normal file
View File

@ -0,0 +1,22 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
xmlns:vm="using:demo_trade.ViewModels"
x:DataType="vm:LoginViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="demo_trade.LoginControl">
<StackPanel Width="200" Spacing="15" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Login"/>
<TextBox Text="{Binding UserLogin.Login}"/>
<TextBlock Text="Password"/>
<TextBox Text="{Binding UserLogin.Password}" PasswordChar="*"/>
<TextBlock Text="{Binding ErrorMessage}" Foreground="Red" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="5" HorizontalAlignment="Center">
<Button Content="Login" Command="{Binding LoginCommand}"/>
<Button Content="Guest" Command="{Binding GuestCommand}"/>
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
namespace demo_trade;
public partial class LoginControl : ReactiveUserControl<LoginViewModel>
{
public LoginControl()
{
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this);
}
}

21
Views/MainWindow.axaml Normal file
View File

@ -0,0 +1,21 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:rxui="http://reactiveui.net"
xmlns:app="clr-namespace:demo_trade"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:demo_trade.ViewModels"
xmlns:local="clr-namespace:demo_trade.UI.Converters;assembly=demo_trade.UI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="demo_trade.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="demo_trade">
<DockPanel>
<rxui:RoutedViewHost Router="{Binding Router}" DockPanel.Dock="Right" Background="AliceBlue">
<rxui:RoutedViewHost.ViewLocator>
<app:ViewLocator />
</rxui:RoutedViewHost.ViewLocator>
</rxui:RoutedViewHost>
</DockPanel>
</Window>

23
Views/MainWindow.axaml.cs Normal file
View File

@ -0,0 +1,23 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
using System.Net.Security;
using System.Reactive.Disposables;
using System.Threading.Tasks;
namespace demo_trade.Views
{
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{
public MainWindow()
{
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -0,0 +1,47 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="using:demo_trade.ViewModels"
x:DataType="vm:OrderManagerViewModel"
xmlns:conv="using:demo_trade.UI.Converters"
x:Class="demo_trade.OrderManagerControl">
<UserControl.Resources>
<conv:ItemDateConverter x:Key="itemDateConverter"/>
<conv:ItemColorOrderConverter x:Key="itemColorOrderConverter"/>
<conv:ItemComboboxConverter x:Key="itemComboboxConverter"/>
<conv:ItemEnableConverterByDate x:Key="itemEnableConverterByDate"/>
</UserControl.Resources>
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" >
<ComboBox MinWidth="100" SelectedIndex="{Binding SelectedSortNumber}">
<ComboBoxItem>отсут.</ComboBoxItem>
<ComboBoxItem>по убыв.</ComboBoxItem>
<ComboBoxItem>по возраст.</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Content="Применить" Command="{Binding ConfirmChangeCommand}"/>
</StackPanel>
<ListBox ItemsSource="{Binding Orders}">
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel Orientation="Vertical" Background="{Binding ProductStock, Converter={StaticResource itemColorOrderConverter}}">
<TextBlock Text="{Binding Orderid, StringFormat='Номер заказа: {0}'}"/>
<ComboBox SelectedIndex="{Binding Orderstatus, Converter={StaticResource itemComboboxConverter}}" IsEnabled="{Binding Orderdeliverydate, Converter={StaticResource itemEnableConverterByDate}}" Tag="{Binding Orderid}" SelectionChanged="StatusComboBox_SelectionChanged">
<ComboBoxItem>Новый</ComboBoxItem>
<ComboBoxItem>Завершен</ComboBoxItem>
</ComboBox>
<DatePicker SelectedDate="{Binding Orderdeliverydate, Converter={StaticResource itemDateConverter}}" Tag="{Binding Orderid}" SelectedDateChanged="DeliveryDatePicker_SelectedDateChanged"/>
<TextBlock Text="{Binding PickupPointName, StringFormat='Пункт выдачи:{0}'}"/>
<TextBlock Text="{Binding OrderSumCost, StringFormat='Сумма заказа: {0}'}" IsVisible="{Binding OrderSumCost, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<TextBlock Text="{Binding OrderClient, StringFormat='Клиент: {0}'}" IsVisible="{Binding OrderClient, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<TextBlock Text="{Binding ProductList}"/>
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</UserControl>

View File

@ -0,0 +1,36 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
namespace demo_trade;
public partial class OrderManagerControl : ReactiveUserControl<OrderManagerViewModel>
{
public OrderManagerControl()
{
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this);
}
private void DeliveryDatePicker_SelectedDateChanged(object? sender, Avalonia.Controls.DatePickerSelectedValueChangedEventArgs e)
{
var datePicker = (DatePicker)sender;
int? orderId = datePicker.Tag as int?;
if (orderId != null && datePicker.SelectedDate != null && datePicker.IsEnabled) {
ViewModel.OrderDateChanged(orderId.Value, datePicker.SelectedDate.Value);
}
}
private void StatusComboBox_SelectionChanged(object? sender, Avalonia.Controls.SelectionChangedEventArgs e)
{
var comboBox = (ComboBox)sender;
int? orderId = comboBox.Tag as int?;
if (orderId != null && comboBox.SelectedIndex > 0 && comboBox.IsEnabled)
{
ViewModel.OrderStatusChanged(orderId.Value, comboBox.SelectedIndex);
}
}
}

View File

@ -0,0 +1,57 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="demo_trade.OrderShowDialog"
xmlns:vm="using:demo_trade.ViewModels"
x:DataType="vm:OrderShowDialogViewModel"
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
Title="OrderShowDialog">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="20" HorizontalAlignment="Center">
<TextBlock IsVisible="{Binding UserName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Text="{Binding UserName, StringFormat='Пользователь: {0}'}"/>
<TextBlock Text="{Binding OrderSumValue, StringFormat='Общая сумма: {0}'}"/>
<TextBlock Text="{Binding NumberOrder, StringFormat='Номер заказа: {0}'}"/>
<ComboBox ItemsSource="{Binding PickupPoints}" SelectedItem="{Binding PickupPointSelected}" SelectedIndex="{Binding SelectedPointId}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text >
<MultiBinding StringFormat="№{0}: {1}">
<Binding Path="PickupPointId"/>
<Binding Path="PickupPointName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock/>
</StackPanel>
<StackPanel DockPanel.Dock="Bottom">
<Button Content="Сформировать заказ" HorizontalAlignment="Center" Command="{Binding GenerateOrderCommand}" Click="Save_Click"/>
</StackPanel>
<ListBox ItemsSource="{Binding ProductOrderList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel ContextMenu="" Orientation="Horizontal" Spacing="10">
<Image asyncImageLoader:ImageLoader.Source="{Binding Image}" Height="50" Width="50"/>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Name, StringFormat='Название товара: {0}'}"/>
<TextBlock Text="{Binding Description, StringFormat='Описание товара: {0}'}"/>
<TextBlock Text="{Binding Manufacturer.Name, StringFormat='Производитель товара: {0}' }"/>
</StackPanel>
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding DiscountAmount, StringFormat='Скидка: {0}%'}"/>
</Border>
<TextBlock Text="{Binding Cost, StringFormat='Цена: {0}'}"/>
<NumericUpDown Value="{Binding ProductCount}" Tag="{Binding ArticleNumber}" Minimum="0" Maximum="{Binding QuantityInStock}" ValueChanged="NumericUpDown_ValueChanged"/>
<TextBlock Text="{Binding CostWithDiscount, StringFormat='Цена с учетом скидки: {0}'}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>

View File

@ -0,0 +1,42 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Dialogs.Internal;
using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage;
using Avalonia.ReactiveUI;
using demo_trade.ViewModels;
using ReactiveUI;
using System.Collections.Generic;
using Tmds.DBus.Protocol;
namespace demo_trade;
public partial class OrderShowDialog : ReactiveWindow<OrderShowDialogViewModel>
{
public OrderShowDialog()
{
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this);
}
private void NumericUpDown_ValueChanged(object? sender, Avalonia.Controls.NumericUpDownValueChangedEventArgs e)
{
var numeric = (sender as NumericUpDown);
if (numeric.Tag == null) return;
string? aritcle = numeric.Tag.ToString();
if (numeric.Value == null) return;
ViewModel.NumericChange(aritcle, (int)numeric.Value );
}
private static FilePickerFileType Pdf { get; } = new FilePickerFileType("All pdf") { Patterns = new[] { ".pdf" } };
private async void Save_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var file = await TopLevel.GetTopLevel(this).StorageProvider.SaveFilePickerAsync(new Avalonia.Platform.Storage.FilePickerSaveOptions
{
Title = "Ñîõðàíèòü òàëîí",
FileTypeChoices = new List<FilePickerFileType> { Pdf }
});
if (file != null) ViewModel!.SaveFile(file.Path.AbsolutePath);
}
}

18
app.manifest Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="demo_trade.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

BIN
bin/Debug/net8.0/A543T6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/Debug/net8.0/D419T7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More