Загрузка данных


Да. Ниже — такой же компактный гайд, но уже под задание с картинки.

Сделаем по приоритету:
	1.	SQL-скрипт БД в 3НФ
	2.	Окно авторизации
	3.	Основное окно:
	•	показывает роль пользователя
	•	показывает пациентов
	•	показывает результаты исследований
	•	позволяет вносить новые данные о проведённом исследовании

⸻

Что будет

Приложение для учета лабораторных анализов:
	•	авторизация лаборанта
	•	просмотр списка пациентов
	•	просмотр внесенных исследований
	•	добавление результата исследования
	•	отображение имени пользователя и его роли

⸻

Структура БД

Таблицы:
	•	Roles
	•	Users
	•	Patients
	•	AnalysisTypes
	•	LabTests

Это 3НФ, потому что:
	•	роли вынесены отдельно
	•	типы анализов вынесены отдельно
	•	пользователи не дублируют названия ролей
	•	записи исследований хранят только ссылки на пациента, тип анализа и лаборанта

⸻

ERD

Связи такие:
	•	Roles (1) -> (M) Users
	•	Users (1) -> (M) LabTests
	•	Patients (1) -> (M) LabTests
	•	AnalysisTypes (1) -> (M) LabTests

⸻

Файлы проекта
	•	App.xaml
	•	LoginWindow.xaml
	•	LoginWindow.xaml.cs
	•	MainWindow.xaml
	•	MainWindow.xaml.cs

Пакет:
	•	MySqlConnector

⸻

1. Создай проект

В Visual Studio:
	•	Create a new project
	•	WPF App (.NET)
	•	имя: LabApp

⸻

2. Установи пакет

Через NuGet:

MySqlConnector


⸻

3. Сначала база данных

SQL-скрипт создания БД

Создай БД, например в MySQL Workbench, и выполни:

drop database if exists lab_accounting_db;
create database lab_accounting_db character set utf8mb4 collate utf8mb4_unicode_ci;
use lab_accounting_db;

create table Roles
(
    RoleID int primary key auto_increment,
    RoleName varchar(50) not null unique
);

create table Users
(
    UserID int primary key auto_increment,
    Login varchar(50) not null unique,
    PasswordHash varchar(100) not null,
    FullName varchar(100) not null,
    RoleID int not null,
    foreign key (RoleID) references Roles(RoleID)
);

create table Patients
(
    PatientID int primary key auto_increment,
    LastName varchar(50) not null,
    FirstName varchar(50) not null,
    MiddleName varchar(50) null,
    BirthDate date not null,
    Gender enum('М','Ж') not null,
    Phone varchar(20) null
);

create table AnalysisTypes
(
    AnalysisTypeID int primary key auto_increment,
    AnalysisName varchar(100) not null unique,
    Unit varchar(20) not null,
    ReferenceRange varchar(50) not null
);

create table LabTests
(
    LabTestID int primary key auto_increment,
    PatientID int not null,
    AnalysisTypeID int not null,
    UserID int not null,
    TestDate datetime not null default current_timestamp,
    ResultValue decimal(10,2) not null,
    CommentText varchar(255) null,
    foreign key (PatientID) references Patients(PatientID),
    foreign key (AnalysisTypeID) references AnalysisTypes(AnalysisTypeID),
    foreign key (UserID) references Users(UserID)
);


⸻

Тестовые данные

Не менее 3 тестовых данных есть. Здесь даже больше.

use lab_accounting_db;

insert into Roles (RoleName) values
('Администратор'),
('Лаборант'),
('Врач');

insert into Users (Login, PasswordHash, FullName, RoleID) values
('admin', '1234', 'Иванов Иван Сергеевич', 1),
('lab1', '1234', 'Петрова Анна Викторовна', 2),
('doctor1', '1234', 'Сидоров Алексей Павлович', 3);

insert into Patients (LastName, FirstName, MiddleName, BirthDate, Gender, Phone) values
('Смирнов', 'Олег', 'Игоревич', '1990-04-12', 'М', '+79990000001'),
('Кузнецова', 'Мария', 'Андреевна', '1985-11-03', 'Ж', '+79990000002'),
('Васильев', 'Денис', 'Олегович', '2001-07-21', 'М', '+79990000003');

