This commit is contained in:
oreshki
2026-04-09 18:54:22 +05:00
parent c6be661ac8
commit 4885765fb3
21 changed files with 735 additions and 102 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -38,6 +38,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Cryptography, Version=2.0.0.0, Culture=neutral, PublicKeyToken=072edcf4a5328938, processorArchitecture=MSIL">
<HintPath>..\packages\BouncyCastle.Cryptography.2.6.2\lib\net461\BouncyCastle.Cryptography.dll</HintPath>
</Reference>
<Reference Include="EasyCaptcha.Wpf, Version=0.9.0.3, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\EasyCaptcha.Wpf.0.9.0.3\lib\net45\EasyCaptcha.Wpf.dll</HintPath>
</Reference>
@@ -47,6 +50,9 @@
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="itextsharp, Version=5.5.13.5, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, processorArchitecture=MSIL">
<HintPath>..\packages\iTextSharp.5.5.13.5\lib\net461\itextsharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll</HintPath>
@@ -98,7 +104,10 @@
<Compile Include="Models\LoggnHistory.cs">
<DependentUpon>Model1.tt</DependentUpon>
</Compile>
<Compile Include="Services\AuthService.cs" />
<Compile Include="Services\StringToImageConverter.cs" />
<Compile Include="Services\Valid.cs" />
<Compile Include="ViewModels\AddPatientViewModel.cs" />
<Compile Include="ViewModels\BaseViewModel.cs" />
<Compile Include="Models\Insurance_Companies.cs">
<DependentUpon>Model1.tt</DependentUpon>
@@ -156,6 +165,10 @@
<Compile Include="Models\User.cs">
<DependentUpon>Model1.tt</DependentUpon>
</Compile>
<Page Include="Views\AddPatientWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\AdminWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -181,6 +194,9 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ViewModels\AdminModel.cs" />
<Compile Include="Views\AddPatientWindow.xaml.cs">
<DependentUpon>AddPatientWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Views\AdminWindow.xaml.cs">
<DependentUpon>AdminWindow.xaml</DependentUpon>
</Compile>
@@ -233,6 +249,10 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Laborant.jpeg" />
<Resource Include="Images\LaborantExplorer.png" />
<Resource Include="Images\Admin.png" />
<Resource Include="Images\Buhalter.jpeg" />
<Content Include="Models\Model1.Context.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Model1.Context.cs</LastGenOutput>

View File

@@ -1,4 +1,4 @@
// Создание кода T4 для модели "C:\Users\usersql\Source\Repos\UP01TASK3\Labaratory\Labaratory\Models\Model1.edmx" включено.
// Создание кода T4 для модели "C:\Users\usersql\source\repos\UP01TASK3\Labaratory\Labaratory\Models\Model1.edmx" включено.
// Чтобы включить формирование кода прежних версий, измените значение свойства "Стратегия создания кода" конструктора
// на "Legacy ObjectContext". Это свойство доступно в окне "Свойства", если модель
// открыта в конструкторе.

View File

