BreweryControlSystem/code/src/worker_tab.rs

567 lines
24 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<RwLock<Option<Vec<Worker>>>>,
positions: Arc<RwLock<Vec<Position>>>,
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::<i32>().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::<i32>().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::<i32>().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<String, String> = 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,
}
}
}