1311 lines
53 KiB
Rust
1311 lines
53 KiB
Rust
use std::{collections::HashMap, ops::Deref, sync::Arc};
|
||
|
||
use crate::{
|
||
database::DBOperator,
|
||
models::{
|
||
Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position,
|
||
Worker,
|
||
},
|
||
};
|
||
use egui::{TextBuffer, 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<Tab>,
|
||
pub main_viewer: MainTabViewer,
|
||
}
|
||
|
||
impl Default for App {
|
||
fn default() -> Self {
|
||
let tree = egui_dock::DockState::new(vec![
|
||
Tab {
|
||
tab_type: TabTypes::Equipment,
|
||
title: "Оборудование".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Material,
|
||
title: "Сырьё".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Worker,
|
||
title: "Сотрудники".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Salary,
|
||
title: "Выплаты".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Recipe,
|
||
title: "Рецепты".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Product,
|
||
title: "Продукция".to_owned(),
|
||
},
|
||
Tab {
|
||
tab_type: TabTypes::Settings,
|
||
title: "Настройки".to_owned(),
|
||
},
|
||
]);
|
||
let main_viewer = MainTabViewer::default();
|
||
Self { tree, main_viewer }
|
||
}
|
||
}
|
||
impl App {
|
||
pub fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
||
Default::default()
|
||
}
|
||
}
|
||
|
||
impl eframe::App for App {
|
||
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||
DockArea::new(&mut self.tree)
|
||
.style(Style::from_egui(ui.style().as_ref()))
|
||
.show_inside(ui, &mut self.main_viewer);
|
||
}
|
||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||
if self.main_viewer.is_dark_theme {
|
||
ctx.set_visuals(egui::Visuals::dark());
|
||
} else {
|
||
ctx.set_visuals(egui::Visuals::light());
|
||
}
|
||
ctx.set_zoom_factor(self.main_viewer.interface_scale_ratio);
|
||
}
|
||
}
|
||
|
||
struct MainTabViewer {
|
||
positions: Arc<RwLock<Option<Vec<Position>>>>,
|
||
workers: Arc<RwLock<Option<Vec<Worker>>>>,
|
||
equipment: Arc<RwLock<Option<Vec<Equipment>>>>,
|
||
db_oper: DBOperator,
|
||
worker_tabs: WorkerTabViewer,
|
||
worker_tree: egui_dock::DockState<Tab>,
|
||
material_tabs: MaterialTabViewer,
|
||
material_tree: egui_dock::DockState<Tab>,
|
||
rt: tokio::runtime::Runtime,
|
||
is_dark_theme: bool,
|
||
interface_scale_ratio: f32,
|
||
}
|
||
impl Default for MainTabViewer {
|
||
fn default() -> Self {
|
||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||
let db_oper = rt.block_on(async { DBOperator::new().await });
|
||
Self {
|
||
positions: Arc::new(RwLock::new(Option::Some(
|
||
rt.block_on(async { db_oper.get_position().await.unwrap() }),
|
||
))),
|
||
workers: Arc::new(RwLock::new(Option::Some(
|
||
rt.block_on(async { db_oper.get_workers().await.unwrap() }),
|
||
))),
|
||
equipment: Arc::new(RwLock::new(Option::Some(
|
||
rt.block_on(async { db_oper.get_equipment().await.unwrap() }),
|
||
))),
|
||
db_oper,
|
||
worker_tabs: WorkerTabViewer::default(),
|
||
worker_tree: egui_dock::DockState::new(vec![
|
||
Tab {
|
||
title: "Работники".to_owned(),
|
||
tab_type: TabTypes::WorkerList,
|
||
},
|
||
Tab {
|
||
title: "Должности".to_owned(),
|
||
tab_type: TabTypes::WorkerPosition,
|
||
},
|
||
]),
|
||
material_tabs: MaterialTabViewer::default(),
|
||
material_tree: egui_dock::DockState::new(vec![
|
||
Tab {
|
||
title: "Сырьё".to_owned(),
|
||
tab_type: TabTypes::MaterialList,
|
||
},
|
||
Tab {
|
||
title: "Тип".to_owned(),
|
||
tab_type: TabTypes::MaterialTypeList,
|
||
},
|
||
]),
|
||
rt,
|
||
is_dark_theme: true,
|
||
interface_scale_ratio: 1.2,
|
||
}
|
||
}
|
||
}
|
||
impl MainTabViewer {
|
||
fn show_equipment(&mut self, ui: &mut egui::Ui) {
|
||
let mut table = TableBuilder::new(ui)
|
||
.striped(true)
|
||
.resizable(false)
|
||
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
|
||
.column(Column::auto())
|
||
.column(Column::auto())
|
||
.column(Column::auto())
|
||
.column(Column::auto())
|
||
.column(Column::auto())
|
||
.header(30.0, |mut header| {
|
||
header.col(|ui| {
|
||
ui.heading("ID");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Название");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Инв. номер");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Ответственный");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Дата последнего\nя техобслуживания");
|
||
});
|
||
})
|
||
.body(|mut body| {
|
||
for eq in self.equipment.read().clone().unwrap().iter() {
|
||
body.row(20.0, |mut row| {
|
||
row.col(|ui| {
|
||
ui.label(eq.id.to_string());
|
||
});
|
||
row.col(|ui| {
|
||
ui.label(&eq.name);
|
||
});
|
||
row.col(|ui| {
|
||
ui.label(&eq.inv_number);
|
||
});
|
||
row.col(|ui| {
|
||
ui.label(&eq.worker.full_name);
|
||
});
|
||
row.col(|ui| {
|
||
ui.label(eq.maintenance_date.date_naive().to_string());
|
||
});
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
fn show_worker(&mut self, ui: &mut egui::Ui) {
|
||
let id = ui.make_persistent_id("WorkerMenu");
|
||
DockArea::new(&mut self.worker_tree)
|
||
.style(Style::from_egui(ui.style().as_ref()))
|
||
.id(id)
|
||
.show_inside(ui, &mut self.worker_tabs);
|
||
}
|
||
fn show_material(&mut self, ui: &mut egui::Ui) {
|
||
let id = ui.make_persistent_id("MaterialMenu");
|
||
DockArea::new(&mut self.material_tree)
|
||
.id(id)
|
||
.show_inside(ui, &mut self.material_tabs);
|
||
}
|
||
fn show_salary(&mut self, ui: &mut egui::Ui) {
|
||
ui.label("Помогите");
|
||
}
|
||
fn show_settings(&mut self, ui: &mut egui::Ui) {
|
||
ui.checkbox(&mut self.is_dark_theme, "Тёмная тема");
|
||
|
||
ui.add(
|
||
egui::Slider::new(&mut self.interface_scale_ratio, 1.0..=2.0)
|
||
.text("Масштаб интерфейса"),
|
||
);
|
||
|
||
if ui.button("Сбросить Масштаб интерфейса").clicked() {
|
||
self.interface_scale_ratio = 1.2;
|
||
}
|
||
}
|
||
}
|
||
|
||
impl egui_dock::TabViewer for MainTabViewer {
|
||
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::Equipment => {
|
||
&self.show_equipment(ui);
|
||
}
|
||
TabTypes::Worker => {
|
||
&self.show_worker(ui);
|
||
}
|
||
TabTypes::Salary => {
|
||
&self.show_salary(ui);
|
||
}
|
||
TabTypes::Material => {
|
||
&self.show_material(ui);
|
||
}
|
||
TabTypes::Settings => {
|
||
&self.show_settings(ui);
|
||
}
|
||
_ => {
|
||
ui.label("This is not");
|
||
}
|
||
}
|
||
}
|
||
fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool {
|
||
TABS_CAN_BE_WINDOWS
|
||
}
|
||
fn is_closeable(&self, _tab: &Self::Tab) -> bool {
|
||
false
|
||
}
|
||
fn id(&mut self, tab: &mut Self::Tab) -> egui::Id {
|
||
egui::Id::new(&tab.title)
|
||
}
|
||
}
|
||
struct WorkerTabViewer {
|
||
db_oper: DBOperator,
|
||
workers: Arc<RwLock<Option<Vec<Worker>>>>,
|
||
positions: Arc<RwLock<Option<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,
|
||
}
|
||
|
||
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(Option::Some(
|
||
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;
|
||
}
|
||
if ui.button("Удалить").clicked() {
|
||
self.show_position_delete_modal = true;
|
||
self.delete_position = self.positions.read().clone().unwrap()[0].clone();
|
||
self.update_positions();
|
||
self.update_workers();
|
||
}
|
||
if ui.button("Обновить").clicked() {
|
||
self.update_positions();
|
||
}
|
||
});
|
||
for eq in self.positions.read().clone().unwrap().iter() {
|
||
ui.push_id(&eq.name, |ui| {
|
||
egui::CollapsingHeader::new(&eq.name)
|
||
.default_open(false)
|
||
.show(ui, |ui| {
|
||
ui.horizontal(|ui| {
|
||
ui.monospace("Оклад:");
|
||
ui.label(format!("${}", eq.wage));
|
||
});
|
||
})
|
||
});
|
||
}
|
||
if self.show_position_add_modal {
|
||
egui::Modal::new("add_position".into()).show(ui.ctx(), |ui| {
|
||
if ui.button("Закрыть").clicked() {
|
||
self.show_position_add_modal = false;
|
||
}
|
||
let mut size = ui.spacing().interact_size;
|
||
size.x = 200.0;
|
||
egui::Grid::new("add_pos_grid").show(ui, |ui| {
|
||
ui.label("Название");
|
||
ui.add_sized(size, |ui: &mut egui::Ui| {
|
||
ui.text_edit_singleline(&mut self.add_position_name)
|
||
});
|
||
|
||
ui.end_row();
|
||
|
||
ui.label("Оклад");
|
||
ui.text_edit_singleline(&mut self.add_position_wage);
|
||
ui.end_row();
|
||
});
|
||
let resp = ui.add_enabled(
|
||
self.add_position_name.len() > 0 && self.add_position_wage.len() > 0,
|
||
egui::Button::new("Добавить"),
|
||
);
|
||
if resp.clicked() {
|
||
self.rt.block_on(async {
|
||
self.db_oper
|
||
.add_position(Position {
|
||
id: 0,
|
||
name: self.add_position_name.clone(),
|
||
wage: BigDecimal::from(
|
||
self.add_position_wage.trim().parse::<i32>().unwrap(),
|
||
),
|
||
})
|
||
.await
|
||
.ok();
|
||
});
|
||
self.update_positions();
|
||
self.show_position_add_modal = false;
|
||
}
|
||
});
|
||
}
|
||
if self.show_position_delete_modal {
|
||
egui::Modal::new("delete_position".into()).show(ui.ctx(), |ui| {
|
||
if ui.button("Закрыть").clicked() {
|
||
self.show_position_delete_modal = false;
|
||
}
|
||
egui::ComboBox::from_label("Должность")
|
||
.selected_text(&self.delete_position.name)
|
||
.show_ui(ui, |ui| {
|
||
self.rt.block_on(async {
|
||
for pos in self.positions.read().clone().unwrap().iter() {
|
||
ui.selectable_value(
|
||
&mut self.delete_position,
|
||
pos.clone(),
|
||
&pos.name,
|
||
);
|
||
}
|
||
});
|
||
});
|
||
let can_delete = self
|
||
.workers
|
||
.read()
|
||
.clone()
|
||
.unwrap()
|
||
.iter()
|
||
.find(|wrkr| wrkr.position.id == self.delete_position.id)
|
||
.iter()
|
||
.len()
|
||
== 0;
|
||
if !can_delete {
|
||
ui.label(
|
||
egui::RichText::new("Есть сотрудники с этой должностью")
|
||
.color(egui::Color32::YELLOW),
|
||
);
|
||
}
|
||
let resp = ui.add_enabled(can_delete, egui::Button::new("Удалить"));
|
||
if resp.clicked() {
|
||
self.rt.block_on(async {
|
||
self.db_oper
|
||
.delete_position(self.delete_position.clone())
|
||
.await
|
||
.unwrap();
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
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 });
|
||
Self {
|
||
workers: Arc::new(RwLock::new(Option::Some(
|
||
rt.block_on(async { db_oper.get_workers().await.unwrap() }),
|
||
))),
|
||
positions: Arc::new(RwLock::new(Option::Some(
|
||
rt.block_on(async { db_oper.get_position().await.unwrap() }),
|
||
))),
|
||
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<RwLock<Vec<MaterialCategory>>>,
|
||
mats: Arc<RwLock<Vec<Material>>>,
|
||
}
|
||
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::Edit;
|
||
}
|
||
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())
|
||
.column(Column::auto())
|
||
.header(20.0, |mut header| {
|
||
header.col(|ui| {
|
||
ui.heading("ID");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Название");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Тип");
|
||
});
|
||
header.col(|ui| {
|
||
ui.heading("Количество");
|
||
});
|
||
})
|
||
.body(|mut body| {
|
||
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.id.to_string());
|
||
});
|
||
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 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::<i32>()
|
||
.unwrap(),
|
||
name: self
|
||
.process_material_state
|
||
.data
|
||
.get("name")
|
||
.unwrap()
|
||
.to_string(),
|
||
quantity: self
|
||
.process_material_state
|
||
.data
|
||
.get("quantity")
|
||
.unwrap()
|
||
.parse::<i32>()
|
||
.unwrap(),
|
||
category_id: self
|
||
.process_material_state
|
||
.data
|
||
.get("category_id")
|
||
.unwrap()
|
||
.parse::<i32>()
|
||
.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::<i32>()
|
||
.unwrap(),
|
||
name: self
|
||
.process_material_state
|
||
.data
|
||
.get("name")
|
||
.unwrap()
|
||
.to_string(),
|
||
quantity: self
|
||
.process_material_state
|
||
.data
|
||
.get("quantity")
|
||
.unwrap()
|
||
.parse::<i32>()
|
||
.unwrap(),
|
||
category_id: self
|
||
.process_material_state
|
||
.data
|
||
.get("category_id")
|
||
.unwrap()
|
||
.parse::<i32>()
|
||
.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::<i32>()
|
||
.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::Edit;
|
||
}
|
||
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::<i32>().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::<i32>().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())
|
||
.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);
|
||
});
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
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("Hello!");
|
||
}
|
||
}
|
||
}
|
||
}
|