From ec2cae91c0c3712abbdec929823eec5f1488debd Mon Sep 17 00:00:00 2001 From: ultrageese Date: Sat, 6 Jun 2026 14:11:05 +1000 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D0=BD=D1=91=D1=81=20=D0=B2?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=BD=D1=8B=D0=BC=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= =?UTF-8?q?=D0=BC,=20=D0=B4=D0=B0=D0=B1=D1=8B=20=D0=BD=D0=B5=20=D0=B1?= =?UTF-8?q?=D0=BE=D1=8F=D1=82=D1=8C=D1=81=D1=8F=20app.rs=20=D0=BD=D0=B0=20?= =?UTF-8?q?100500=20=D1=81=D1=82=D1=80=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 1162 +------------------------------------- code/src/main.rs | 5 +- code/src/material_tab.rs | 581 +++++++++++++++++++ code/src/recipe_tab.rs | 27 + code/src/tab.rs | 25 + code/src/worker_tab.rs | 566 +++++++++++++++++++ 6 files changed, 1205 insertions(+), 1161 deletions(-) create mode 100644 code/src/material_tab.rs create mode 100644 code/src/recipe_tab.rs create mode 100644 code/src/tab.rs create mode 100644 code/src/worker_tab.rs diff --git a/code/src/app.rs b/code/src/app.rs index 7cfaa85..392b75f 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -1,41 +1,16 @@ use std::{collections::HashMap, ops::Deref, str::FromStr, sync::Arc}; use crate::{ - database::DBOperator, - models::{ + database::DBOperator, material_tab::MaterialTabViewer, models::{ Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position, Worker, - }, + }, tab::*, worker_tab::* }; use egui::{TextBuffer, Vec2, mutex::RwLock}; use egui_dock::{DockArea, Style, TabViewer}; use egui_extras::{Column, TableBuilder}; use sqlx::types::BigDecimal; -static TABS_CAN_BE_WINDOWS: bool = false; - -enum TabTypes { - Equipment, - Worker, - Position, - Salary, - Material, - Recipe, - Product, - Order, - Settings, - WorkerList, - WorkerPosition, - MaterialList, - MaterialTypeList, - RecipeList, - RecipeDetail, - ProductList, -} -struct Tab { - tab_type: TabTypes, - title: String, -} pub struct App { pub tree: egui_dock::DockState, pub main_viewer: MainTabViewer, @@ -356,1136 +331,3 @@ impl egui_dock::TabViewer for MainTabViewer { egui::Id::new(&tab.title) } } -struct WorkerTabViewer { - db_oper: DBOperator, - workers: Arc>>>, - positions: Arc>>, - show_worker_add_modal: bool, - show_worker_edit_modal: bool, - show_position_add_modal: bool, - fire_worker_id: String, - add_worker_name: String, - add_worker_hire_date: String, - 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, - show_position_delete_modal: bool, - delete_position: Position, - process_position_state: ModalWinState, -} - -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 update_positions(&mut self) { - self.positions = Arc::new(RwLock::new( - self.rt - .block_on(async { self.db_oper.get_position().await.unwrap() }), - )); - } - - fn show_worker(&mut self, ui: &mut egui::Ui) { - ui.horizontal(|ui| { - if ui.button("Добавить").clicked() { - self.show_worker_add_modal = true; - self.add_worker_name = String::new(); - self.add_worker_position = Position::default(); - }; - if ui.button("Редактировать").clicked() { - self.show_worker_edit_modal = true; - 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; - }); - } - if ui.button("Обновить").clicked() { - self.update_workers(); - } - }); - if self.show_worker_add_modal { - egui::Modal::new("add_worker".into()).show(ui.ctx(), |ui| { - if ui.button("Закрыть").clicked() { - self.show_worker_add_modal = false; - } - ui.horizontal(|ui| { - ui.vertical(|ui| { - ui.label("Имя сотрудника:"); - ui.label("Дата найма:"); - ui.label("Должность:"); - }); - ui.vertical(|ui| { - ui.add( - egui::TextEdit::singleline(&mut self.add_worker_name) - .hint_text("Напр: Иванов Иван"), - ); - ui.add( - egui::TextEdit::singleline(&mut self.add_worker_hire_date) - .hint_text("Напр: 12-02-2010"), - ); - egui::ComboBox::from_label("Выбрать!") - .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.add_worker_position, - pos.clone(), - &pos.name, - ); - } - }); - }); - }); - }); - - 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_worker = false; - } else { - self.can_add_worker = true; - } - ui.vertical_centered(|ui| { - let resp = ui.add_enabled(self.can_add_worker, egui::Button::new("Добавить")); - if resp.clicked() { - self.rt.block_on(async { - 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: 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 { - 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.label("Дата найма"); - ui.text_edit_singleline(&mut self.edit_worker_hire_date); - ui.end_row(); - - ui.checkbox(&mut self.edit_worker_is_fired, "Уволен"); - ui.end_row(); - }); - if chrono::NaiveDate::parse_from_str(&self.edit_worker_hire_date, "%Y-%m-%d") - .is_ok() - && self.edit_worker_name.len() > 0 - { - self.can_edit_worker = true; - } else { - self.can_edit_worker = false; - } - let resp = ui.add_enabled(self.can_edit_worker, egui::Button::new("Добавить")); - if resp.clicked() { - self.rt.block_on(async { - let ndate = chrono::NaiveDate::parse_from_str( - &self.edit_worker_hire_date, - "%Y-%m-%d", - ) - .unwrap(); - self.db_oper - .update_worker(Worker { - id: self.edit_worker_id, - full_name: self.edit_worker_name.clone(), - hire_date: ndate - .and_hms_opt(0, 0, 0) - .unwrap() - .and_local_timezone(chrono::Local) - .unwrap(), - position: self.edit_worker_position.clone(), - is_fired: self.edit_worker_is_fired, - }) - .await - .unwrap(); - }); - self.update_workers(); - self.show_worker_edit_modal = false; - } - }); - } - for wk in self.workers.read().clone().unwrap().iter() { - ui.push_id(format!("{}:{}", &wk.full_name, &wk.id), |ui| { - egui::CollapsingHeader::new(format!("#{:08} | {}", &wk.id, &wk.full_name)) - .default_open(false) - .show(ui, |ui| { - ui.horizontal(|ui| { - ui.label("Нанят: "); - ui.label(format!( - "{}", - wk.hire_date.date_naive().format("%d-%m-%Y").to_string() - )); - }); - ui.horizontal(|ui| { - ui.label("Должность: "); - ui.label(&wk.position.name); - }); - ui.horizontal(|ui| { - ui.label("Уволен: "); - ui.label(if wk.is_fired { "Да" } else { "Нет" }) - }) - }) - }); - } - } - fn show_position(&mut self, ui: &mut egui::Ui) { - ui.horizontal(|ui| { - if ui.button("Добавить").clicked() { - // self.show_position_add_modal = true; - self.process_position_state.is_open = true; - self.process_position_state.status = ModalStatus::Add; - self.process_position_state - .data - .insert("id".into(), "0".to_string()); - self.process_position_state - .data - .insert("name".into(), String::new()); - self.process_position_state - .data - .insert("wage".into(), String::from("0")); - } - if ui.button("Обновить").clicked() { - self.update_positions(); - } - }); - TableBuilder::new(ui) - .column(Column::auto()) - .column(Column::auto()) - .column(Column::auto()) - .sense(egui::Sense::click()) - .header(30.0, |mut header| { - header.col(|ui| { - ui.heading("Название"); - }); - header.col(|ui| { - ui.heading("Оклад"); - }); - }) - .body(|mut body| { - body.ui_mut().style_mut().interaction.selectable_labels = false; - for pos in self.positions.read().clone().iter() { - body.row(20.0, |mut row| { - row.col(|ui| { - ui.label(pos.name.clone()); - }); - row.col(|ui| { - ui.label(format!("${}", pos.wage)); - }); - row.col(|ui| { - let resp = ui.add(egui::Button::new("Удалить")); - if resp.clicked() { - self.process_position_state.is_open = true; - self.process_position_state.status = ModalStatus::Remove; - self.process_position_state - .data - .insert("id".into(), pos.id.to_string()); - self.process_position_state - .data - .insert("name".into(), pos.name.clone()); - self.process_position_state - .data - .insert("wage".into(), pos.wage.to_string()); - } - }); - if row.response().double_clicked() { - self.process_position_state.is_open = true; - self.process_position_state.status = ModalStatus::Edit; - self.process_position_state - .data - .insert("id".into(), pos.id.to_string()); - self.process_position_state - .data - .insert("name".into(), pos.name.clone()); - self.process_position_state - .data - .insert("wage".into(), pos.wage.to_string()); - } - }); - } - }); - - if self.process_position_state.is_open { - egui::Modal::new(egui::Id::new("process_worker_pos_modal")).show(ui.ctx(), |ui| { - if ui.button("Закрыть").clicked() { - self.process_position_state.is_open = false; - } - - if self.process_position_state.status != ModalStatus::Remove { - egui::Grid::new("process_worker_pos_grid").show(ui, |ui| { - ui.label("Название"); - let mut name = self.process_position_state.data.get_mut("name").unwrap(); - let mut spacing = ui.spacing().interact_size; - spacing.x = 150.0; - ui.add_sized(spacing, |ui: &mut egui::Ui| ui.text_edit_singleline(name)); - - ui.end_row(); - - ui.label("Оклад"); - let mut wage = self.process_position_state.data.get_mut("wage").unwrap(); - ui.text_edit_singleline(wage); - }); - } else { - ui.label("Вы уверены, что хотите удалить:"); - ui.label(format!( - "{}?", - self.process_position_state.data["name"].clone() - )); - } - let btext: String; - match self.process_position_state.status { - ModalStatus::Add => { - btext = String::from("Добавить"); - self.process_position_state.can_finish = true; - } - ModalStatus::Edit => { - btext = String::from("Сохранить"); - self.process_position_state.can_finish = true; - } - ModalStatus::Remove => { - self.process_position_state.can_finish = self - .workers - .read() - .clone() - .unwrap() - .iter() - .find(|wrkr| wrkr.position.id == self.delete_position.id) - .iter() - .len() - == 0; - btext = String::from("Удалить"); - } - } - let button = ui.add_enabled( - self.process_position_state.can_finish, - egui::Button::new(btext), - ); - if button.clicked() { - match self.process_position_state.status { - ModalStatus::Add => { - let pos = self.process_position_state.data.clone(); - self.rt.block_on(async { - self.db_oper - .add_position(Position { - id: pos["id"].parse::().unwrap(), - name: pos["name"].clone(), - wage: bigdecimal::BigDecimal::from_str( - pos["wage"].as_str(), - ) - .unwrap(), - }) - .await; - }) - } - ModalStatus::Edit => { - let pos = self.process_position_state.data.clone(); - self.rt.block_on(async { - self.db_oper - .update_position(Position { - id: pos["id"].parse::().unwrap(), - name: pos["name"].clone(), - wage: bigdecimal::BigDecimal::from_str( - pos["wage"].as_str(), - ) - .unwrap(), - }) - .await; - }) - } - ModalStatus::Remove => { - let pos = self.process_position_state.data.clone(); - self.rt.block_on(async { - self.db_oper - .delete_position(Position { - id: pos["id"].parse::().unwrap(), - name: String::new(), - wage: BigDecimal::from(0), - }) - .await; - }); - } - } - self.update_positions(); - self.process_position_state.is_open = false; - } - }); - } - } -} - -impl egui_dock::TabViewer for WorkerTabViewer { - type Tab = Tab; - fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { - (&*tab.title).into() - } - fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { - match &tab.tab_type { - TabTypes::WorkerList => self.show_worker(ui), - TabTypes::WorkerPosition => self.show_position(ui), - _ => { - ui.label("Nope"); - } - } - } - fn id(&mut self, tab: &mut Self::Tab) -> egui::Id { - egui::Id::new(&tab.title) - } - fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool { - TABS_CAN_BE_WINDOWS - } - fn is_closeable(&self, _tab: &Self::Tab) -> bool { - false - } -} -impl Default for WorkerTabViewer { - fn default() -> Self { - let rt = tokio::runtime::Runtime::new().unwrap(); - let db_oper = rt.block_on(async { DBOperator::new().await }); - let positions = Arc::new(RwLock::new( - rt.block_on(async { db_oper.get_position().await.unwrap() }), - )); - let mut pos_map: HashMap = HashMap::new(); - pos_map.extend(|| -> Vec<(String, String)> { - let pos = positions.read()[0].clone(); - vec![ - ("id".to_string(), pos.id.to_string()), - ("name".to_string(), pos.name.clone()), - ("wage".to_string(), pos.wage.to_string()), - ] - }()); - Self { - process_position_state: ModalWinState { - is_open: false, - can_finish: false, - data: pos_map, - status: ModalStatus::Add, - }, - workers: Arc::new(RwLock::new(Option::Some( - rt.block_on(async { db_oper.get_workers().await.unwrap() }), - ))), - positions: positions, - show_worker_add_modal: false, - show_worker_edit_modal: false, - show_position_add_modal: false, - show_position_delete_modal: false, - fire_worker_id: String::new(), - add_worker_name: String::new(), - add_worker_position: Position::default(), - add_worker_hire_date: String::new(), - can_add_worker: false, - can_edit_worker: false, - add_position_name: String::new(), - add_position_wage: String::new(), - delete_position: Position::default(), - - 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, - } - } -} - -struct MaterialTabViewer { - db_oper: DBOperator, - rt: tokio::runtime::Runtime, - process_mcat_state: ModalWinState, - - process_material_state: ModalWinState, - - mat_cats: Arc>>, - mats: Arc>>, -} -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 = ModalStatus::Add; - } - if ui.button("Удалить").clicked() { - self.process_material_state.is_open = true; - self.process_material_state.status = ModalStatus::Remove; - } - if ui.button("Обновить").clicked() { - self.update_materials(); - } - }); - - TableBuilder::new(ui) - .striped(true) - .cell_layout(egui::Layout::centered_and_justified( - egui::Direction::LeftToRight, - )) - .vscroll(true) - .column(Column::auto()) - .column(Column::auto()) - .column(Column::auto()) - .sense(egui::Sense::click()) - .header(20.0, |mut header| { - header.col(|ui| { - ui.heading("Название"); - }); - header.col(|ui| { - ui.heading("Тип"); - }); - header.col(|ui| { - ui.heading("Количество"); - }); - }) - .body(|mut body| { - body.ui_mut().style_mut().interaction.selectable_labels = false; - self.rt.block_on(async { - for mat in self.mats.read().clone().iter() { - body.row(30.0, |mut row| { - row.col(|ui| { - ui.label(&mat.name); - }); - row.col(|ui| { - ui.label(&mat.category.name); - }); - row.col(|ui| { - ui.label(mat.quantity.to_string()); - }); - if row.response().double_clicked() { - self.process_material_state.is_open = true; - self.process_material_state.status = ModalStatus::Edit; - self.process_material_state - .data - .insert("id".into(), mat.id.to_string()); - self.process_material_state - .data - .insert("name".into(), mat.name.to_string()); - self.process_material_state - .data - .insert("category_id".into(), mat.category.id.to_string()); - self.process_material_state - .data - .insert("quantity".into(), 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; - } - } - } - }); - } - } - - fn show_material_type(&mut self, ui: &mut egui::Ui) { - ui.horizontal(|ui| { - if ui.button("Добавить").clicked() { - self.process_mcat_state.is_open = true; - self.process_mcat_state.status = ModalStatus::Add; - } - if ui.button("Удалить").clicked() { - self.process_mcat_state.is_open = true; - self.process_mcat_state.status = ModalStatus::Remove; - } - if ui.button("Обновить").clicked() { - self.update_material_category(); - } - }); - if self.process_mcat_state.is_open { - egui::Modal::new("process_mcat".into()).show(ui.ctx(), |ui| { - if ui.button("Закрыть").clicked() { - self.process_mcat_state.is_open = false; - } - egui::Grid::new("process_mcat_grid").show(ui, |ui| { - 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()) - .unwrap_or(""); - - let current_name = iterr - .iter() - .find(|mc| mc.id.to_string() == *selected_id) - .map(|mc| mc.name.as_str()) - .unwrap_or("Выбрать"); - 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(); - } - 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; - } - } - } - }); - }); - } - TableBuilder::new(ui) - .striped(true) - .column(Column::auto()) - .column(Column::auto()) - .sense(egui::Sense::click()) - .header(20.0, |mut header| { - header.col(|ui| { - ui.heading("ID"); - }); - header.col(|ui| { - ui.heading("Название"); - }); - }) - .body(|mut body| { - self.rt.block_on(async { - for mcat in self.mat_cats.read().clone().iter() { - body.row(20.0, |mut row| { - row.col(|ui| { - ui.label(mcat.id.to_string()); - }); - row.col(|ui| { - ui.label(&mcat.name); - }); - if row.response().double_clicked() { - self.process_mcat_state.is_open = true; - self.process_mcat_state.status = ModalStatus::Edit; - self.process_mcat_state - .data - .insert("id".into(), mcat.id.to_string()); - self.process_mcat_state - .data - .insert("name".into(), mcat.name.clone()); - } - }); - } - }); - }); - } -} -impl egui_dock::TabViewer for MaterialTabViewer { - type Tab = Tab; - fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { - (&*tab.title).into() - } - fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { - match &tab.tab_type { - TabTypes::MaterialList => self.show_material(ui), - TabTypes::MaterialTypeList => self.show_material_type(ui), - _ => { - ui.label("Каким образом?"); - } - } - } - fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool { - TABS_CAN_BE_WINDOWS - } - fn is_closeable(&self, _tab: &Self::Tab) -> bool { - false - } -} -impl Default for MaterialTabViewer { - fn default() -> Self { - 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 { - db_oper, - rt, - process_mcat_state: ModalWinState { - data: HashMap::from([ - ( - String::from("id"), - mat_cats.clone().read().clone()[0].id.to_string(), - ), - ( - String::from("name"), - mat_cats.clone().read().clone()[0].name.clone(), - ), - ]), - status: ModalStatus::Add, - ..Default::default() - }, - - process_material_state: ModalWinState { - data: HashMap::from([ - ( - "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, - } - } -} - -struct RecipeTabViewer {} - -impl RecipeTabViewer { - fn show_recipe_list(&mut self, ui: &mut egui::Ui) {} - fn show_recipe_detail(&mut self, ui: &mut egui::Ui) {} -} -impl egui_dock::TabViewer for RecipeTabViewer { - type Tab = Tab; - - fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { - tab.title.clone().into() - } - - fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { - match &tab.tab_type { - TabTypes::RecipeList => { - self.show_recipe_list(ui); - } - TabTypes::RecipeDetail => { - self.show_recipe_detail(ui); - } - _ => { - ui.label("Помогите!!"); - } - } - } -} diff --git a/code/src/main.rs b/code/src/main.rs index 564f70b..67b6ec6 100644 --- a/code/src/main.rs +++ b/code/src/main.rs @@ -1,8 +1,11 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - mod app; mod database; +mod material_tab; mod models; +mod recipe_tab; +mod tab; +mod worker_tab; // mod schema; fn main() { dotenvy::dotenv().ok(); diff --git a/code/src/material_tab.rs b/code/src/material_tab.rs new file mode 100644 index 0000000..0677572 --- /dev/null +++ b/code/src/material_tab.rs @@ -0,0 +1,581 @@ +use std::{collections::HashMap, 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}}; + +pub struct MaterialTabViewer { + db_oper: DBOperator, + rt: tokio::runtime::Runtime, + process_mcat_state: ModalWinState, + + process_material_state: ModalWinState, + + mat_cats: Arc>>, + mats: Arc>>, +} +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 = ModalStatus::Add; + } + if ui.button("Удалить").clicked() { + self.process_material_state.is_open = true; + self.process_material_state.status = ModalStatus::Remove; + } + if ui.button("Обновить").clicked() { + self.update_materials(); + } + }); + + TableBuilder::new(ui) + .striped(true) + .cell_layout(egui::Layout::centered_and_justified( + egui::Direction::LeftToRight, + )) + .vscroll(true) + .column(Column::auto()) + .column(Column::auto()) + .column(Column::auto()) + .sense(egui::Sense::click()) + .header(20.0, |mut header| { + header.col(|ui| { + ui.heading("Название"); + }); + header.col(|ui| { + ui.heading("Тип"); + }); + header.col(|ui| { + ui.heading("Количество"); + }); + }) + .body(|mut body| { + body.ui_mut().style_mut().interaction.selectable_labels = false; + self.rt.block_on(async { + for mat in self.mats.read().clone().iter() { + body.row(30.0, |mut row| { + row.col(|ui| { + ui.label(&mat.name); + }); + row.col(|ui| { + ui.label(&mat.category.name); + }); + row.col(|ui| { + ui.label(mat.quantity.to_string()); + }); + if row.response().double_clicked() { + self.process_material_state.is_open = true; + self.process_material_state.status = ModalStatus::Edit; + self.process_material_state + .data + .insert("id".into(), mat.id.to_string()); + self.process_material_state + .data + .insert("name".into(), mat.name.to_string()); + self.process_material_state + .data + .insert("category_id".into(), mat.category.id.to_string()); + self.process_material_state + .data + .insert("quantity".into(), 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; + } + } + } + }); + } + } + + fn show_material_type(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + if ui.button("Добавить").clicked() { + self.process_mcat_state.is_open = true; + self.process_mcat_state.status = ModalStatus::Add; + } + if ui.button("Удалить").clicked() { + self.process_mcat_state.is_open = true; + self.process_mcat_state.status = ModalStatus::Remove; + } + if ui.button("Обновить").clicked() { + self.update_material_category(); + } + }); + if self.process_mcat_state.is_open { + egui::Modal::new("process_mcat".into()).show(ui.ctx(), |ui| { + if ui.button("Закрыть").clicked() { + self.process_mcat_state.is_open = false; + } + egui::Grid::new("process_mcat_grid").show(ui, |ui| { + 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()) + .unwrap_or(""); + + let current_name = iterr + .iter() + .find(|mc| mc.id.to_string() == *selected_id) + .map(|mc| mc.name.as_str()) + .unwrap_or("Выбрать"); + 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(); + } + 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; + } + } + } + }); + }); + } + TableBuilder::new(ui) + .striped(true) + .column(Column::auto()) + .column(Column::auto()) + .sense(egui::Sense::click()) + .header(20.0, |mut header| { + header.col(|ui| { + ui.heading("ID"); + }); + header.col(|ui| { + ui.heading("Название"); + }); + }) + .body(|mut body| { + self.rt.block_on(async { + for mcat in self.mat_cats.read().clone().iter() { + body.row(20.0, |mut row| { + row.col(|ui| { + ui.label(mcat.id.to_string()); + }); + row.col(|ui| { + ui.label(&mcat.name); + }); + if row.response().double_clicked() { + self.process_mcat_state.is_open = true; + self.process_mcat_state.status = ModalStatus::Edit; + self.process_mcat_state + .data + .insert("id".into(), mcat.id.to_string()); + self.process_mcat_state + .data + .insert("name".into(), mcat.name.clone()); + } + }); + } + }); + }); + } +} +impl egui_dock::TabViewer for MaterialTabViewer { + type Tab = Tab; + fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { + (&*tab.title).into() + } + fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { + match &tab.tab_type { + TabTypes::MaterialList => self.show_material(ui), + TabTypes::MaterialTypeList => self.show_material_type(ui), + _ => { + ui.label("Каким образом?"); + } + } + } + fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool { + TABS_CAN_BE_WINDOWS + } + fn is_closeable(&self, _tab: &Self::Tab) -> bool { + false + } +} +impl Default for MaterialTabViewer { + fn default() -> Self { + 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 { + db_oper, + rt, + process_mcat_state: ModalWinState { + data: HashMap::from([ + ( + String::from("id"), + mat_cats.clone().read().clone()[0].id.to_string(), + ), + ( + String::from("name"), + mat_cats.clone().read().clone()[0].name.clone(), + ), + ]), + status: ModalStatus::Add, + ..Default::default() + }, + + process_material_state: ModalWinState { + data: HashMap::from([ + ( + "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/recipe_tab.rs b/code/src/recipe_tab.rs new file mode 100644 index 0000000..6d7ea36 --- /dev/null +++ b/code/src/recipe_tab.rs @@ -0,0 +1,27 @@ +struct RecipeTabViewer {} + +impl RecipeTabViewer { + fn show_recipe_list(&mut self, ui: &mut egui::Ui) {} + fn show_recipe_detail(&mut self, ui: &mut egui::Ui) {} +} +impl egui_dock::TabViewer for RecipeTabViewer { + type Tab = Tab; + + fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { + tab.title.clone().into() + } + + fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { + match &tab.tab_type { + TabTypes::RecipeList => { + self.show_recipe_list(ui); + } + TabTypes::RecipeDetail => { + self.show_recipe_detail(ui); + } + _ => { + ui.label("Помогите!!"); + } + } + } +} diff --git a/code/src/tab.rs b/code/src/tab.rs new file mode 100644 index 0000000..fa4542d --- /dev/null +++ b/code/src/tab.rs @@ -0,0 +1,25 @@ +pub static TABS_CAN_BE_WINDOWS: bool = false; + +pub enum TabTypes { + Equipment, + Worker, + Position, + Salary, + Material, + Recipe, + Product, + Order, + Settings, + WorkerList, + WorkerPosition, + MaterialList, + MaterialTypeList, + RecipeList, + RecipeDetail, + ProductList, +} + +pub struct Tab { + pub tab_type: TabTypes, + pub title: String, +} diff --git a/code/src/worker_tab.rs b/code/src/worker_tab.rs new file mode 100644 index 0000000..7fa63d6 --- /dev/null +++ b/code/src/worker_tab.rs @@ -0,0 +1,566 @@ +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 crate::models::{ModalStatus, ModalWinState, Position, Worker}; +use crate::database::*; +use crate::tab::*; +pub struct WorkerTabViewer { + db_oper: DBOperator, + workers: Arc>>>, + positions: Arc>>, + show_worker_add_modal: bool, + show_worker_edit_modal: bool, + show_position_add_modal: bool, + fire_worker_id: String, + add_worker_name: String, + add_worker_hire_date: String, + 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, + show_position_delete_modal: bool, + delete_position: Position, + process_position_state: ModalWinState, +} + +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 update_positions(&mut self) { + self.positions = Arc::new(RwLock::new( + self.rt + .block_on(async { self.db_oper.get_position().await.unwrap() }), + )); + } + + fn show_worker(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + if ui.button("Добавить").clicked() { + self.show_worker_add_modal = true; + self.add_worker_name = String::new(); + self.add_worker_position = Position::default(); + }; + if ui.button("Редактировать").clicked() { + self.show_worker_edit_modal = true; + 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; + }); + } + if ui.button("Обновить").clicked() { + self.update_workers(); + } + }); + if self.show_worker_add_modal { + egui::Modal::new("add_worker".into()).show(ui.ctx(), |ui| { + if ui.button("Закрыть").clicked() { + self.show_worker_add_modal = false; + } + ui.horizontal(|ui| { + ui.vertical(|ui| { + ui.label("Имя сотрудника:"); + ui.label("Дата найма:"); + ui.label("Должность:"); + }); + ui.vertical(|ui| { + ui.add( + egui::TextEdit::singleline(&mut self.add_worker_name) + .hint_text("Напр: Иванов Иван"), + ); + ui.add( + egui::TextEdit::singleline(&mut self.add_worker_hire_date) + .hint_text("Напр: 12-02-2010"), + ); + egui::ComboBox::from_label("Выбрать!") + .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.add_worker_position, + pos.clone(), + &pos.name, + ); + } + }); + }); + }); + }); + + 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_worker = false; + } else { + self.can_add_worker = true; + } + ui.vertical_centered(|ui| { + let resp = ui.add_enabled(self.can_add_worker, egui::Button::new("Добавить")); + if resp.clicked() { + self.rt.block_on(async { + 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: 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 { + 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.label("Дата найма"); + ui.text_edit_singleline(&mut self.edit_worker_hire_date); + ui.end_row(); + + ui.checkbox(&mut self.edit_worker_is_fired, "Уволен"); + ui.end_row(); + }); + if chrono::NaiveDate::parse_from_str(&self.edit_worker_hire_date, "%Y-%m-%d") + .is_ok() + && self.edit_worker_name.len() > 0 + { + self.can_edit_worker = true; + } else { + self.can_edit_worker = false; + } + let resp = ui.add_enabled(self.can_edit_worker, egui::Button::new("Добавить")); + if resp.clicked() { + self.rt.block_on(async { + let ndate = chrono::NaiveDate::parse_from_str( + &self.edit_worker_hire_date, + "%Y-%m-%d", + ) + .unwrap(); + self.db_oper + .update_worker(Worker { + id: self.edit_worker_id, + full_name: self.edit_worker_name.clone(), + hire_date: ndate + .and_hms_opt(0, 0, 0) + .unwrap() + .and_local_timezone(chrono::Local) + .unwrap(), + position: self.edit_worker_position.clone(), + is_fired: self.edit_worker_is_fired, + }) + .await + .unwrap(); + }); + self.update_workers(); + self.show_worker_edit_modal = false; + } + }); + } + TableBuilder::new(ui) + .column(Column::auto()) + .column(Column::auto()) + .column(Column::auto()) + .column(Column::auto()) + .column(Column::auto()) + .sense(egui::Sense::click()) + .header(30.0, |mut header| { + header.col(|ui| { + ui.heading("Имя"); + }); + header.col(|ui| { + ui.heading("Дата найма"); + }); + header.col(|ui| { + ui.heading("Должность"); + }); + header.col(|ui| { + ui.heading("Уволен"); + }); + }) + .body(|mut body| { + body.ui_mut().style_mut().interaction.selectable_labels = false; + + for wk in self.workers.read().clone().unwrap().iter() { + body.row(25.0, |mut row| { + row.col(|ui| { + ui.label(&wk.full_name); + }); + row.col(|ui| { + ui.label(wk.hire_date.date_naive().format("%d-%m-%Y").to_string()); + }); + row.col(|ui| { + ui.label(&wk.position.name); + }); + row.col(|ui| { + ui.label(if wk.is_fired { "Да" } else { "Нет" }); + }); + row.col(|ui| { + if ui.button("Уволить").clicked() { + todo!(); + } + }); + }); + } + }); + } + + fn show_position(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + if ui.button("Добавить").clicked() { + // self.show_position_add_modal = true; + self.process_position_state.is_open = true; + self.process_position_state.status = ModalStatus::Add; + self.process_position_state + .data + .insert("id".into(), "0".to_string()); + self.process_position_state + .data + .insert("name".into(), String::new()); + self.process_position_state + .data + .insert("wage".into(), String::from("0")); + } + if ui.button("Обновить").clicked() { + self.update_positions(); + } + }); + TableBuilder::new(ui) + .column(Column::auto()) + .column(Column::auto()) + .column(Column::auto()) + .sense(egui::Sense::click()) + .header(30.0, |mut header| { + header.col(|ui| { + ui.heading("Название"); + }); + header.col(|ui| { + ui.heading("Оклад"); + }); + }) + .body(|mut body| { + body.ui_mut().style_mut().interaction.selectable_labels = false; + for pos in self.positions.read().clone().iter() { + body.row(20.0, |mut row| { + row.col(|ui| { + ui.label(pos.name.clone()); + }); + row.col(|ui| { + ui.label(format!("${}", pos.wage)); + }); + row.col(|ui| { + let resp = ui.add(egui::Button::new("Удалить")); + if resp.clicked() { + self.process_position_state.is_open = true; + self.process_position_state.status = ModalStatus::Remove; + self.process_position_state + .data + .insert("id".into(), pos.id.to_string()); + self.process_position_state + .data + .insert("name".into(), pos.name.clone()); + self.process_position_state + .data + .insert("wage".into(), pos.wage.to_string()); + } + }); + if row.response().double_clicked() { + self.process_position_state.is_open = true; + self.process_position_state.status = ModalStatus::Edit; + self.process_position_state + .data + .insert("id".into(), pos.id.to_string()); + self.process_position_state + .data + .insert("name".into(), pos.name.clone()); + self.process_position_state + .data + .insert("wage".into(), pos.wage.to_string()); + } + }); + } + }); + + if self.process_position_state.is_open { + egui::Modal::new(egui::Id::new("process_worker_pos_modal")).show(ui.ctx(), |ui| { + if ui.button("Закрыть").clicked() { + self.process_position_state.is_open = false; + } + + if self.process_position_state.status != ModalStatus::Remove { + egui::Grid::new("process_worker_pos_grid").show(ui, |ui| { + ui.label("Название"); + let mut name = self.process_position_state.data.get_mut("name").unwrap(); + let mut spacing = ui.spacing().interact_size; + spacing.x = 150.0; + ui.add_sized(spacing, |ui: &mut egui::Ui| ui.text_edit_singleline(name)); + + ui.end_row(); + + ui.label("Оклад"); + let mut wage = self.process_position_state.data.get_mut("wage").unwrap(); + ui.text_edit_singleline(wage); + }); + } else { + ui.label("Вы уверены, что хотите удалить:"); + ui.label(format!( + "{}?", + self.process_position_state.data["name"].clone() + )); + } + let btext: String; + match self.process_position_state.status { + ModalStatus::Add => { + btext = String::from("Добавить"); + self.process_position_state.can_finish = true; + } + ModalStatus::Edit => { + btext = String::from("Сохранить"); + self.process_position_state.can_finish = true; + } + ModalStatus::Remove => { + self.process_position_state.can_finish = self + .workers + .read() + .clone() + .unwrap() + .iter() + .find(|wrkr| wrkr.position.id == self.delete_position.id) + .iter() + .len() + == 0; + btext = String::from("Удалить"); + } + } + let button = ui.add_enabled( + self.process_position_state.can_finish, + egui::Button::new(btext), + ); + if button.clicked() || ui.input(|i| i.key_pressed(egui::Key::Enter)) { + match self.process_position_state.status { + ModalStatus::Add => { + let pos = self.process_position_state.data.clone(); + self.rt.block_on(async { + self.db_oper + .add_position(Position { + id: pos["id"].parse::().unwrap(), + name: pos["name"].clone(), + wage: bigdecimal::BigDecimal::from_str( + pos["wage"].as_str(), + ) + .unwrap(), + }) + .await; + }) + } + ModalStatus::Edit => { + let pos = self.process_position_state.data.clone(); + self.rt.block_on(async { + self.db_oper + .update_position(Position { + id: pos["id"].parse::().unwrap(), + name: pos["name"].clone(), + wage: bigdecimal::BigDecimal::from_str( + pos["wage"].as_str(), + ) + .unwrap(), + }) + .await; + }) + } + ModalStatus::Remove => { + let pos = self.process_position_state.data.clone(); + self.rt.block_on(async { + self.db_oper + .delete_position(Position { + id: pos["id"].parse::().unwrap(), + name: String::new(), + wage: BigDecimal::from(0), + }) + .await; + }); + } + } + self.update_positions(); + self.process_position_state.is_open = false; + } + }); + } + } +} + +impl egui_dock::TabViewer for WorkerTabViewer { + type Tab = Tab; + fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { + (&*tab.title).into() + } + fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { + match &tab.tab_type { + TabTypes::WorkerList => { + self.show_worker(ui) + }, + TabTypes::WorkerPosition => self.show_position(ui), + _ => { + ui.label("Nope"); + } + } + } + fn id(&mut self, tab: &mut Self::Tab) -> egui::Id { + egui::Id::new(&tab.title) + } + fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool { + TABS_CAN_BE_WINDOWS + } + fn is_closeable(&self, _tab: &Self::Tab) -> bool { + false + } +} +impl Default for WorkerTabViewer { + fn default() -> Self { + let rt = tokio::runtime::Runtime::new().unwrap(); + let db_oper = rt.block_on(async { DBOperator::new().await }); + let positions = Arc::new(RwLock::new( + rt.block_on(async { db_oper.get_position().await.unwrap() }), + )); + let mut pos_map: HashMap = HashMap::new(); + pos_map.extend(|| -> Vec<(String, String)> { + let pos = positions.read()[0].clone(); + vec![ + ("id".to_string(), pos.id.to_string()), + ("name".to_string(), pos.name.clone()), + ("wage".to_string(), pos.wage.to_string()), + ] + }()); + Self { + process_position_state: ModalWinState { + is_open: false, + can_finish: false, + data: pos_map, + status: ModalStatus::Add, + }, + workers: Arc::new(RwLock::new(Option::Some( + rt.block_on(async { db_oper.get_workers().await.unwrap() }), + ))), + positions: positions, + show_worker_add_modal: false, + show_worker_edit_modal: false, + show_position_add_modal: false, + show_position_delete_modal: false, + fire_worker_id: String::new(), + add_worker_name: String::new(), + add_worker_position: Position::default(), + add_worker_hire_date: String::new(), + can_add_worker: false, + can_edit_worker: false, + add_position_name: String::new(), + add_position_wage: String::new(), + delete_position: Position::default(), + + 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, + } + } +}