@@ -46,13 +46,11 @@
<Property Name="Amount" Type="money" />
<Property Name="IssueDate" Type="date" />
</EntityType>
<!--Ошибки, обнаруженные при создании:
предупреждение 6002: В таблице или представлении "LaboratoryDB.dbo.LoggnHistory" не определен первичный ключ. Ключ был выведен, а определение таблицы или представления было создано в режиме только для чтения.-->
<EntityType Name="LoggnHistory">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="int" Nullable="false" />
<Property Name="ID" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Login" Type="nvarchar" MaxLength="50" />
<Property Name="AttemptTime" Type="datetime" />
<Property Name="IsSuccess" Type="bit" />
@@ -386,6 +384,7 @@
<EntitySet Name="Analyzers" EntityType="Self.Analyzers" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Insurance_Companies" EntityType="Self.Insurance_Companies" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Invoices" EntityType="Self.Invoices" Schema="dbo" store:Type="Tables" />
<EntitySet Name="LoggnHistory" EntityType="Self.LoggnHistory" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Order_Items" EntityType="Self.Order_Items" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Order_Statuses" EntityType="Self.Order_Statuses" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Orders" EntityType="Self.Orders" Schema="dbo" store:Type="Tables" />
@@ -397,14 +396,6 @@
<EntitySet Name="Services" EntityType="Self.Services" Schema="dbo" store:Type="Tables" />
<EntitySet Name="User_Services" EntityType="Self.User_Services" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Users" EntityType="Self.Users" Schema="dbo" store:Type="Tables" />
<EntitySet Name="LoggnHistory" EntityType="Self.LoggnHistory" store:Type="Tables" store:Schema="dbo">
<DefiningQuery>SELECT
[LoggnHistory].[ID] AS [ID],
[LoggnHistory].[Login] AS [Login],
[LoggnHistory].[AttemptTime] AS [AttemptTime],
[LoggnHistory].[IsSuccess] AS [IsSuccess]
FROM [dbo].[LoggnHistory] AS [LoggnHistory]</DefiningQuery>
</EntitySet>
<AssociationSet Name="FK__Analyzer___Analy__5629CD9C" Association="Self.FK__Analyzer___Analy__5629CD9C">
<End Role="Analyzers" EntitySet="Analyzers" />
<End Role="Analyzer_Logs" EntitySet="Analyzer_Logs" />

View File