insert into AnalysisTypes (AnalysisName, Unit, ReferenceRange) values
('Гемоглобин', 'г/л', '120-160'),
('Глюкоза', 'ммоль/л', '3.9-5.5'),
('Лейкоциты', '10^9/л', '4.0-9.0');

insert into LabTests (PatientID, AnalysisTypeID, UserID, TestDate, ResultValue, CommentText) values
(1, 1, 2, '2025-09-01 09:30:00', 145.00, 'Норма'),
(2, 2, 2, '2025-09-01 10:00:00', 6.10, 'Незначительное повышение'),
(3, 3, 2, '2025-09-01 10:30:00', 7.20, 'Норма');


⸻

4. Логика окон

Будет 2 окна:
	•	LoginWindow — авторизация
	•	MainWindow — основная работа

После успешного входа:
	•	открывается основное окно
	•	показывается ФИО
	•	показывается роль
	•	загружаются пациенты и исследования

⸻

5. App.xaml

Замени StartupUri, чтобы сначала открывалось окно логина:

<Application x:Class="LabApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
    </Application.Resources>
</Application>


⸻

6. Создай окно LoginWindow

Через:
	•	Add
	•	New Item
	•	Window (WPF)

Имя:

LoginWindow.xaml


⸻

7. LoginWindow.xaml

Замени весь файл:

<Window x:Class="LabApp.LoginWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Авторизация" Height="280" Width="420" WindowStartupLocation="CenterScreen">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock Text="Логин"/>
        <TextBox x:Name="tbLogin" Margin="0,25,0,10" Height="30"/>

        <TextBlock Grid.Row="1" Text="Пароль"/>
        <PasswordBox x:Name="pbPassword" Grid.Row="1" Margin="0,25,0,10" Height="30"/>

        <Button Grid.Row="2" Content="Войти" Height="35" Margin="0,10,0,0" Click="LoginClick"/>
        <TextBlock x:Name="tbMsg" Grid.Row="3" Margin="0,15,0,0"/>
    </Grid>
</Window>


⸻

8. LoginWindow.xaml.cs

Замени весь файл:

using System;
using System.Data;
using System.Windows;
using MySqlConnector;

namespace LabApp
{
    public partial class LoginWindow : Window
    {
        string cs = "Server=localhost;Port=3306;Database=lab_accounting_db;Uid=root;Pwd=12345;";

        public LoginWindow()
        {
            InitializeComponent();
        }

        DataTable Q(string sql, params MySqlParameter[] p)
        {
            using var c = new MySqlConnection(cs);
            using var m = new MySqlCommand(sql, c);
            if (p.Length > 0) m.Parameters.AddRange(p);
            using var a = new MySqlDataAdapter(m);
            var t = new DataTable();
            a.Fill(t);
            return t;
        }

        void LoginClick(object s, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(tbLogin.Text) || string.IsNullOrWhiteSpace(pbPassword.Password))
            {
                tbMsg.Text = "Введите логин и пароль";
                return;
            }

            try
            {
                var t = Q(@"
select u.UserID,u.FullName,r.RoleName
from Users u
join Roles r on r.RoleID=u.RoleID
where u.Login=@l and u.PasswordHash=@p",
                    new("@l", tbLogin.Text.Trim()),
                    new("@p", pbPassword.Password.Trim()));

                if (t.Rows.Count == 0)
                {
                    tbMsg.Text = "Неверный логин или пароль";
                    return;
                }

                var row = t.Rows[0];
                int userId = Convert.ToInt32(row["UserID"]);
                string fullName = row["FullName"].ToString();
                string roleName = row["RoleName"].ToString();

                var w = new MainWindow(userId, fullName, roleName);
                w.Show();
                Close();
            }
            catch (Exception ex)
            {
                tbMsg.Text = ex.Message;
            }
        }
    }
}


⸻

9. Чтобы приложение стартовало с логина

Открой App.xaml.cs и сделай так:

using System.Windows;

namespace LabApp
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            new LoginWindow().Show();
        }
    }
}


⸻

10. MainWindow.xaml

Замени весь файл:

<Window x:Class="LabApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Учет лабораторных анализов" Height="680" Width="1150" WindowStartupLocation="CenterScreen">
    <Grid Margin="15">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Border BorderThickness="1" Padding="10" Margin="0,0,0,10">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Польз