595 lines
25 KiB
Rust
595 lines
25 KiB
Rust
use bigdecimal::BigDecimal;
|
||
use egui::mutex::RwLock;
|
||
use egui_extras::{Column, TableBuilder};
|
||
use std::collections::HashMap;
|
||
use std::default::Default;
|
||
use std::str::FromStr;
|
||
use std::sync::Arc;
|
||
|
||
use crate::database::*;
|
||
use crate::models::{ModalStatus, ModalWinState, Position, Worker};
|
||
use crate::tab::*;
|
||
pub struct WorkerTabViewer {
|
||
db_oper: DBOperator,
|
||
workers: Arc<RwLock<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_worker_state: ModalWinState,
|
||
process_position_state: ModalWinState,
|
||
is_admin: bool,
|
||
}
|
||
|
||
impl WorkerTabViewer {
|
||
pub fn new(is_admin: bool) -> Self {
|
||
Self {
|
||
is_admin,
|
||
..Default::default()
|
||
}
|
||
}
|
||
fn update_workers(&mut self) {
|
||
self.workers = Arc::new(RwLock::new(
|
||
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.positions.read().clone().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().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()
|
||
.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 workers = Arc::new(RwLock::new(
|
||
rt.block_on(async { db_oper.get_workers().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()),
|
||
]
|
||
}());
|
||
let mut worker_map: HashMap<String, String> = HashMap::new();
|
||
worker_map.extend(|| -> Vec<(String, String)> {
|
||
let worker = workers.read()[0].clone();
|
||
vec![
|
||
("id".to_string(), worker.id.to_string()),
|
||
("full_name".to_string(), worker.full_name),
|
||
("position_id".to_string(), worker.position.id.to_string()),
|
||
(
|
||
"hire_date".to_string(),
|
||
worker.hire_date.date_naive().format("%d-%m-%Y").to_string(),
|
||
),
|
||
("is_fired".to_string(), worker.is_fired.to_string()),
|
||
]
|
||
}());
|
||
Self {
|
||
process_position_state: ModalWinState {
|
||
is_open: false,
|
||
can_finish: false,
|
||
data: pos_map,
|
||
status: ModalStatus::Add,
|
||
},
|
||
process_worker_state: ModalWinState {
|
||
is_open: false,
|
||
can_finish: false,
|
||
data: worker_map,
|
||
status: ModalStatus::Add,
|
||
},
|
||
workers,
|
||
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,
|
||
is_admin: false,
|
||
}
|
||
}
|
||
}
|