From 13e2d7926088079717495b61d3ab3d5d71fd664b Mon Sep 17 00:00:00 2001 From: ultrageese Date: Fri, 29 May 2026 01:21:57 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=20=D0=B4=D0=B2=D0=B5=20=D0=B2?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA=D0=B8=20=D0=B1=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D1=88=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 243 ++++++++++++++++++++++++++++++++++++------- code/src/database.rs | 86 ++++++++++++++- code/src/models.rs | 46 ++------ 3 files changed, 296 insertions(+), 79 deletions(-) diff --git a/code/src/app.rs b/code/src/app.rs index c13e8c2..90c894f 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -4,7 +4,7 @@ use egui::{TextBuffer, mutex::RwLock}; use egui_dock::{DockArea, Style, TabViewer}; use egui_extras::{Column, TableBuilder}; use sqlx::types::BigDecimal; -use crate::{database::DBOperator, models::{Equipment, Material, MaterialCategory, ModalDataType, ModalWinState, Position, Worker}}; +use crate::{database::DBOperator, models::{Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position, Worker}}; static TABS_CAN_BE_WINDOWS: bool = false; @@ -654,31 +654,30 @@ struct MaterialTabViewer{ } impl MaterialTabViewer { + fn update_material_category(&mut self){ + self.mat_cats = Arc::new(RwLock::new(self.rt.block_on(async{self.db_oper.get_mcat().await.unwrap()}))); + } + fn update_materials(&mut self){ + self.mats = Arc::new(RwLock::new(self.rt.block_on(async{self.db_oper.get_materials().await.unwrap()}))); + } fn show_material(&mut self, ui: &mut egui::Ui) { ui.horizontal(|ui|{ if ui.button("Добавить").clicked(){ self.process_material_state.is_open = true; - self.process_material_state.status = "add".to_owned(); + self.process_material_state.status = ModalStatus::Add; } if ui.button("Редактировать").clicked(){ self.process_material_state.is_open = true; - self.process_material_state.status = "edit".to_owned(); + self.process_material_state.status = ModalStatus::Edit; } if ui.button("Удалить").clicked(){ self.process_material_state.is_open = true; - self.process_material_state.status = "remove".to_owned(); + self.process_material_state.status = ModalStatus::Remove; } if ui.button("Обновить").clicked(){ - + self.update_materials(); } }); - if self.process_material_state.is_open{ - egui::Modal::new("add_material".into()).show(ui.ctx(), |ui|{ - if ui.button("Закрыть").clicked(){ - self.process_material_state.is_open = false; - } - }); - } TableBuilder::new(ui) .striped(true) @@ -691,8 +690,8 @@ impl MaterialTabViewer { .header(20.0, |mut header|{ header.col(|ui|{ui.heading("ID");}); header.col(|ui|{ui.heading("Название");}); - header.col(|ui|{ui.heading("Количество");}); header.col(|ui|{ui.heading("Тип");}); + header.col(|ui|{ui.heading("Количество");}); }) .body(|mut body|{ self.rt.block_on(async{ @@ -702,14 +701,127 @@ impl MaterialTabViewer { body.row(30.0,|mut row|{ row.col(|ui|{ui.label(mat.id.to_string());}); row.col(|ui|{ui.label(&mat.name);}); - row.col(|ui|{ui.label(mat.quantity.to_string());}); row.col(|ui|{ui.label(&mat.category.name);}); + row.col(|ui|{ui.label(mat.quantity.to_string());}); }); } }) }); + if self.process_material_state.is_open{ + egui::Modal::new("process_material".into()).show(ui.ctx(), |ui|{ + if ui.button("Закрыть").clicked(){ + self.process_material_state.is_open = false; + } + egui::Grid::new("process_material_grid").show(ui, |ui|{ + let old = self.process_material_state.data.get("id").unwrap().clone(); + if self.process_material_state.status != ModalStatus::Add{ + ui.label("Материал"); + + let mats = self.mats.read().clone(); + + let sel_id = self.process_material_state.data.get("id") + .map(|d| d.as_str()) + .unwrap_or(""); + let cur_name = mats + .iter() + .find(|m| m.id.to_string() == sel_id) + .map(|m| m.name.clone()) + .unwrap_or_default(); + egui::ComboBox::from_id_salt("process_material_combobox_mat") + .selected_text(cur_name) + .show_ui(ui, |ui|{ + for mat in self.mats.read().iter().clone(){ + ui.selectable_value(self.process_material_state.data.get_mut("id").unwrap(), mat.id.to_string(), &mat.name); + } + let id = self.process_material_state.data.get_mut("id").unwrap().clone(); + if id != old{ + self.process_material_state.data.insert("name".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().name.clone()); + self.process_material_state.data.insert("quantity".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().quantity.to_string()); + self.process_material_state.data.insert("category_id".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().category.id.to_string()); + } + }); + ui.end_row(); + + } + let old = self.process_material_state.data.get("category_id").unwrap().clone(); + if self.process_material_state.status != ModalStatus::Remove{ + ui.label("Название"); + ui.text_edit_singleline( self.process_material_state.data.get_mut("name").unwrap()); + + ui.end_row(); + ui.label("Количество"); + ui.text_edit_singleline(self.process_material_state.data.get_mut("quantity").unwrap()); + + ui.end_row(); + ui.label("Тип"); + + + let mats = self.mat_cats.read().clone(); + + let sel_id = self.process_material_state.data.get("category_id") + .map(|d| d.as_str()) + .unwrap_or_default(); + let cur_name = mats + .iter() + .find(|m| m.id.to_string() == sel_id) + .map(|m| m.name.clone()) + .unwrap_or_default(); + egui::ComboBox::from_id_salt("process_material_combobox_cat") + .selected_text(cur_name) + .show_ui(ui, |ui|{ + for mat in self.mat_cats.read().iter(){ + ui.selectable_value(self.process_material_state.data.get_mut("category_id").unwrap(), mat.id.to_string(), &mat.name.clone()); + } + }); + ui.end_row(); + } + + }); + match self.process_material_state.status{ + ModalStatus::Add => { + let resp = ui.add_enabled(self.process_material_state.data.get("name").unwrap().len()>0&& + self.process_material_state.data.get("quantity").unwrap().len()>0, egui::Button::new("Добавить")); + if resp.clicked(){ + + self.rt.block_on(async{ + self.db_oper.add_material(MaterialRow{ + id: self.process_material_state.data.get("id").unwrap().parse::().unwrap(), + name: self.process_material_state.data.get("name").unwrap().to_string(), + quantity: self.process_material_state.data.get("quantity").unwrap().parse::().unwrap(), + category_id: self.process_material_state.data.get("category_id").unwrap().parse::().unwrap(), + }).await.unwrap(); + }); + self.update_materials(); + self.process_material_state.is_open = false; + } + }, + ModalStatus::Edit => { + if ui.button("Сохранить").clicked(){ + self.rt.block_on(async{ + self.db_oper.update_material(MaterialRow { + id: self.process_material_state.data.get("id").unwrap().parse::().unwrap(), + name: self.process_material_state.data.get("name").unwrap().to_string(), + quantity: self.process_material_state.data.get("quantity").unwrap().parse::().unwrap(), + category_id: self.process_material_state.data.get("category_id").unwrap().parse::().unwrap() }).await.unwrap(); + }); + self.update_materials(); + self.process_material_state.is_open = false; + } + }, + ModalStatus::Remove => { + if ui.button("Удалить").clicked(){ + self.rt.block_on(async{ + self.db_oper.delete_material(MaterialRow { id: self.process_material_state.data.get("id").unwrap().parse::().unwrap(), name: "".to_owned(), quantity: 0, category_id:0 }).await.unwrap(); + }); + self.update_materials(); + self.process_material_state.is_open = false; + } + } + } + }); + } } @@ -717,18 +829,18 @@ impl MaterialTabViewer { ui.horizontal(|ui|{ if ui.button("Добавить").clicked(){ self.process_mcat_state.is_open = true; - self.process_mcat_state.status = "add".to_owned(); + self.process_mcat_state.status = ModalStatus::Add; } if ui.button("Редактировать").clicked(){ self.process_mcat_state.is_open = true; - self.process_mcat_state.status = "edit".to_owned(); + self.process_mcat_state.status = ModalStatus::Edit; } if ui.button("Удалить").clicked(){ self.process_mcat_state.is_open = true; - self.process_mcat_state.status = "remove".to_owned(); + self.process_mcat_state.status = ModalStatus::Remove; } if ui.button("Обновить").clicked(){ - + self.update_material_category(); } }); if self.process_mcat_state.is_open{ @@ -738,30 +850,81 @@ impl MaterialTabViewer { } egui::Grid::new("process_mcat_grid") .show(ui, |ui|{ - ui.label("Тип"); - // println!("{}",self.process_mcat_state.data.get("name").unwrap().as_str()); - let mut iterr = self.mat_cats.read().clone(); + + + + let old = self.process_mcat_state.data.get("id").unwrap().clone(); + let iterr = self.mat_cats.read().clone(); + let selected_id = self.process_mcat_state.data.get("id") - .map(|s| s.as_str()) // если там что-то, у чего есть as_str() + .map(|s| s.as_str()) .unwrap_or(""); + let current_name = iterr.iter() .find(|mc| mc.id.to_string() == *selected_id) .map(|mc | mc.name.as_str()) .unwrap_or("Выбрать"); - egui::ComboBox::new("process_mcat_grid_selector","Выбрать") - .selected_text(current_name) - .show_ui(ui, |ui|{ - - self.rt.block_on(async{ - for mcat in iterr{ - ui.selectable_value(self.process_mcat_state.data.get_mut("id").unwrap(), mcat.id.to_string(), &mcat.name); - } + if self.process_mcat_state.status != ModalStatus::Add{ + ui.label("Тип"); + egui::ComboBox::new("process_mcat_grid_selector","Выбрать") + .selected_text(current_name) + .show_ui(ui, |ui|{ + + self.rt.block_on(async{ + for mcat in iterr{ + ui.selectable_value(self.process_mcat_state.data.get_mut("id").unwrap(), mcat.id.to_string(), format!("{}|{}",mcat.id,&mcat.name)); + } + }); }); - }); - ui.end_row(); - - ui.label("Название"); - ui.text_edit_singleline(self.process_mcat_state.data.get_mut("name").unwrap()); + ui.end_row(); + } + let current_id = self.process_mcat_state.data.get("id").unwrap().clone(); + if self.process_mcat_state.data.get("id").unwrap() != &old{ + self.process_mcat_state.data.insert("name".to_owned(), self.mat_cats.read().iter().find(|mc| mc.id.to_string() == current_id).unwrap().name.clone()); + } + + if self.process_mcat_state.status != ModalStatus::Remove{ + ui.label("Название"); + let mut name = self.process_mcat_state.data.get_mut("name").unwrap(); + ui.text_edit_singleline(name); + ui.end_row(); + } + + + match self.process_mcat_state.status{ + ModalStatus::Add =>{ + if ui.button("Добавить").clicked(){ + let name = self.process_mcat_state.data.get("name").unwrap().clone(); + self.rt.block_on(async{ + self.db_oper.add_material_category(MaterialCategory { id: 0, name }).await.unwrap(); + }); + self.update_material_category(); + self.process_mcat_state.is_open = false; + } + }, + ModalStatus::Edit =>{ + if ui.button("Сохранить").clicked(){ + let id = self.process_mcat_state.data.get("id").unwrap().clone(); + let name = self.process_mcat_state.data.get("name").unwrap().clone(); + self.rt.block_on(async{ + self.db_oper.update_material_category(MaterialCategory { id:id.parse::().unwrap(), name: name.clone()}).await.unwrap() + }); + println!("{}",&name); + self.update_material_category(); + self.process_mcat_state.is_open = false; + } + }, + ModalStatus::Remove => { + if ui.button("Удалить").clicked(){ + let idd = self.process_mcat_state.data.get("id").unwrap().clone(); + self.rt.block_on(async{ + self.db_oper.delete_material_category(MaterialCategory { id:idd.parse::().unwrap(), name: "".to_owned() }).await.unwrap() + }); + self.update_material_category(); + self.process_mcat_state.is_open = false; + } + }, + } }); }); } @@ -814,9 +977,9 @@ impl Default for MaterialTabViewer{ let rt = tokio::runtime::Runtime::new().unwrap(); let db_oper = rt.block_on(async{DBOperator::new().await}); let mat_cats = Arc::new(RwLock::new(rt.block_on(async{db_oper.get_mcat().await.unwrap()}))); + let mats = Arc::new(RwLock::new(rt.block_on(async{db_oper.get_materials().await.unwrap()}))); Self { - mats: Arc::new(RwLock::new(rt.block_on(async{db_oper.get_materials().await.unwrap()}))), db_oper, rt, process_mcat_state: ModalWinState{ @@ -824,19 +987,21 @@ impl Default for MaterialTabViewer{ (String::from("id"), mat_cats.clone().read().clone()[0].id.to_string()), (String::from("name"), mat_cats.clone().read().clone()[0].name.clone()), ]), - status: "none".to_owned(), + status: ModalStatus::Add, ..Default::default() }, process_material_state: ModalWinState{ data: HashMap::from([ - ("id".to_owned(),String::new()), - ("name".to_owned(), String::new()), + ("id".to_owned(),mats.clone().read().clone()[0].id.to_string()), + ("name".to_owned(), mats.clone().read().clone()[0].name.clone()), + ("quantity".to_owned(),mats.clone().read().clone()[0].quantity.to_string()), ("category_id".to_owned(), "1".to_owned()) ]), ..Default::default() }, mat_cats, + mats } } diff --git a/code/src/database.rs b/code/src/database.rs index 1885e39..cb7d810 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -121,8 +121,36 @@ impl DBOperator{ } } } + pub async fn add_material_category(&self, mat_cat: MaterialCategory) -> Result{ + match sqlx::query("INSERT INTO Brewery.`material_category` (id, name) VALUES (0, ?)") + .bind(mat_cat.name) + .execute(&self.pool) + .await{ + Ok(_)=>{ + Ok(true) + }, + Err(_)=>{ + Ok(false) + } + } + } + pub async fn add_material(&self, mat: MaterialRow) -> Result{ + match sqlx::query("INSERT INTO Brewery.material (id, name, quantity, category_id) VALUES(0, ?, ?, ?);") + .bind(mat.name) + .bind(mat.quantity) + .bind(mat.category_id) + .execute(&self.pool) + .await{ + Ok(_)=>{ + Ok(true) + }, + Err(_)=>{ + Ok(false) + } + } + } pub async fn delete_position(&self, position: Position) -> Result{ - match sqlx::query("DELETE FROM Brewer.`position` WHERE id = ?;") + match sqlx::query("DELETE FROM Brewery.`position` WHERE id = ?;") .bind(position.id) .execute(&self.pool) .await{ @@ -134,6 +162,32 @@ impl DBOperator{ } } } + pub async fn delete_material_category(&self, mat_cat: MaterialCategory) -> Result{ + match sqlx::query("DELETE FROM Brewery.`material_category` WHERE id = ?;") + .bind(mat_cat.id) + .execute(&self.pool) + .await{ + Ok(_) =>{ + Ok(true) + }, + Err(_)=>{ + Ok(false) + } + } + } + pub async fn delete_material(&self, mat: MaterialRow) -> Result{ + match sqlx::query("DELETE FROM Brewery.`material` WHERE id = ?;") + .bind(mat.id) + .execute(&self.pool) + .await{ + Ok(_) =>{ + Ok(true) + }, + Err(_)=>{ + Ok(false) + } + } + } pub async fn update_worker(&self, worker: Worker) -> Result{ match sqlx::query("UPDATE Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;") @@ -152,6 +206,36 @@ impl DBOperator{ } } } + pub async fn update_material_category(&self, mat_cat: MaterialCategory) -> Result{ + match sqlx::query("UPDATE Brewery.`material_category` SET name=? WHERE id=?;") + .bind(mat_cat.name) + .bind(mat_cat.id) + .execute(&self.pool) + .await{ + Ok(_) =>{ + Ok(true) + }, + Err(_)=>{ + Ok(false) + } + } + } + pub async fn update_material(&self, mat: MaterialRow) -> Result{ + match sqlx::query("UPDATE Brewery.material SET name=?, quantity=?, category_id=? WHERE id=?;") + .bind(mat.name) + .bind(mat.quantity) + .bind(mat.category_id) + .bind(mat.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?; diff --git a/code/src/models.rs b/code/src/models.rs index c9c3fd8..e34d789 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -114,45 +114,13 @@ pub struct ModalWinState{ pub is_open: bool, pub can_finish: bool, pub data: std::collections::HashMap, - pub status: String, + pub status: ModalStatus, } -#[derive(PartialEq)] -pub enum ModalDataType{ - Pos(Position), - MatCat(MaterialCategory), - Text(String), -} -impl TextBuffer for ModalDataType{ - fn is_mutable(&self) -> bool { - true - } - fn as_str(&self) -> &str { - match self{ - ModalDataType::Pos(pos) => &pos.name, - ModalDataType::Text(txt) => &txt, - ModalDataType::MatCat(mat_cat) => &mat_cat.name, - } - } - - fn insert_text(&mut self, text: &str, char_index: usize) -> usize { - match self{ - ModalDataType::Pos(pos) => {pos.name.insert_str(char_index, text);}, - ModalDataType::Text(txt) => {txt.insert_str(char_index, text);}, - ModalDataType::MatCat(mat_cat) => {mat_cat.name.insert_str(char_index, text);} - } - text.len() - } - - fn delete_char_range(&mut self, char_range: std::ops::Range) { - match self{ - ModalDataType::Pos(pos) => {pos.name.delete_char_range(char_range);}, - ModalDataType::Text(txt) => {txt.delete_char_range(char_range);}, - ModalDataType::MatCat(mat_cat) => {mat_cat.name.delete_char_range(char_range);} - } - } - - fn type_id(&self) -> std::any::TypeId { - TypeId::of::() - } +#[derive(Default, PartialEq)] +pub enum ModalStatus{ + #[default] + Add, + Edit, + Remove } \ No newline at end of file