From be927a213d975cdd0011bfc1deddf051c410d1f4 Mon Sep 17 00:00:00 2001 From: ultrageese Date: Wed, 27 May 2026 19:59:30 +1000 Subject: [PATCH] =?UTF-8?q?=D0=A7=D1=83=D1=82=D1=8C-=D1=87=D1=83=D1=82?= =?UTF-8?q?=D1=8C=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB,=20=D0=BC=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=D0=B5=20=D0=B5=D1=89=D1=91=20=D0=B2=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B4=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 224 ++++++++++++++++++++++++++++++++++--------- code/src/database.rs | 27 ++++++ code/src/models.rs | 9 +- database.sql | 23 ++++- 4 files changed, 230 insertions(+), 53 deletions(-) diff --git a/code/src/app.rs b/code/src/app.rs index 88657a1..c7fc346 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use chrono::NaiveDate; use egui::mutex::RwLock; use egui_dock::{DockArea, Style, TabViewer}; -use sqlx::{Connection, MySqlConnection, MySqlPool}; +use rust_decimal::prelude::Zero; +use sqlx::{Connection, MySqlConnection, MySqlPool, types::BigDecimal}; use crate::{database::DBOperator, models::{self, Equipment, Position, Salary, Worker}}; static TABS_CAN_BE_WINDOWS: bool = false; @@ -91,6 +92,7 @@ impl eframe::App for App{ }else{ ctx.set_visuals(egui::Visuals::light()); } + ctx.set_zoom_factor(self.main_viewer.interface_scale_ratio); } } @@ -103,6 +105,7 @@ struct MainTabViewer { worker_tree: egui_dock::DockState, rt: tokio::runtime::Runtime, is_dark_theme: bool, + interface_scale_ratio: f32, } impl Default for MainTabViewer{ @@ -129,7 +132,8 @@ impl Default for MainTabViewer{ } ]), rt, - is_dark_theme: true + is_dark_theme: true, + interface_scale_ratio: 1.2, } } } @@ -200,9 +204,14 @@ impl MainTabViewer{ } fn show_settings(&mut self, ui: &mut egui::Ui){ - ui.horizontal(|ui|{ - ui.checkbox(&mut self.is_dark_theme, "Тёмная тема"); - }); + ui.checkbox(&mut self.is_dark_theme, "Тёмная тема"); + + + ui.add(egui::Slider::new(&mut self.interface_scale_ratio,1.0..=2.0).text("Масштаб интерфейса")); + + if ui.button("Сбросить Масштаб интерфейса").clicked(){ + self.interface_scale_ratio = 1.2; + } } } @@ -249,31 +258,52 @@ struct WorkerTabViewer{ db_oper: DBOperator, workers: Arc>>>, positions: Arc>>>, - show_add_modal: bool, + show_worker_add_modal: bool, + show_worker_edit_modal: bool, + show_position_add_modal: bool, + fire_worker_id: String, add_worker_name: String, - selected_position_id: i32, add_worker_hire_date: String, - can_add: bool, - rt: tokio::runtime::Runtime + add_worker_position: Position, + can_add_worker: bool, + can_edit_worker: bool, + add_position_name: String, + add_position_wage: String, + + edit_worker_id: i32, + edit_worker_name: String, + edit_worker_hire_date: String, + edit_worker_is_fired: bool, + edit_worker_position: Position, + + rt: tokio::runtime::Runtime, + } impl WorkerTabViewer{ + fn update_workers(&mut self){ + self.workers = Arc::new(RwLock::new(Option::Some(self.rt.block_on(async{self.db_oper.get_workers().await.unwrap()})))); + } + fn show_worker(&mut self, ui: &mut egui::Ui){ ui.horizontal(|ui|{ if ui.button("Добавить").clicked() { - self.show_add_modal = true; + self.show_worker_add_modal = true; self.add_worker_name = String::new(); - self.selected_position_id = 1; + self.add_worker_position = Position::default(); }; - if ui.button("Уволить").clicked() { - + if ui.button("Редактировать").clicked() { + self.show_worker_edit_modal = true; + } + if ui.button("Обновить").clicked(){ + self.update_workers(); } }); - if self.show_add_modal{ - egui::Modal::new("add".into()).show(ui.ctx(), |ui|{ + if self.show_worker_add_modal{ + egui::Modal::new("add_worker".into()).show(ui.ctx(), |ui|{ if ui.button("Закрыть").clicked(){ - self.show_add_modal = false; + self.show_worker_add_modal = false; } ui.horizontal(|ui|{ ui.vertical(|ui|{ @@ -286,13 +316,13 @@ impl WorkerTabViewer{ ui.add( egui::TextEdit::singleline(&mut self.add_worker_hire_date).hint_text("Напр: 12-02-2010")); egui::ComboBox::from_label("Выбрать!") - .selected_text(format!("{}",self.selected_position)) + .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(){ - ui.selectable_value(&mut self.selected_position, pos.id, pos.name); + ui.selectable_value(&mut self.add_worker_position, pos.clone(), &pos.name); } - });p + }); }); }); }); @@ -300,38 +330,96 @@ impl WorkerTabViewer{ if(chrono::NaiveDate::parse_from_str(&self.add_worker_hire_date, "%d-%m-%Y").is_err()){ ui.label(egui::RichText::new("ДАТА УКАЗАНА НЕВЕРНО").color(egui::Color32::RED)); - self.can_add = false; + self.can_add_worker = false; }else{ - self.can_add = true; + self.can_add_worker = true; } ui.vertical_centered(|ui|{ - let resp = ui.add_enabled(self.can_add, egui::Button::new("Добавить")); + let resp = ui.add_enabled(self.can_add_worker, egui::Button::new("Добавить")); if resp.clicked(){ self.rt.block_on(async{ - let poss = self.db_oper.get_position().await.unwrap(); - + let ndate =chrono::NaiveDate::parse_from_str(&self.add_worker_hire_date, "%d-%m-%Y").unwrap(); self.db_oper.add_worker(Worker { id: 0, full_name: self.add_worker_name.clone(), - hire_date: chrono::DateTime::parse_from_str(&self.add_worker_hire_date, "%d-%m-%Y") - .unwrap() - .into(), - position: (|| -> Position{ - for pos in poss{ - if pos.id.to_string() == self.selected_position{ - return pos - } - }) - }, - is_fired: () - }); - }) - - } - // if ui.button("Добавить").clicked(){ + hire_date: ndate.and_hms_opt(0, 0, 0).unwrap().and_local_timezone(chrono::Local).unwrap(), + position: self.add_worker_position.clone(), + is_fired: false + }).await.ok(); + + self.show_worker_add_modal = false; + }); + self.update_workers(); + } + + }); + + }); + } + if self.show_worker_edit_modal{ + egui::Modal::new("edit_worker".into()).show(ui.ctx(), |ui|{ + if ui.button("Закрыть").clicked(){ + self.show_worker_edit_modal = false; + } + let mut size = ui.spacing().interact_size; + size.x = 200.0; + + egui::Grid::new("edit_worker_grid").show(ui, |ui|{ + ui.label("ID"); + let old = self.edit_worker_id.clone(); + egui::ComboBox::from_id_salt("edit_worker_id") + .selected_text(format!("#{:08}",&self.edit_worker_id)) + .show_ui(ui, |ui|{ + self.rt.block_on(async{ + for worker in self.db_oper.get_workers().await.unwrap().iter(){ + ui.selectable_value(&mut self.edit_worker_id, worker.id, format!("#{:08} | {}", worker.id, worker.full_name)); + } + + }); + }); + if self.edit_worker_id != old{ + println!("Ура перемена"); + self.rt.block_on(async{ + let wrkr = match self.db_oper.get_worker_by_id(self.edit_worker_id).await{ + Ok(worker)=>{ + worker + }, + Err(_)=>{ + Worker::default() + } + }; + self.edit_worker_name = wrkr.full_name; + self.edit_worker_hire_date = wrkr.hire_date.format("%Y-%m-%d").to_string(); + self.edit_worker_position = wrkr.position; + self.edit_worker_is_fired = wrkr.is_fired; + }); + + + } + ui.end_row(); + + ui.label("Имя"); + ui.add_sized(size, |ui: &mut egui::Ui|{ + ui.text_edit_singleline(&mut self.edit_worker_name) + }); + ui.end_row(); + + ui.label("Должность"); + egui::ComboBox::from_id_salt("edit_worker_pos") + .selected_text(&self.edit_worker_position.name) + .show_ui(ui, |ui|{ + self.rt.block_on(async{ + for pos in self.db_oper.get_position().await.unwrap().iter(){ + ui.selectable_value(&mut self.edit_worker_position, pos.clone(), &pos.name); + } + }); + }); + ui.end_row(); + + ui.checkbox(&mut self.edit_worker_is_fired, "Уволен"); + ui.end_row(); - // } }); }); @@ -360,8 +448,13 @@ impl WorkerTabViewer{ }) }); } - } + } fn show_position(&mut self, ui: &mut egui::Ui){ + ui.horizontal(|ui|{ + if ui.button("Добавить").clicked(){ + self.show_position_add_modal = true; + } + }); for eq in self.positions.read().clone().unwrap().iter(){ ui.push_id(&eq.name, |ui|{ egui::CollapsingHeader::new(&eq.name) @@ -373,6 +466,30 @@ impl WorkerTabViewer{ }); }) + }); + } + if self.show_position_add_modal{ + egui::Modal::new("add_position".into()).show(ui.ctx(), |ui|{ + if ui.button("Закрыть").clicked(){ + self.show_position_add_modal = false; + } + let mut size = ui.spacing().interact_size; + size.x = 200.0; + egui::Grid::new("add_pos_grid").show(ui, |ui|{ + ui.label("Название"); + ui.add_sized(size, |ui: &mut egui::Ui|{ + ui.text_edit_singleline(&mut self.add_position_name) + }); + + ui.end_row(); + + ui.label("Оклад"); + ui.text_edit_singleline(&mut self.add_position_wage); + ui.end_row(); + + }); + + }); } } @@ -406,13 +523,26 @@ impl Default for WorkerTabViewer{ let db_oper = rt.block_on(async{DBOperator::new().await}); Self { workers: Arc::new(RwLock::new(Option::Some(rt.block_on(async{db_oper.get_workers().await.unwrap()})))) , positions: Arc::new(RwLock::new(Option::Some(rt.block_on(async{db_oper.get_position().await.unwrap()})))), - show_add_modal: false, + show_worker_add_modal: false, + show_worker_edit_modal: false, + show_position_add_modal: false, + fire_worker_id: String::new(), add_worker_name: String::new(), - selected_position: String::new(), + add_worker_position: Position::default(), add_worker_hire_date: String::new(), - can_add: false, - db_oper. - rt + can_add_worker: false, + can_edit_worker: false, + add_position_name: String::new(), + add_position_wage: String::new(), + + edit_worker_id: 1, + edit_worker_name: String::new(), + edit_worker_hire_date: String::new(), + edit_worker_position: Position::default(), + edit_worker_is_fired: false, + + db_oper, + rt, } } } \ No newline at end of file diff --git a/code/src/database.rs b/code/src/database.rs index 72e5a37..130f824 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -78,7 +78,34 @@ impl DBOperator{ Ok(false) } } + } + pub async fn change_worker_fire_state(&self, worker_id: i32, is_fired: bool) -> Result{ + match(sqlx::query("UPDATE Brewery.worker SET is_fired=? WHERE id=?;") + .bind(if is_fired {1} else {0}) + .bind(worker_id) + .execute(&self.pool) + .await){ + Ok(_) =>{ + Ok(true) + }, + Err(_) =>{ + Ok(false) + } } + } + pub async fn get_worker_by_id(&self, worker_id:i32) -> Result{ + let preret = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker` WHERE id = ?;").bind(worker_id).fetch_all(&self.pool).await?; + let poses = self.get_position().await?; + let ret = Ok(Worker{ + id: preret[0].id, + full_name: preret[0].full_name.clone(), + hire_date: preret[0].hire_date, + is_fired: preret[0].is_fired, + position: poses.iter().find(|&pos| &pos.id == &preret[0].position_id).unwrap().clone(), + + }); + ret + } } diff --git a/code/src/models.rs b/code/src/models.rs index 5e97663..6ce5ee4 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -1,12 +1,17 @@ use sqlx::types::{BigDecimal, chrono::DateTime}; -#[derive(Default, Clone, Hash, sqlx::FromRow)] +#[derive(Clone, Hash, sqlx::FromRow, PartialEq)] pub struct Position{ pub id: i32, pub name: String, pub wage: BigDecimal, } +impl Default for Position{ + fn default() -> Self { + Self { id: 1, name: "".into(), wage: 0.into() } + } +} #[derive(Default, Clone, Hash)] pub struct Worker{ pub id: i32, @@ -15,7 +20,7 @@ pub struct Worker{ pub position: Position, pub is_fired: bool, } -#[derive(sqlx::FromRow)] +#[derive(sqlx::FromRow, sqlx::Decode)] pub struct WorkerRow{ pub id: i32, pub full_name: String, diff --git a/database.sql b/database.sql index 18b441e..96ae966 100644 --- a/database.sql +++ b/database.sql @@ -55,10 +55,11 @@ CREATE TABLE `equipment` ( `inv_number` varchar(20) DEFAULT NULL, `maintenance_date` datetime DEFAULT NULL, `worker_id` int(11) DEFAULT NULL, + `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_worker1` (`worker_id`), CONSTRAINT `fk_worker1` FOREIGN KEY (`worker_id`) REFERENCES `worker` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -68,6 +69,9 @@ CREATE TABLE `equipment` ( SET @OLD_AUTOCOMMIT=@@AUTOCOMMIT, @@AUTOCOMMIT=0; LOCK TABLES `equipment` WRITE; /*!40000 ALTER TABLE `equipment` DISABLE KEYS */; +INSERT INTO `equipment` VALUES +(1,'М-1','1970-01-01 00:00:00',1,'Метла деревяная'), +(2,'М-2','1970-01-01 00:00:00',2,'Метла деревяная'); /*!40000 ALTER TABLE `equipment` ENABLE KEYS */; UNLOCK TABLES; COMMIT; @@ -204,7 +208,7 @@ CREATE TABLE `position` ( `name` varchar(50) DEFAULT NULL, `wage` decimal(10,0) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -214,6 +218,9 @@ CREATE TABLE `position` ( SET @OLD_AUTOCOMMIT=@@AUTOCOMMIT, @@AUTOCOMMIT=0; LOCK TABLES `position` WRITE; /*!40000 ALTER TABLE `position` DISABLE KEYS */; +INSERT INTO `position` VALUES +(1,'Уборщик',20000), +(2,'Кладовщик',35000); /*!40000 ALTER TABLE `position` ENABLE KEYS */; UNLOCK TABLES; COMMIT; @@ -352,10 +359,11 @@ CREATE TABLE `worker` ( `position_id` int(11) NOT NULL, `hire_date` datetime DEFAULT NULL, `is_fired` tinyint(1) DEFAULT NULL, + `full_name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_position` (`position_id`), CONSTRAINT `fk_position` FOREIGN KEY (`position_id`) REFERENCES `position` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -365,6 +373,13 @@ CREATE TABLE `worker` ( SET @OLD_AUTOCOMMIT=@@AUTOCOMMIT, @@AUTOCOMMIT=0; LOCK TABLES `worker` WRITE; /*!40000 ALTER TABLE `worker` DISABLE KEYS */; +INSERT INTO `worker` VALUES +(1,1,'1997-02-24 00:00:00',0,'Степан Иванов'), +(2,1,'2021-06-12 00:00:00',1,'Иван Петров'), +(3,1,'2010-02-11 14:00:00',0,'Pupue!'), +(4,2,'2003-01-26 14:00:00',0,'Никита Булаников'), +(5,2,'2009-01-06 14:00:00',0,'Никитин Олег'), +(6,1,'2009-09-08 13:00:00',0,'Авраамов Моисей'); /*!40000 ALTER TABLE `worker` ENABLE KEYS */; UNLOCK TABLES; COMMIT; @@ -379,4 +394,4 @@ SET AUTOCOMMIT=@OLD_AUTOCOMMIT; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*M!100616 SET NOTE_VERBOSITY=@OLD_NOTE_VERBOSITY */; --- Dump completed on 2026-05-11 20:50:22 +-- Dump completed on 2026-05-27 19:59:23