@@ -0,0 +1,26 @@
using Labaratory.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Labaratory.Services
{
public static class AuthService
{
public static void LogAttempt(string login, bool isSuccess)
{
using (var db = new Models.LaboratoryDBEntities())
{
db.LoggnHistories.Add(new Models.LoggnHistory
{
AttemptTime = DateTime.Now,
Login = login,
IsSuccess = isSuccess
});
db.SaveChanges();
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace Labaratory.Services
{
public class StringToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string imageName = value as string;
if (string.IsNullOrWhiteSpace(imageName))
return null;
try
{
return new BitmapImage(new Uri($"pack://application:,,,/Images/{imageName}"));
}
catch
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
=> throw new NotImplementedException();
}
}

View File

@@ -1,4 +1,7 @@
using System;
using Labaratory.Models;
using Labaratory.ViewModels;
using Labaratory.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -26,5 +29,40 @@ namespace Labaratory.Services
if (string.IsNullOrEmpty(input)) return false;
return input.Trim().ToUpper() == original.ToUpper();
}
public static void OpenRoleWindow(User user)
{
if (user.Role.Value == 1)
{
var nextWindow = new AdminWindow();
var mainVM = new AdminModel(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 2)
{
var nextWindow = new ByhalterWindow();
var mainVM = new ByhalterModel(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 3)
{
var nextWindow = new Views.Laborant();
var mainVM = new ViewModels.Laborant(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 4)
{
var nextWindow = new Views.LaborantExplorer();
var mainVM = new ViewModels.LaborantExplorer(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
}
}
}

View File

@@ -0,0 +1,102 @@
using Labaratory.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using System.Windows.Input;
using Wpf.Ui.Input;
namespace Labaratory.ViewModels
{
public class AddPatientViewModel : BaseViewModel
{
private Models.LaboratoryDBEntities db = new Models.LaboratoryDBEntities();
public string Surname { get; set; }
public string FirstName { get; set; }
public string Patronymic { get; set; }
public DateTime BirthDate { get; set; } = DateTime.Now.AddYears(-20);
public string PassportSeries { get; set; }
public string PassportNumber { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string InsuranceNumber { get; set; }
public List<Models.Policy_Types> PolicyTypes => db.Policy_Types.ToList();
public List<Models.Insurance_Companies> Companies => db.Insurance_Companies.ToList();
public Models.Policy_Types SelectedPolicyType { get; set; }
public Models.Insurance_Companies SelectedCompany { get; set; }
public Models.Patient SavedPatient { get; private set; }
public ICommand SaveCommand { get; }
public ICommand CancelCommand { get; }
public AddPatientViewModel()
{
SaveCommand = new RelayCommand<Window>(ExecuteSave);
CancelCommand = new RelayCommand<Window>(ExecuteCancel);
}
private void ExecuteSave(Window window)
{
if (Save())
{
if (window != null)
{
window.DialogResult = true;
window.Close();
}
}
}
private void ExecuteCancel(Window window)
{
if (window != null)
{
window.DialogResult = false;
window.Close();
}
}
public bool Save()
{
try
{
if (string.IsNullOrWhiteSpace(Surname) || string.IsNullOrWhiteSpace(FirstName))
{
MessageBox.Show("Заполните обязательные поля: Фамилия и Имя");
return false;
}
var newPatient = new Models.Patient
{
Surname = Surname,
FirstName = FirstName,
Patronymic = Patronymic,
BirthDate = BirthDate,
PassportSeries = PassportSeries,
PassportNumber = PassportNumber,
Phone = Phone,
Email = Email,
InsuranceNumber = InsuranceNumber,
PolicyType = SelectedPolicyType?.ID_PolicyType,
Company = SelectedCompany?.ID_Company
};
db.Patients.Add(newPatient);
db.SaveChanges();
SavedPatient = newPatient;
return true;
}
catch (Exception ex)
{
MessageBox.Show("Ошибка при сохранении: " + ex.Message);
return false;
}
}
}
}

View File

@@ -7,6 +7,8 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Wpf.Ui.Input;
using Labaratory.Models;
using System.Collections.ObjectModel;
namespace Labaratory.ViewModels
{
@@ -17,6 +19,40 @@ namespace Labaratory.ViewModels
public AdminModel(Models.User user)
{
CurrentUser = user;
LoadData();
}
private Models.LaboratoryDBEntities db = new Models.LaboratoryDBEntities();
private string _filterLogin;
private List<LoggnHistory> _allLogs;
public string FilterLogin
{
get => _filterLogin;
set { _filterLogin = value; OnPropertyChanged(); ApplyFilter(); }
}
private ObservableCollection<LoggnHistory> _history;
public ObservableCollection<LoggnHistory> History
{
get => _history;
set { _history = value; OnPropertyChanged(); }
}
public void LoadData()
{
_allLogs = db.LoggnHistories.OrderByDescending(h => h.AttemptTime).ToList();
History = new ObservableCollection<LoggnHistory>(_allLogs);
}
private void ApplyFilter()
{
var filtered = _allLogs.AsEnumerable();
if (!string.IsNullOrWhiteSpace(FilterLogin))
{
filtered = filtered.Where(h => h.Login.ToLower().Contains(FilterLogin.ToLower()));
}
History = new ObservableCollection<LoggnHistory>(filtered);
}
}
}

View File

@@ -4,6 +4,14 @@ using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using Labaratory.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Wpf.Ui.Input;
using Labaratory.Views;
namespace Labaratory.ViewModels
{
@@ -15,10 +23,34 @@ namespace Labaratory.ViewModels
{
CurrentUser = user;
CalculateNextNumber();
ProcessOrderCommand = new RelayCommand<object>(execute => ProcessOrder());
}
private string _barcodeInput;
private string _suggestedNumber;
private Models.LaboratoryDBEntities db = new Models.LaboratoryDBEntities();
private Patient _selectedPatient;
private ObservableCollection<Service> _selectedServices = new ObservableCollection<Service>();
private decimal _totalCost;
public List<Models.Service> AllServices => db.Services.ToList();
public ICommand ProcessOrderCommand { get; }
public Patient SelectedPatient
{
get => _selectedPatient;
set { _selectedPatient = value; OnPropertyChanged(); }
}
public ObservableCollection<Models.Service> SelectedServices
{
get;
set;
} = new ObservableCollection<Models.Service>();
public decimal TotalCost
{
get => _totalCost;
set { _totalCost = value; OnPropertyChanged(); }
}
public string BarcodeInput
{
@@ -33,30 +65,9 @@ namespace Labaratory.ViewModels
}
private void CalculateNextNumber()
{
// Находим последний ID в заказах (кроме архивных, если есть флаг IsArchived)
//var lastId = db.Orders.OrderByDescending(o => o.ID).Select(o => o.ID).FirstOrDefault();
//SuggestedNumber = (lastId + 1).ToString();
BarcodeInput = SuggestedNumber; // Устанавливаем как значение по умолчанию
}
private string GetNextOrderNumber()
{
// Находим максимальный ID_Order
var lastId = db.Orders.OrderByDescending(o => o.ID_Order).Select(o => o.ID_Order).FirstOrDefault();
return (lastId + 1).ToString();
}
// Формирование полного штрих-кода по ТЗ
private string CreateFullBarcodeString(string orderId)
{
string datePart = DateTime.Now.ToString("ddMMyyyy");
// Генерируем 6 случайных цифр
Random rnd = new Random();
string randomPart = "";
for (int i = 0; i < 6; i++) randomPart += rnd.Next(0, 10).ToString();
// Результат: ID + Дата + 6 цифр
return $"{orderId}{datePart}{randomPart}";
SuggestedNumber = (lastId + 1).ToString();
BarcodeInput = SuggestedNumber;
}
public void ProcessOrder()
{
@@ -66,19 +77,173 @@ namespace Labaratory.ViewModels
return;
}
// Формируем полный код: ID + Дата + 6 случайных символов
string fullCode = GenerateFullBarcode(BarcodeInput);
// Сохраняем в PDF и БД
//SaveToPdf(fullCode);
//SaveOrderToDb(fullCode);
SaveToPdf(fullCode);
SaveOrderToDb(fullCode);
}
private string GenerateFullBarcode(string orderId)
{
string datePart = DateTime.Now.ToString("ddMMyyyy");
string uniquePart = Guid.NewGuid().ToString("N").Substring(0, 6); // 6 случайных символов
Random rnd = new Random();
string uniquePart = "";
for (int i = 0; i < 6; i++)
uniquePart += rnd.Next(0, 10).ToString();
return $"{orderId}{datePart}{uniquePart}";
}
private void SaveOrderToDb(string fullBarcode)
{
try
{
var newOrder = new Models.Order
{
Barcode = fullBarcode,
OrderDate = DateTime.Now,
ID_Order = int.Parse(BarcodeInput)
};
db.Orders.Add(newOrder);
db.SaveChanges();
MessageBox.Show($"Заказ успешно сохранен! Штрих-код: {fullBarcode}");
CalculateNextNumber();
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при сохранении в БД: {ex.Message}");
}
}
private void SaveToPdf(string fullCode)
{
string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), $"Barcode_{fullCode}.pdf");
const float mmToPt = 72f / 25.4f;
// Устанавливаем размер страницы чуть больше штрихкода
Document doc = new Document(new Rectangle(120 * mmToPt, 60 * mmToPt));
try
{
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(filePath, FileMode.Create));
doc.Open();
PdfContentByte cb = writer.DirectContent;
float startX = 3.63f * mmToPt;
float currentX = startX;
float y = 15 * mmToPt;
cb.SetColorFill(BaseColor.BLACK);
DrawGuardBar(cb, currentX, y, (22.85f + 1.65f), mmToPt);
currentX += (0.15f + 0.2f) * mmToPt;
foreach (char c in fullCode)
{
if (!char.IsDigit(c)) continue;
int digit = int.Parse(c.ToString());
float barWidth = (digit == 0) ? 1.35f : (0.15f * digit);
if (digit != 0)
{
cb.Rectangle(currentX, y + (1.65f * mmToPt), barWidth * mmToPt, 22.85f * mmToPt);
cb.Fill();
}
currentX += (barWidth + 0.2f) * mmToPt;
}
DrawGuardBar(cb, currentX, y, (22.85f + 1.65f), mmToPt);
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, "Cp1251", BaseFont.NOT_EMBEDDED);
cb.BeginText();
cb.SetFontAndSize(bf, 2.75f * mmToPt);
float textY = y - (3.0f * mmToPt);
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, fullCode, startX, textY, 0);
cb.EndText();
doc.Close();
MessageBox.Show($"PDF сохранен: {filePath}");
}
catch (Exception ex)
{
MessageBox.Show("Ошибка PDF: " + ex.Message);
}
}
private void DrawGuardBar(PdfContentByte cb, float x, float y, float height, float mmToPt)
{
cb.Rectangle(x, y, 0.15f * mmToPt, height * mmToPt);
cb.Fill();
}
public ICommand AddServiceCommand => new RelayCommand<Models.Service>(service =>
{
if (service != null)
{
SelectedServices.Add(service);
CalculateTotal();
}
});
public ICommand SearchPatientCommand => new RelayCommand<string>(fio =>
{
if (string.IsNullOrWhiteSpace(fio)) return;
var parts = fio.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string surname = parts[0];
string firstName = parts.Length > 1 ? parts[1] : "";
// 1. Ищем в БД
var patient = db.Patients.FirstOrDefault(p => p.Surname == surname && p.FirstName == firstName);
if (patient == null)
{
// 2. Если не нашли — открываем модальное окно
var addWin = new Views.AddPatientWindow();
var vm = new AddPatientViewModel { Surname = surname, FirstName = firstName };
addWin.DataContext = vm;
if (addWin.ShowDialog() == true)
{
SelectedPatient = vm.SavedPatient;
}
}
else
{
SelectedPatient = patient;
}
});
private void CalculateTotal()
{
TotalCost = SelectedServices.Sum(s => s.Price);
OnPropertyChanged(nameof(TotalCost));
}
private void CheckAndAddPatient(string searchSurname, string searchName)
{
var patient = db.Patients.FirstOrDefault(p => p.Surname == searchSurname && p.FirstName == searchName);
if (patient == null)
{
var addWin = new AddPatientWindow();
var vm = new AddPatientViewModel { Surname = searchSurname, FirstName = searchName };
addWin.DataContext = vm;
if (addWin.ShowDialog() == true)
{
SelectedPatient = vm.SavedPatient;
}
}
else
{
SelectedPatient = patient;
}
}
}
}

