From a1cc8e4e86e26f46ee8e39fcc5139908d11598f3 Mon Sep 17 00:00:00 2001 From: ultrageese Date: Fri, 26 Jun 2026 10:42:57 +1000 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=BE=D0=B3=D0=B8=D1=82?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 89 ++++++++++------- code/src/database.rs | 131 ++++++++++++++++++------ code/src/material_tab.rs | 21 ++-- code/src/models.rs | 4 +- code/src/order_tab.rs | 210 +++++++++++++++++++++++++++++++-------- code/src/recipe_tab.rs | 42 ++++++-- code/src/worker_tab.rs | 130 ++++++++++++++++++------ ЧЁСДЕЛАТЬ | 4 +- 8 files changed, 471 insertions(+), 160 deletions(-) diff --git a/code/src/app.rs b/code/src/app.rs index c39ce9e..d8f1b66 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -664,31 +664,42 @@ impl MainTabViewer { .show_inside(ui, &mut self.order_tabs); } fn show_salary(&mut self, ui: &mut egui::Ui) { - /* - * Чё надо: - * 1. Список платежей. - */ - - if self.is_admin && ui.button("Добавить").clicked() { - self.salary_modal_state - .data - .insert("id".to_owned(), String::new()); - self.salary_modal_state - .data - .insert("worker_id".to_owned(), String::new()); - self.salary_modal_state - .data - .insert("salary_size".to_owned(), String::new()); - self.salary_modal_state - .data - .insert("salary_date".to_owned(), String::new()); - self.salary_modal_state - .data - .insert("comment".to_owned(), String::new()); - self.salary_modal_state.workers.clear(); - self.salary_modal_state.is_open = true; - self.salary_modal_state.status = ModalStatus::Add; - } + ui.horizontal(|ui| { + if self.is_admin && ui.button("Добавить").clicked() { + self.update_workers(); + self.salary_modal_state + .data + .insert("id".to_owned(), String::new()); + self.salary_modal_state + .data + .insert("worker_id".to_owned(), String::new()); + self.salary_modal_state + .data + .insert("salary_size".to_owned(), String::new()); + self.salary_modal_state + .data + .insert("salary_date".to_owned(), String::new()); + self.salary_modal_state + .data + .insert("comment".to_owned(), String::new()); + self.salary_modal_state.workers.clear(); + self.salary_modal_state.is_open = true; + self.salary_modal_state.status = ModalStatus::Add; + } + if ui.button("<-").clicked() { + if self.salaries_page > 0 { + self.salaries_page -= 1; + self.update_salary(); + } + } + ui.monospace(self.salaries_page.to_string()); + if ui.button("->").clicked() { + if self.salaries.read().len().to_i32().unwrap() == misc::ELEMENTS_PER_PAGE { + self.salaries_page += 1; + self.update_salary(); + } + } + }); TableBuilder::new(ui) .striped(true) .columns(Column::auto(), 5) @@ -795,19 +806,21 @@ impl MainTabViewer { .close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside) .show_ui(ui, |ui| { for wrkr in self.workers.read().clone().iter() { - let mut checked = - self.salary_modal_state.workers.contains(wrkr); - let res = ui.add(egui::Checkbox::new( - &mut checked, - &wrkr.full_name, - )); - if res.clicked() { - if checked { - self.salary_modal_state - .workers - .insert(wrkr.clone()); - } else { - self.salary_modal_state.workers.remove(wrkr); + if !wrkr.is_fired { + let mut checked = + self.salary_modal_state.workers.contains(wrkr); + let res = ui.add(egui::Checkbox::new( + &mut checked, + &wrkr.full_name, + )); + if res.clicked() { + if checked { + self.salary_modal_state + .workers + .insert(wrkr.clone()); + } else { + self.salary_modal_state.workers.remove(wrkr); + } } } } diff --git a/code/src/database.rs b/code/src/database.rs index 0a647ea..ce785c9 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -1,4 +1,5 @@ use bigdecimal::BigDecimal; +use bigdecimal::ToPrimitive; use chrono::DateTime; use sqlx::Row; use sqlx::mysql::MySqlPool; @@ -24,10 +25,17 @@ impl DBOperator { pool: MySqlPool::connect(&db_url).await.unwrap(), } } - pub async fn get_position(&self) -> Result, sqlx::Error> { - let rets: Vec = sqlx::query_as::<_, Position>("SELECT * FROM `position`") - .fetch_all(&self.pool) - .await?; + pub async fn get_positions( + &self, + start: i32, + length: i32, + ) -> Result, sqlx::Error> { + let rets: Vec = + sqlx::query_as::<_, Position>("SELECT * FROM `position` LIMIT ? OFFSET ?") + .bind(length) + .bind(start) + .fetch_all(&self.pool) + .await?; Ok(rets) } pub async fn get_position_by_id(&self, id: i32) -> Result { @@ -53,15 +61,11 @@ impl DBOperator { .fetch_all(&self.pool) .await?; let mut rets: Vec = Vec::new(); - let pos = self.get_position().await.unwrap(); for worker in pre_rets { - let mut ppos = Position::default(); - for position in pos.clone() { - if position.id == worker.position_id { - ppos = position.clone(); - break; - } - } + let ppos = self + .get_position_by_id(worker.position_id) + .await + .unwrap_or(Position::default()); rets.push(Worker { id: worker.id, full_name: worker.full_name, @@ -187,8 +191,14 @@ impl DBOperator { .await?; Ok(rets) } - pub async fn get_materials(&self) -> Result, sqlx::Error> { - let mats = sqlx::query_as::<_, MaterialRow>("SELECT * FROM `material`") + pub async fn get_materials( + &self, + start: i32, + length: i32, + ) -> Result, sqlx::Error> { + let mats = sqlx::query_as::<_, MaterialRow>("SELECT * FROM `material` LIMIT ? OFFSET ?") + .bind(length) + .bind(start) .fetch_all(&self.pool) .await?; let cats = self.get_mcat().await?; @@ -346,13 +356,16 @@ impl DBOperator { } pub async fn update_worker(&self, worker: Worker) -> Result { - match sqlx::query("UPDATE `worker` SET hire_date=?, is_fired=?, full_name=? WHERE id=?;") - .bind(worker.hire_date) - .bind(worker.is_fired) - .bind(worker.full_name) - .bind(worker.id) - .execute(&self.pool) - .await + match sqlx::query( + "UPDATE `worker` SET hire_date=?, is_fired=?, full_name=?, fire_date=? WHERE id=?;", + ) + .bind(worker.hire_date) + .bind(worker.is_fired) + .bind(worker.full_name) + .bind(worker.fire_date) + .bind(worker.id) + .execute(&self.pool) + .await { Ok(_) => Ok(true), Err(_) => Ok(false), @@ -587,6 +600,24 @@ impl DBOperator { Err(_) => Ok(false), } } + pub async fn get_mat_by_id(&self, mat_id: i32) -> Result { + let pret = sqlx::query_as::<_, MaterialRow>("SELECT * FROM material WHERE id=?") + .bind(mat_id) + .fetch_one(&self.pool) + .await?; + Ok(Material { + id: pret.id, + name: pret.name, + category: self.get_mcat_by_id(pret.category_id).await.unwrap(), + quantity: pret.quantity, + }) + } + pub async fn get_mcat_by_id(&self, mcat_id: i32) -> Result { + sqlx::query_as::<_, MaterialCategory>("SELECT * FROM material_category WHERE id=?") + .bind(mcat_id) + .fetch_one(&self.pool) + .await + } pub async fn update_recipe(&self, recipe: Recipe) -> Result { match sqlx::query("UPDATE `recipe` SET name=? WHERE id=?;") .bind(recipe.name) @@ -605,10 +636,9 @@ impl DBOperator { .fetch_all(&self.pool) .await; - let mats = self.get_materials().await.unwrap(); let mut ret: Vec = Vec::new(); for re in pre_ret.unwrap().iter() { - let mat = mats.iter().find(|m| m.id == re.material_id); + let mat = self.get_mat_by_id(re.material_id).await.ok(); let eq = self.get_equipment_by_id(re.equipment_id).await.ok(); match (mat, eq) { (Some(m), Some(e)) => { @@ -704,7 +734,7 @@ impl DBOperator { ret } pub async fn get_client_by_id(&self, id: i32) -> Result { - sqlx::query_as::<_, Client>("SELECT FROM `client` WHERE id=?") + sqlx::query_as::<_, Client>("SELECT * FROM `client` WHERE id=?") .bind(id) .fetch_one(&self.pool) .await @@ -799,17 +829,56 @@ impl DBOperator { .await?; Ok(ret) } - pub async fn add_order_element(&self, order_elem: OrderElement) -> Result<(), sqlx::Error> { - match sqlx::query("INSERT INTO order_element (order_id, product_id, quantity, total_amount) VALUES(?, ?, ?, ?);") - .bind(self.get_order_id_by_order_element_id(order_elem.id).await.unwrap()) - .bind(order_elem.product.id) - .bind(order_elem.quantity) - .bind(order_elem.total_price) - .execute(&self.pool).await{ + pub async fn add_order_element( + &self, + order_elems: BTreeSet, + order_id: i32, + ) -> Result<(), sqlx::Error> { + let mut tx = self.pool.begin().await?; + for el in order_elems.iter() { + sqlx::query("INSERT INTO order_element (order_id, product_id, quantity, total_amount) VALUES(?, ?, ?, ?);") + .bind(order_id) + .bind(el.product.id) + .bind(el.quantity) + .bind(el.total_price.clone()) + .execute(&mut *tx).await; + } + + match tx.commit().await { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + pub async fn remove_order_elements(&self, order_id: i32) -> Result<(), sqlx::Error> { + match sqlx::query("DELETE FROM order_element WHERE order_id=?") + .bind(order_id) + .execute(&self.pool) + .await + { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + pub async fn add_order(&self, order: Order, incoming: bool) -> Result { + let res = sqlx::query("INSERT INTO `order` (client_id, order_date, total_price, is_incoming) VALUES(?, ?, ?, ?);").bind(order.client.id).bind(order.order_date).bind(order.total_price).bind(incoming).execute(&self.pool).await?; + Ok(res.last_insert_id().to_i32().unwrap()) + } + pub async fn update_order(&self, order: Order, incoming: bool) -> Result<(), sqlx::Error> { + match sqlx::query("UPDATE `order` SET client_id=?, order_date=?, total_price=?, is_incoming=? WHERE id=?;").bind(order.client.id).bind(order.order_date).bind(order.total_price).bind(incoming).bind(order.id).execute(&self.pool).await{ Ok(_) => Ok(()), Err(e) => Err(e) } } + pub async fn remove_order(&self, order_id: i32) -> Result<(), sqlx::Error> { + match sqlx::query("DELETE FROM `order` WHERE id=?") + .bind(order_id) + .execute(&self.pool) + .await + { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } pub async fn get_clients(&self, start: i32, length: i32) -> Vec { let pret = sqlx::query_as::<_, Client>("SELECT * FROM client LIMIT ? OFFSET ?") .bind(length) diff --git a/code/src/material_tab.rs b/code/src/material_tab.rs index ca3cd5f..1b519f6 100644 --- a/code/src/material_tab.rs +++ b/code/src/material_tab.rs @@ -5,6 +5,7 @@ use egui_extras::{Column, TableBuilder}; use crate::{ database::DBOperator, + misc::ELEMENTS_PER_PAGE, models::{Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState}, tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes}, }; @@ -19,6 +20,8 @@ pub struct MaterialTabViewer { mat_cats: Arc>>, mats: Arc>>, is_admin: bool, + mat_page: i32, + mcat_page: i32, } impl MaterialTabViewer { pub fn new(is_admin: bool) -> Self { @@ -34,10 +37,12 @@ impl MaterialTabViewer { )); } fn update_materials(&mut self) { - self.mats = Arc::new(RwLock::new( - self.rt - .block_on(async { self.db_oper.get_materials().await.unwrap() }), - )); + self.mats = Arc::new(RwLock::new(self.rt.block_on(async { + self.db_oper + .get_materials(self.mat_page * ELEMENTS_PER_PAGE, ELEMENTS_PER_PAGE) + .await + .unwrap() + }))); } fn show_material(&mut self, ui: &mut egui::Ui) { ui.horizontal(|ui| { @@ -546,9 +551,9 @@ impl Default for MaterialTabViewer { 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() }), - )); + let mats = Arc::new(RwLock::new(rt.block_on(async { + db_oper.get_materials(0, ELEMENTS_PER_PAGE).await.unwrap() + }))); Self { db_oper, rt, @@ -588,6 +593,8 @@ impl Default for MaterialTabViewer { mat_cats, mats, is_admin: false, + mat_page: 0, + mcat_page: 0, } } } diff --git a/code/src/models.rs b/code/src/models.rs index efb2523..b03588c 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -131,7 +131,7 @@ pub struct Client { pub name: String, pub address: String, } -#[derive(Default, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Default, PartialEq, PartialOrd, Eq, Ord, Clone)] pub struct Order { pub id: i32, pub client: Client, @@ -159,7 +159,6 @@ pub struct OrderElementRow { pub product_id: i32, pub quantity: i32, pub total_price: BigDecimal, - pub is_incoming: bool, } #[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Product { @@ -213,6 +212,7 @@ pub struct WorkerModalState { pub worker: Worker, pub status: ModalStatus, pub old_pos: Position, + pub old_fired: bool, } #[derive(Default)] diff --git a/code/src/order_tab.rs b/code/src/order_tab.rs index c656298..fbd30f9 100644 --- a/code/src/order_tab.rs +++ b/code/src/order_tab.rs @@ -178,6 +178,7 @@ impl OrderTabViewer { ui.horizontal(|ui| { if self.is_admin { if ui.button("Добавить").clicked() { + self.update_clients(); self.process_order_state.is_open = true; self.process_order_state.order = Order::default(); } @@ -226,9 +227,9 @@ impl OrderTabViewer { .header(25.0, |mut heading| { heading.col(|ui| { ui.heading(if incoming_orders { - "Заказчик" + "Заказчик " } else { - "Клиент" + "Клиент " }); }); heading.col(|ui| { @@ -240,9 +241,13 @@ impl OrderTabViewer { heading.col(|ui| { ui.heading("Дата создания"); }); + heading.col(|ui| { + ui.heading(" "); + }); }) .body(|mut body| { for or in orders.read().iter() { + body.ui_mut().style_mut().interaction.selectable_labels = false; body.row(25.0, |mut row| { let len = orders.read().iter().clone().len(); row.col(|ui| { @@ -260,7 +265,21 @@ impl OrderTabViewer { row.col(|ui| { ui.label(or.order_date.date_naive().to_string()); }); - row.col(|ui| if ui.button("Удалить").clicked() {}); + if self.is_admin { + row.col(|ui| { + if ui.button("Удалить").clicked() { + self.process_order_state.is_open = true; + self.process_order_state.order = or.clone(); + self.process_order_state.status = ModalStatus::Remove; + } + }); + if row.response().double_clicked() { + self.update_clients(); + self.process_order_state.is_open = true; + self.process_order_state.order = or.clone(); + self.process_order_state.status = ModalStatus::Edit; + } + } }); } }); @@ -275,46 +294,155 @@ impl OrderTabViewer { ui.label(self.process_order_state.order.id.to_string()); ui.end_row(); } - - ui.label(if incoming_orders { - "Заказчик" - } else { - "Клиент" - }); - egui::ComboBox::new("select_client_combobox", "") - .selected_text(&self.process_order_state.order.client.name) - .show_ui(ui, |ui| {}); - ui.end_row(); - - ui.label("Элементы"); - egui::ComboBox::new("order_process_combobox", "") - .close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside) - .selected_text(match self.process_order_state.order.elements.len() { - 0 => "Пусто".to_owned(), - _ => format!("{} элем.", self.process_order_state.order.elements.len()), - }) - .show_ui(ui, |ui| { - if ui.button("Новый элемент").clicked() { - self.process_element_state.is_open = true; - self.process_element_state.status = ModalStatus::Add; - self.process_element_state.element = OrderElement::default(); - } - - for el in self.process_order_state.order.elements.clone().iter() { - ui.horizontal(|ui| { - if ui.button("x").clicked() { - self.process_order_state.order.elements.remove(el); - } - ui.label(format!( - "{} ({})\n{}/шт.", - el.product.recipe.name, - el.quantity, - el.product.price_per_unit - )); - }); - } + if self.process_order_state.status != ModalStatus::Remove { + ui.label(if incoming_orders { + "Заказчик" + } else { + "Клиент" }); + egui::ComboBox::new("select_client_combobox", "") + .selected_text(&self.process_order_state.order.client.name) + .show_ui(ui, |ui| { + ui.horizontal(|ui| { + if ui.button("<-").clicked() { + if self.client_page > 0 { + self.client_page -= 1; + } + } + ui.monospace(self.client_page.to_string()); + if ui.button("->").clicked() { + if self.clients.read().len().to_i32().unwrap() + == misc::ELEMENTS_PER_PAGE + { + self.client_page += 1; + } + } + }); + for cl in self.clients.read().iter() { + ui.selectable_value( + &mut self.process_order_state.order.client, + cl.clone(), + &cl.name, + ); + } + }); + ui.end_row(); + + ui.label("Элементы"); + egui::ComboBox::new("order_process_combobox", "") + .close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside) + .selected_text(match self.process_order_state.order.elements.len() { + 0 => "Пусто".to_owned(), + _ => format!( + "{} элем.", + self.process_order_state.order.elements.len() + ), + }) + .show_ui(ui, |ui| { + if ui.button("Новый элемент").clicked() { + self.process_element_state.is_open = true; + self.process_element_state.status = ModalStatus::Add; + self.process_element_state.element = OrderElement::default(); + } + + for el in self.process_order_state.order.elements.clone().iter() { + ui.horizontal(|ui| { + if ui.button("x").clicked() { + self.process_order_state.order.elements.remove(el); + } + ui.label(format!( + "{} ({})\n{}/шт.", + el.product.recipe.name, + el.quantity, + el.product.price_per_unit + )); + }); + } + }); + ui.end_row(); + ui.label("Дата заказа: "); + let ndate = self.process_order_state.order.order_date.date_naive(); + let mut date = misc::naivedate_to_jiff(ndate); + ui.add(egui_extras::DatePickerButton::new(&mut date)); + if self.process_order_state.order.order_date.date_naive() + != misc::jiff_to_naivedate(date) + { + self.process_order_state.order.order_date = + misc::jiff_to_naivedate(date) + .and_hms_opt(0, 0, 0) + .unwrap() + .and_local_timezone(chrono::Local) + .unwrap(); + } + } }); + let btext = match self.process_order_state.status { + ModalStatus::Add => "Добавить", + ModalStatus::Edit => "Сохранить", + ModalStatus::Remove => "Удалить", + }; + self.process_order_state.can_finish = match self.process_order_state.status { + ModalStatus::Remove => true, + _ => { + self.process_order_state.order.client.name.len() > 0 + && self.process_order_state.order.elements.len() > 0 + } + }; + if ui + .add_enabled( + self.process_order_state.can_finish, + egui::Button::new(btext), + ) + .clicked() + { + self.rt.block_on(async { + match self.process_order_state.status { + ModalStatus::Add => { + let id = self + .db_oper + .add_order( + self.process_order_state.order.clone(), + incoming_orders, + ) + .await + .unwrap(); + self.db_oper + .add_order_element( + self.process_order_state.order.elements.clone(), + id, + ) + .await; + } + ModalStatus::Edit => { + self.db_oper + .remove_order_elements(self.process_order_state.order.id) + .await; + self.db_oper + .update_order( + self.process_order_state.order.clone(), + incoming_orders, + ) + .await; + self.db_oper + .add_order_element( + self.process_order_state.order.elements.clone(), + self.process_order_state.order.id, + ) + .await; + } + ModalStatus::Remove => { + self.db_oper + .remove_order_elements(self.process_order_state.order.id) + .await; + self.db_oper + .remove_order(self.process_order_state.order.id) + .await; + } + } + }); + self.update_orders(); + self.process_order_state.is_open = false; + } }); } if self.process_element_state.is_open { diff --git a/code/src/recipe_tab.rs b/code/src/recipe_tab.rs index 344ba0d..b10994a 100644 --- a/code/src/recipe_tab.rs +++ b/code/src/recipe_tab.rs @@ -3,10 +3,10 @@ use egui_extras::{Column, TableBuilder}; use crate::{ database::DBOperator, - misc, + misc::{self, ELEMENTS_PER_PAGE}, models::{ - RecipeElementModalState, Equipment, Material, ModalStatus, Product, ProductModalState, Recipe, - RecipeElement, RecipeModalState, + Equipment, Material, ModalStatus, Product, ProductModalState, Recipe, RecipeElement, + RecipeElementModalState, RecipeModalState, }, tab::{self, Tab, TabTypes}, }; @@ -34,6 +34,7 @@ pub struct RecipeTabViewer { old_price: BigDecimal, product_page: i32, recipe_page: i32, + mat_page: i32, } impl RecipeTabViewer { @@ -68,6 +69,21 @@ impl RecipeTabViewer { egui::ComboBox::new("material_select_combobox", "") .selected_text(&self.process_element_status.element.material.name) .show_ui(ui, |ui| { + if ui.button("<-").clicked() { + if self.mat_page > 0 { + self.mat_page -= 1; + self.update_materials(); + } + } + ui.monospace(self.mat_page.to_string()); + if ui.button("->").clicked() { + if self.materials.read().len().to_i32().unwrap() + == misc::ELEMENTS_PER_PAGE + { + self.mat_page += 1; + self.update_materials(); + } + } for mat in self.materials.read().clone().iter() { ui.selectable_value( &mut self.process_element_status.element.material, @@ -370,6 +386,15 @@ impl RecipeTabViewer { } }); } + + fn update_materials(&mut self) { + self.materials = Arc::new(RwLock::new(self.rt.block_on(async { + self.db_oper + .get_materials(self.mat_page, ELEMENTS_PER_PAGE) + .await + .unwrap_or(Vec::new()) + }))) + } } impl egui_dock::TabViewer for RecipeTabViewer { type Tab = Tab; @@ -499,9 +524,12 @@ impl Default for RecipeTabViewer { .await .unwrap_or(Vec::new()) }))), - materials: Arc::new(RwLock::new( - rt.block_on(async { db_oper.get_materials().await.unwrap_or(Vec::new()) }), - )), + materials: Arc::new(RwLock::new(rt.block_on(async { + db_oper + .get_materials(0, ELEMENTS_PER_PAGE) + .await + .unwrap_or(Vec::new()) + }))), equipment: Arc::new(RwLock::new(rt.block_on(async { db_oper .get_equipment(0, 5, false) @@ -530,7 +558,7 @@ impl Default for RecipeTabViewer { product_page: 0, recipe_page: 0, - + mat_page: 0, rt, db_oper, } diff --git a/code/src/worker_tab.rs b/code/src/worker_tab.rs index 6db883d..15b9a87 100644 --- a/code/src/worker_tab.rs +++ b/code/src/worker_tab.rs @@ -1,4 +1,4 @@ -use bigdecimal::BigDecimal; +use bigdecimal::{BigDecimal, ToPrimitive}; use egui::mutex::RwLock; use egui_extras::{Column, TableBuilder}; use std::collections::HashMap; @@ -26,6 +26,7 @@ pub struct WorkerTabViewer { only_not_fired_workers: bool, workers_page: i32, + positions_page: i32, } impl WorkerTabViewer { @@ -39,7 +40,7 @@ impl WorkerTabViewer { self.workers = Arc::new(RwLock::new(self.rt.block_on(async { self.db_oper .get_workers( - self.workers_page, + self.workers_page * ELEMENTS_PER_PAGE, ELEMENTS_PER_PAGE, self.only_not_fired_workers, ) @@ -48,21 +49,42 @@ impl WorkerTabViewer { }))); } fn update_positions(&mut self) { - self.positions = Arc::new(RwLock::new( - self.rt - .block_on(async { self.db_oper.get_position().await.unwrap() }), - )); + self.positions = Arc::new(RwLock::new(self.rt.block_on(async { + self.db_oper + .get_positions(self.positions_page * ELEMENTS_PER_PAGE, ELEMENTS_PER_PAGE) + .await + .unwrap() + }))); } fn show_worker(&mut self, ui: &mut egui::Ui) { ui.horizontal(|ui| { - if ui.button("Добавить").clicked() { - self.process_worker_state.is_open = true; - self.process_worker_state.worker = Worker::default(); - }; - if ui.button("Обновить").clicked() { - self.update_workers(); + if self.is_admin { + if ui.button("Добавить").clicked() { + self.process_worker_state.is_open = true; + self.process_worker_state.worker = Worker::default(); + }; } + if ui.button("<-").clicked() { + if self.workers_page > 0 { + self.workers_page -= 1; + self.update_workers(); + } + } + ui.monospace(self.workers_page.to_string()); + if ui.button("->").clicked() { + if self.workers.read().len().to_i32().unwrap() == misc::ELEMENTS_PER_PAGE { + self.workers_page += 1; + self.update_workers(); + } + } + + if ui + .checkbox(&mut self.only_not_fired_workers, "Без уволенных") + .changed() + { + self.update_workers(); + }; }); if self.process_worker_state.is_open { let pos = self.process_worker_state.worker.position.clone(); @@ -90,6 +112,21 @@ impl WorkerTabViewer { &self.process_worker_state.worker.position.name }) .show_ui(ui, |ui| { + if ui.button("<-").clicked() { + if self.workers_page > 0 { + self.workers_page -= 1; + self.update_workers(); + } + } + ui.monospace(self.workers_page.to_string()); + if ui.button("->").clicked() { + if self.workers.read().len().to_i32().unwrap() + == misc::ELEMENTS_PER_PAGE + { + self.workers_page += 1; + self.update_workers(); + } + } for pos in self.positions.read().clone().iter() { ui.selectable_value( &mut self.process_worker_state.worker.position, @@ -165,6 +202,13 @@ impl WorkerTabViewer { .await .unwrap(); } + if self.process_worker_state.worker.is_fired + != self.process_worker_state.old_fired + { + self.process_worker_state.worker.fire_date = + Some(chrono::Local::now()); + } + self.db_oper .update_worker(self.process_worker_state.worker.clone()) .await @@ -214,13 +258,18 @@ impl WorkerTabViewer { ui.label(&wk.position.name); }); row.col(|ui| { - ui.label(if wk.is_fired { "Да" } else { "Нет" }); + ui.label(if wk.is_fired { + wk.fire_date.unwrap().date_naive().to_string() + } else { + "Нет".to_owned() + }); }); if row.response().double_clicked() { self.process_worker_state.is_open = true; self.process_worker_state.status = ModalStatus::Edit; self.process_worker_state.worker = wk.clone(); self.process_worker_state.old_pos = wk.position.clone(); + self.process_worker_state.old_fired = wk.is_fired.clone(); } }); } @@ -229,22 +278,34 @@ impl WorkerTabViewer { 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 self.is_admin { + 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(); + if ui.button("<-").clicked() { + if self.positions_page > 0 { + self.positions_page -= 1; + self.update_positions(); + } + } + ui.monospace(self.positions_page.to_string()); + if ui.button("->").clicked() { + if self.positions.read().len().to_i32().unwrap() == ELEMENTS_PER_PAGE { + self.positions_page += 1; + self.update_positions(); + } } }); TableBuilder::new(ui) @@ -368,6 +429,7 @@ impl WorkerTabViewer { 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 { @@ -378,7 +440,8 @@ impl WorkerTabViewer { ) .unwrap(), }) - .await; + .await + .unwrap(); }) } ModalStatus::Edit => { @@ -488,9 +551,10 @@ 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 positions = + Arc::new(RwLock::new(rt.block_on(async { + db_oper.get_positions(0, ELEMENTS_PER_PAGE).await.unwrap() + }))); let workers = Arc::new(RwLock::new(rt.block_on(async { db_oper .get_workers(0, misc::ELEMENTS_PER_PAGE, false) @@ -520,6 +584,7 @@ impl Default for WorkerTabViewer { process_worker_state: WorkerModalState { is_open: false, can_finish: false, + old_fired: worker.is_fired, worker, status: ModalStatus::Add, old_pos: Position::default(), @@ -533,6 +598,7 @@ impl Default for WorkerTabViewer { is_admin: false, only_not_fired_workers: false, workers_page: 0, + positions_page: 0, } } } diff --git a/ЧЁСДЕЛАТЬ b/ЧЁСДЕЛАТЬ index 039b35d..576e947 100644 --- a/ЧЁСДЕЛАТЬ +++ b/ЧЁСДЕЛАТЬ @@ -1,4 +1,4 @@ 1 - Добавить пагниацию там, где её ещё нет 2 - Доделать проверки при нажатии кнопок в модальных окнах -3 - Написать часть с клиентом -4 - доделать заказы +3 - Сделать отчёты +