From 0b457af6f7c03e712c6afeda5a42808287d5970e Mon Sep 17 00:00:00 2001 From: ultrageese Date: Sun, 7 Jun 2026 15:07:07 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=BC=D0=B8=D1=82=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=BC=D0=B5=D1=80=20=D0=BA=D0=B0=D0=BA=D0=BE=D0=B9-?= =?UTF-8?q?=D1=82=D0=BE.=20=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=87=D1=82=D0=BE-=D1=82=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 117 +++++++++++++++++++++++---------------- code/src/database.rs | 41 ++++++++------ code/src/material_tab.rs | 16 +++++- code/src/models.rs | 6 ++ code/src/recipe_tab.rs | 17 +++++- code/src/worker_tab.rs | 60 ++++++++++++++------ 6 files changed, 173 insertions(+), 84 deletions(-) diff --git a/code/src/app.rs b/code/src/app.rs index 227de0b..fc1f2c1 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, ops::Deref, str::FromStr, sync::Arc}; +use std::{collections::HashMap, default::Default, ops::Deref, str::FromStr, sync::Arc}; use crate::{ database::DBOperator, @@ -8,7 +8,7 @@ use crate::{ ModalWinState, Position, Worker, }, tab::*, - worker_tab::*, + worker_tab::{self, *}, }; use egui::{TextBuffer, Vec2, mutex::RwLock}; use egui_dock::{DockArea, Style, TabViewer}; @@ -22,11 +22,12 @@ pub struct App<'a> { pub main_viewer: MainTabViewer, pub db_oper: DBOperator, pub rt: tokio::runtime::Runtime, + pub is_admin: bool, } impl Default for App<'_> { fn default() -> Self { - let tree = egui_dock::DockState::new(vec![ + let mut tree = egui_dock::DockState::new(vec![ Tab { tab_type: TabTypes::Equipment, title: "Оборудование".to_owned(), @@ -69,6 +70,7 @@ impl Default for App<'_> { }, db_oper: rt.block_on(DBOperator::new()), rt, + is_admin: false, } } } @@ -104,28 +106,31 @@ impl eframe::App for App<'_> { || ui.input(|i| i.key_pressed(egui::Key::Enter)) { let uname = self.login_modal_state.data.get("login").unwrap().clone(); + + self.login_modal_state.fail = false; + let mut hashed_pass = Sha256::new(); + hashed_pass.update(self.login_modal_state.data.get("password").unwrap()); + let pass_hash = hex::encode(hashed_pass.finalize()); if self.rt.block_on(async { - self.db_oper.check_username(uname.clone()).await.unwrap() + self.db_oper + .check_password(uname.clone(), pass_hash) + .await + .unwrap() }) { self.login_modal_state.fail = false; - let mut hashed_pass = Sha256::new(); - hashed_pass - .update(self.login_modal_state.data.get("password").unwrap()); - let pass_hash = hex::encode(hashed_pass.finalize()); + self.login_modal_state.status = crate::models::LoginStatus::Finished; + self.login_modal_state.is_open = false; if self.rt.block_on(async { - self.db_oper.check_password(uname, pass_hash).await.unwrap() + self.db_oper.check_admin(uname.clone()).await.unwrap() }) { - self.login_modal_state.fail = false; - self.login_modal_state.status = - crate::models::LoginStatus::Finished; - self.login_modal_state.is_open = false; + self.main_viewer.is_admin = true } else { - self.login_modal_state.fail = true; - self.login_modal_state.fail_message = "Неверный пароль".to_string(); + self.main_viewer.is_admin = false; } } else { self.login_modal_state.fail = true; - self.login_modal_state.fail_message = "Неверный логин".to_string(); + self.login_modal_state.fail_message = + "Неверные логин или пароль".to_string(); } } }); @@ -158,6 +163,7 @@ struct MainTabViewer { equipment_modal_state: ModalWinState, is_dark_theme: bool, interface_scale_ratio: f32, + is_admin: bool, } impl Default for MainTabViewer { fn default() -> Self { @@ -211,29 +217,40 @@ impl Default for MainTabViewer { ]), status: ModalStatus::Add, }, + is_admin: false, } } } impl MainTabViewer { + fn new(is_admin: bool) -> Self { + Self { + is_admin, + worker_tabs: WorkerTabViewer::new(is_admin), + material_tabs: MaterialTabViewer::new(is_admin), + ..Default::default() + } + } fn show_equipment(&mut self, ui: &mut egui::Ui) { - ui.horizontal(|ui| { - if ui.button("Добавить").clicked() { - self.equipment_modal_state.is_open = true; - self.equipment_modal_state.status = ModalStatus::Add; - self.equipment_modal_state - .data - .insert("id".into(), "0".into()); - self.equipment_modal_state - .data - .insert("name".into(), "".into()); - self.equipment_modal_state - .data - .insert("inv_numver".into(), "".into()); - self.equipment_modal_state - .data - .insert("worker_id".into(), "0".into()); - } - }); + if self.is_admin { + ui.horizontal(|ui| { + if ui.button("Добавить").clicked() { + self.equipment_modal_state.is_open = true; + self.equipment_modal_state.status = ModalStatus::Add; + self.equipment_modal_state + .data + .insert("id".into(), "0".into()); + self.equipment_modal_state + .data + .insert("name".into(), "".into()); + self.equipment_modal_state + .data + .insert("inv_numver".into(), "".into()); + self.equipment_modal_state + .data + .insert("worker_id".into(), "0".into()); + } + }); + } let mut table = TableBuilder::new(ui) .striped(true) .resizable(false) @@ -275,21 +292,23 @@ impl MainTabViewer { ui.label(eq.maintenance_date.date_naive().to_string()); }); row.col(|ui| { - if ui.button("Удалить").clicked() { - self.equipment_modal_state.is_open = true; - self.equipment_modal_state.status = ModalStatus::Remove; - self.equipment_modal_state - .data - .insert("id".into(), eq.id.to_string()); - self.equipment_modal_state - .data - .insert("name".into(), eq.name.clone()); - self.equipment_modal_state - .data - .insert("inv_numver".into(), eq.inv_number.clone()); - self.equipment_modal_state - .data - .insert("worker_id".into(), eq.worker.id.to_string()); + if self.is_admin { + if ui.button("Удалить").clicked() { + self.equipment_modal_state.is_open = true; + self.equipment_modal_state.status = ModalStatus::Remove; + self.equipment_modal_state + .data + .insert("id".into(), eq.id.to_string()); + self.equipment_modal_state + .data + .insert("name".into(), eq.name.clone()); + self.equipment_modal_state + .data + .insert("inv_numver".into(), eq.inv_number.clone()); + self.equipment_modal_state + .data + .insert("worker_id".into(), eq.worker.id.to_string()); + } } }); if row.response().double_clicked() { diff --git a/code/src/database.rs b/code/src/database.rs index 81798e1..9c313ba 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -1,3 +1,4 @@ +use sqlx::Row; use sqlx::mysql::MySqlPool; use sqlx::mysql::MySqlPoolOptions; @@ -283,22 +284,6 @@ impl DBOperator { Err(_) => Ok(false), } } - pub async fn check_username(&self, username: String) -> Result { - let ans = sqlx::query("SELECT * FROM Brewery.profile WHERE login=?") - .bind(username) - .fetch_all(&self.pool) - .await; - match ans { - Ok(n) => { - if n.len() > 0 { - return Ok(true); - } else { - return Ok(false); - } - } - Err(_) => Ok(false), - } - } pub async fn check_password( &self, username: String, @@ -320,6 +305,30 @@ impl DBOperator { Err(_) => Ok(false), } } + pub async fn check_admin(&self, username: String) -> Result { + let ans: bool = sqlx::query_scalar( + r#"SELECT + position.is_admin, + profile.worker_id, + worker.id, + profile.login, + position.id + FROM + Brewery.profile + JOIN + Brewery.worker + JOIN + Brewery.position + ON profile.worker_id = worker.id + AND profile.login=? + AND worker.position_id =position.id"#, + ) + .bind(username) + .fetch_one(&self.pool) + .await + .unwrap(); + Ok(ans) + } } pub async fn estabilish_connection() -> Result<(), sqlx::Error> { diff --git a/code/src/material_tab.rs b/code/src/material_tab.rs index 0677572..f2fdd52 100644 --- a/code/src/material_tab.rs +++ b/code/src/material_tab.rs @@ -1,9 +1,13 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, default::Default, sync::Arc}; use egui::mutex::RwLock; use egui_extras::{Column, TableBuilder}; -use crate::{database::DBOperator, models::{Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState}, tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes}}; +use crate::{ + database::DBOperator, + models::{Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState}, + tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes}, +}; pub struct MaterialTabViewer { db_oper: DBOperator, @@ -14,8 +18,15 @@ pub struct MaterialTabViewer { mat_cats: Arc>>, mats: Arc>>, + is_admin: bool, } impl MaterialTabViewer { + pub fn new(is_admin: bool) -> Self { + Self { + is_admin, + ..Default::default() + } + } fn update_material_category(&mut self) { self.mat_cats = Arc::new(RwLock::new( self.rt @@ -576,6 +587,7 @@ impl Default for MaterialTabViewer { }, mat_cats, mats, + is_admin: false, } } } diff --git a/code/src/models.rs b/code/src/models.rs index 816e178..3e05621 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -112,6 +112,12 @@ pub struct Product<'a> { price_per_unit: rust_decimal::Decimal, } #[derive(Default)] +pub struct User{ + login: String, + is_admin: bool, + worker: Worker, +} +#[derive(Default)] pub struct ModalWinState { pub is_open: bool, pub can_finish: bool, diff --git a/code/src/recipe_tab.rs b/code/src/recipe_tab.rs index 56cc59e..286132b 100644 --- a/code/src/recipe_tab.rs +++ b/code/src/recipe_tab.rs @@ -1,8 +1,17 @@ use crate::tab::{Tab, TabTypes}; +use std::default::Default; -struct RecipeTabViewer {} +struct RecipeTabViewer { + is_admin: bool, +} impl RecipeTabViewer { + fn new(is_admin: bool) -> Self { + Self { + is_admin, + ..Default::default() + } + } fn show_recipe_list(&mut self, ui: &mut egui::Ui) {} fn show_recipe_detail(&mut self, ui: &mut egui::Ui) {} } @@ -27,3 +36,9 @@ impl egui_dock::TabViewer for RecipeTabViewer { } } } + +impl Default for RecipeTabViewer { + fn default() -> Self { + Self { is_admin: false } + } +} diff --git a/code/src/worker_tab.rs b/code/src/worker_tab.rs index 7fa63d6..03e5fdc 100644 --- a/code/src/worker_tab.rs +++ b/code/src/worker_tab.rs @@ -1,16 +1,17 @@ -use std::collections::HashMap; -use std::str::FromStr; -use std::sync::{Arc}; use bigdecimal::BigDecimal; use egui::mutex::RwLock; use egui_extras::{Column, TableBuilder}; +use std::collections::HashMap; +use std::default::Default; +use std::str::FromStr; +use std::sync::Arc; -use crate::models::{ModalStatus, ModalWinState, Position, Worker}; use crate::database::*; +use crate::models::{ModalStatus, ModalWinState, Position, Worker}; use crate::tab::*; pub struct WorkerTabViewer { db_oper: DBOperator, - workers: Arc>>>, + workers: Arc>>, positions: Arc>>, show_worker_add_modal: bool, show_worker_edit_modal: bool, @@ -33,15 +34,23 @@ pub struct WorkerTabViewer { rt: tokio::runtime::Runtime, show_position_delete_modal: bool, delete_position: Position, + process_worker_state: ModalWinState, process_position_state: ModalWinState, + is_admin: bool, } impl WorkerTabViewer { + pub fn new(is_admin: bool) -> Self { + Self { + is_admin, + ..Default::default() + } + } fn update_workers(&mut self) { - self.workers = Arc::new(RwLock::new(Option::Some( + self.workers = Arc::new(RwLock::new( self.rt .block_on(async { self.db_oper.get_workers().await.unwrap() }), - ))); + )); } fn update_positions(&mut self) { self.positions = Arc::new(RwLock::new( @@ -98,7 +107,7 @@ impl WorkerTabViewer { .selected_text(format!("{}", self.add_worker_position.name)) .show_ui(ui, |ui| { self.rt.block_on(async { - for pos in self.db_oper.get_position().await.unwrap().iter() { + for pos in self.positions.read().clone().iter() { ui.selectable_value( &mut self.add_worker_position, pos.clone(), @@ -278,7 +287,7 @@ impl WorkerTabViewer { .body(|mut body| { body.ui_mut().style_mut().interaction.selectable_labels = false; - for wk in self.workers.read().clone().unwrap().iter() { + for wk in self.workers.read().clone().iter() { body.row(25.0, |mut row| { row.col(|ui| { ui.label(&wk.full_name); @@ -420,7 +429,6 @@ impl WorkerTabViewer { .workers .read() .clone() - .unwrap() .iter() .find(|wrkr| wrkr.position.id == self.delete_position.id) .iter() @@ -493,9 +501,7 @@ impl egui_dock::TabViewer for WorkerTabViewer { } fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { match &tab.tab_type { - TabTypes::WorkerList => { - self.show_worker(ui) - }, + TabTypes::WorkerList => self.show_worker(ui), TabTypes::WorkerPosition => self.show_position(ui), _ => { ui.label("Nope"); @@ -519,6 +525,9 @@ impl Default for WorkerTabViewer { let positions = Arc::new(RwLock::new( rt.block_on(async { db_oper.get_position().await.unwrap() }), )); + let workers = Arc::new(RwLock::new( + rt.block_on(async { db_oper.get_workers().await.unwrap() }), + )); let mut pos_map: HashMap = HashMap::new(); pos_map.extend(|| -> Vec<(String, String)> { let pos = positions.read()[0].clone(); @@ -528,6 +537,20 @@ impl Default for WorkerTabViewer { ("wage".to_string(), pos.wage.to_string()), ] }()); + let mut worker_map: HashMap = HashMap::new(); + worker_map.extend(|| -> Vec<(String, String)> { + let worker = workers.read()[0].clone(); + vec![ + ("id".to_string(), worker.id.to_string()), + ("full_name".to_string(), worker.full_name), + ("position_id".to_string(), worker.position.id.to_string()), + ( + "hire_date".to_string(), + worker.hire_date.date_naive().format("%d-%m-%Y").to_string(), + ), + ("is_fired".to_string(), worker.is_fired.to_string()), + ] + }()); Self { process_position_state: ModalWinState { is_open: false, @@ -535,9 +558,13 @@ impl Default for WorkerTabViewer { data: pos_map, status: ModalStatus::Add, }, - workers: Arc::new(RwLock::new(Option::Some( - rt.block_on(async { db_oper.get_workers().await.unwrap() }), - ))), + process_worker_state: ModalWinState { + is_open: false, + can_finish: false, + data: worker_map, + status: ModalStatus::Add, + }, + workers, positions: positions, show_worker_add_modal: false, show_worker_edit_modal: false, @@ -561,6 +588,7 @@ impl Default for WorkerTabViewer { db_oper, rt, + is_admin: false, } } }