View File

@@ -9,6 +9,7 @@ using System.Windows.Input;
using Wpf.Ui.Input;
using Labaratory.ViewModels;
using Labaratory.Views;
using Labaratory.Models;
namespace Labaratory
{
@@ -59,14 +60,14 @@ namespace Labaratory
CaptchaText = Valid.GenerateCaptchaText();
CaptchaInput = string.Empty;
}
private async void ExecuteLogin(object parameter)
{
if (CapchaVisibility == Visibility.Visible && !Valid.ValidateCaptcha(CaptchaInput, CaptchaText))
{
LogAttempt(Login, false);
MessageBox.Show("Неверная капча!");
GenerateNewCaptcha();
await LockSystem(10); //Блокировка на 10 сек
await LockSystem(10);
return;
}
@@ -74,52 +75,40 @@ namespace Labaratory
if (user != null)
{
LogAttempt(Login, true);
MessageBox.Show($"Успешный вход! Добро пожаловать, {user.Login}");
if (parameter is Window window)
{
if (user.Role.Value == 1)
{
var nextWindow = new AdminWindow();
var mainVM = new AdminModel(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 2)
{
var nextWindow = new ByhalterWindow();
var mainVM = new ByhalterModel(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 3)
{
var nextWindow = new Views.Laborant();
var mainVM = new ViewModels.Laborant(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
if (user.Role.Value == 4)
{
var nextWindow = new Views.LaborantExplorer();
var mainVM = new ViewModels.LaborantExplorer(user);
nextWindow.DataContext = mainVM;
nextWindow.Show();
}
Valid.OpenRoleWindow(user);
window.Close();
}
}
else
{
LogAttempt(Login, false);
MessageBox.Show("Неверный логин или пароль");
CapchaVisibility = Visibility.Visible;
GenerateNewCaptcha();
}
}
private void LogAttempt(string login, bool isSuccess)
{
// Новый контекст гарантирует запись, даже если основной db "глючит"
using (var context = new Models.LaboratoryDBEntities())
{
var log = new Models.LoggnHistory
{
Login = login ?? "Unknown",
AttemptTime = DateTime.Now,
IsSuccess = isSuccess
};
context.LoggnHistories.Add(log);
context.SaveChanges();
}
}
private async Task LockSystem(int seconds)
{
IsLoginEnabled = false;

View File

@@ -0,0 +1,77 @@
<Window x:Class="Labaratory.Views.AddPatientWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="Регистрация нового пациента" Height="780" Width="500"
WindowStartupLocation="CenterScreen"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Карточка пациента" FontSize="20" FontWeight="SemiBold" Margin="0,0,0,20" />
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- Личные данные -->
<ui:TextBox Text="{Binding Surname}" PlaceholderText="Фамилия*" Margin="0,5" />
<ui:TextBox Text="{Binding FirstName}" PlaceholderText="Имя*" Margin="0,5" />
<ui:TextBox Text="{Binding Patronymic}" PlaceholderText="Отчество" Margin="0,5" />
<DatePicker SelectedDate="{Binding BirthDate}" Margin="0,5" />
<Separator Margin="0,10" />
<!-- Контакты -->
<ui:TextBox Text="{Binding Phone}" PlaceholderText="Телефон (+7...)" Margin="0,5" />
<ui:TextBox Text="{Binding Email}" PlaceholderText="E-mail" Margin="0,5" />
<Separator Margin="0,10" />
<!-- Паспортные данные -->
<Grid Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ui:TextBox Text="{Binding PassportSeries}" PlaceholderText="Серия" Margin="0,0,5,0" MaxLength="4" />
<ui:TextBox Grid.Column="1" Text="{Binding PassportNumber}" PlaceholderText="Номер" MaxLength="6" />
</Grid>
<Separator Margin="0,10" />
<!-- Страхование -->
<ui:TextBox Text="{Binding InsuranceNumber}" PlaceholderText="Номер полиса" Margin="0,5" />
<TextBlock Text="Тип полиса" Margin="0,5,0,0" FontSize="12" Foreground="Gray" />
<ComboBox ItemsSource="{Binding PolicyTypes}"
SelectedItem="{Binding SelectedPolicyType}"
DisplayMemberPath="TypeName" Margin="0,5" />
<TextBlock Text="Страховая компания" Margin="0,5,0,0" FontSize="12" Foreground="Gray" />
<ComboBox ItemsSource="{Binding Companies}"
SelectedItem="{Binding SelectedCompany}"
DisplayMemberPath="CompanyName" Margin="0,5" />
</StackPanel>
</ScrollViewer>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0">
<ui:Button Content="Отмена"
Appearance="Secondary"
Command="{Binding CancelCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Width="100" Margin="0,0,10,0" />
<ui:Button Content="Сохранить"
Appearance="Primary"
Command="{Binding SaveCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Width="120" />
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,29 @@
using Labaratory.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Labaratory.Views
{
/// <summary>
/// Логика взаимодействия для AddPatientWindow.xaml
/// </summary>
public partial class AddPatientWindow : Window
{
public AddPatientWindow()
{
InitializeComponent();
DataContext = new AddPatientViewModel();
}
}
}

View File

@@ -12,7 +12,19 @@
<Grid>
<TabControl>
<TabItem Header="Orders" Background="Black">
<StackPanel>
<TextBox
Text="{Binding FilterLogin, UpdateSourceTrigger = PropertyChanged}"
Tag="Поиск по логину..." Margin="5"/>
<DataGrid ItemsSource="{Binding History}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Время" Binding="{Binding AttemptTime, StringFormat='dd.MM.yyyy HH:mm:ss'}" Width="*"/>
<DataGridTextColumn Header="Логин" Binding="{Binding Login}" Width="*"/>
<DataGridCheckBoxColumn Header="Успешно" Binding="{Binding IsSuccess}" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</TabItem>
<TabItem Header="Orders" Background="Black">

View File

@@ -1,4 +1,6 @@
using System;
using Labaratory.Models;
using Labaratory.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

View File

@@ -1,36 +1,148 @@
<Window x:Class="Labaratory.Views.Laborant"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:Labaratory.Views"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
Title="Laborant" Height="450" Width="800"
xmlns:services="clr-namespace:Labaratory.Services"
Title="Рабочее место лаборанта" Height="700" Width="900"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}">
<Window.Resources>
<services:StringToImageConverter x:Key="StringToImageConverter" />
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Orders" Background="Black">
<StackPanel Margin="20">
<ui:TextBlock Text="Введите код пробирки:" Margin="0,0,0,5"/>
<TabControl Margin="0,10,0,0">
<!-- ВКЛАДКА 1: ОФОРМЛЕНИЕ -->
<TabItem Header="Новый заказ">
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.5*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBox
Text="{Binding BarcodeInput, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="{Binding SuggestedNumber}">
<ui:TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding ProcessOrderCommand}"/>
</ui:TextBox.InputBindings>
</ui:TextBox>
<StackPanel Grid.Column="0" Margin="0,0,15,0">
<!-- Блок пациента -->
<ui:Card Margin="0,0,0,10">
<StackPanel Margin="5">
<TextBlock Text="Поиск пациента" FontWeight="Bold" Margin="0,0,0,5"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ui:TextBox x:Name="PatientNameInput" PlaceholderText="Введите фамилию..." />
<ui:Button Grid.Column="1" Content="Найти/Создать"
Command="{Binding SearchPatientCommand}"
CommandParameter="{Binding Text, ElementName=PatientNameInput}"
Margin="5,0,0,0" />
</Grid>
<ui:Button Content="Сформировать заказ"
Command="{Binding ProcessOrderCommand}"
Margin="0,10,0,0"/>
</StackPanel>
<!-- Детальные данные пациента после выбора -->
<StackPanel Margin="0,10,0,0">
<TextBlock>
<Run Text="Пациент: " Foreground="Gray"/>
<Run Text="{Binding SelectedPatient.Surname}" FontWeight="Bold"/>
<Run Text="{Binding SelectedPatient.FirstName}"/>
<Run Text="{Binding SelectedPatient.Patronymic}"/>
</TextBlock>
<TextBlock Margin="0,3,0,0">
<Run Text="Полис: " Foreground="Gray"/>
<Run Text="{Binding SelectedPatient.InsuranceNumber}"/>
</TextBlock>
</StackPanel>
</StackPanel>
</ui:Card>
<!-- Блок услуг -->
<ui:Card>
<StackPanel>
<TextBlock Text="Выбор услуг" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,10" />
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox x:Name="ServicesCombo"
ItemsSource="{Binding AllServices}"
DisplayMemberPath="ServiceName" />
<ui:Button Grid.Column="1" Content="Добавить" Margin="5,0,0,0"
Command="{Binding AddServiceCommand}"
CommandParameter="{Binding SelectedItem, ElementName=ServicesCombo}" />
</Grid>
<DataGrid ItemsSource="{Binding SelectedServices}"
AutoGenerateColumns="False" Height="200"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Услуга" Binding="{Binding ServiceName}" Width="*" />
<DataGridTextColumn Header="Цена" Binding="{Binding Price, StringFormat='{}{0:N2} р.'}" Width="100" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</ui:Card>
</StackPanel>
<!-- Правая часть: Итог -->
<StackPanel Grid.Column="1">
<ui:Card>
<StackPanel>
<TextBlock Text="Оформление" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,10" />
<ui:TextBlock Text="Код пробирки:" Margin="0,5" />
<ui:TextBox Text="{Binding BarcodeInput, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="{Binding SuggestedNumber}" />
<Separator Margin="0,15" />
<TextBlock Text="Итого к оплате:" FontSize="14" Foreground="Gray" />
<TextBlock Text="{Binding TotalCost, StringFormat='{}{0:N2} руб.'}"
FontSize="28" FontWeight="Bold" Foreground="{ui:ThemeResource SystemAccentColorPrimaryBrush}" />
<ui:Button Content="Завершить и печатать PDF" Appearance="Primary" Height="50" Margin="0,20,0,0"
Command="{Binding ProcessOrderCommand}" HorizontalAlignment="Stretch" />
</StackPanel>
</ui:Card>
</StackPanel>
</Grid>
</TabItem>
<TabItem Header="Orders" Background="Black">
<!-- ВКЛАДКА 2: ИСТОРИЯ ЗАКАЗОВ -->
<TabItem Header="Список заказов">
<Grid Margin="10">
<DataGrid ItemsSource="{Binding AllOrders}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID_Order}" Width="50"/>
<DataGridTextColumn Header="Дата" Binding="{Binding OrderDate, StringFormat='dd.MM.yyyy HH:mm'}" Width="130"/>
<DataGridTemplateColumn Header="Пациент" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Patient.Surname}"/>
<Run Text="{Binding Patient.FirstName}"/>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Штрих-код" Binding="{Binding Barcode}" Width="150"/>
<DataGridTextColumn Header="Статус" Binding="{Binding OrderStatus.StatusName}" Width="120"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>
<TabItem Header="Профиль">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<ui:Card Padding="30">
<StackPanel>
<Ellipse Width="150" Height="150" Stroke="{ui:ThemeResource SystemAccentColorPrimaryBrush}" StrokeThickness="2">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding CurrentUser.Photo, Converter={StaticResource StringToImageConverter}}" Stretch="UniformToFill"/>
</Ellipse.Fill>
</Ellipse>
<TextBlock Text="{Binding CurrentUser.FirstName}" FontSize="20" HorizontalAlignment="Center" Margin="0,15,0,0"/>
<TextBlock Text="{Binding CurrentUser.LastName}" FontSize="24" HorizontalAlignment="Center" FontWeight="Bold"/>
<TextBlock Text="{Binding CurrentUser.Role.Name}" Foreground="Gray" HorizontalAlignment="Center" Margin="0,5,0,0"/>
</StackPanel>
</ui:Card>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
</Window>

View File

@@ -1,4 +1,5 @@
using System;
using Labaratory.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -22,7 +23,6 @@ namespace Labaratory.Views
public Laborant()
{
InitializeComponent();
DataContext = new Laborant();
}
}
}

View File

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle.Cryptography" version="2.6.2" targetFramework="net472" />
<package id="EasyCaptcha.Wpf" version="0.9.0.3" targetFramework="net472" />
<package id="EntityFramework" version="6.5.1" targetFramework="net472" />
<package id="EntityFramework.ru" version="6.2.0" targetFramework="net472" />
<package id="iTextSharp" version="5.5.13.5" targetFramework="net472" />
<package id="System.Buffers" version="4.6.1" targetFramework="net472" />
<package id="System.Memory" version="4.6.3" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.6.1" targetFramework="net472" />