439 lines
17 KiB
Rust
439 lines
17 KiB
Rust
use std::{collections::HashMap, default::Default, ops::Deref, str::FromStr, sync::Arc};
|
|
|
|
use crate::{
|
|
database::DBOperator,
|
|
material_tab::MaterialTabViewer,
|
|
models::{
|
|
Equipment, LoginModalState, Material, MaterialCategory, MaterialRow, ModalStatus,
|
|
ModalWinState, Position, Worker,
|
|
},
|
|
tab::*,
|
|
worker_tab::{self, *},
|
|
};
|
|
use egui::{TextBuffer, Vec2, mutex::RwLock};
|
|
use egui_dock::{DockArea, Style, TabViewer};
|
|
use egui_extras::{Column, TableBuilder};
|
|
use sha2::{Digest, Sha256};
|
|
use sqlx::types::BigDecimal;
|
|
|
|
pub struct App<'a> {
|
|
pub login_modal_state: LoginModalState<'a>,
|
|
pub tree: egui_dock::DockState<Tab>,
|
|
pub main_viewer: MainTabViewer,
|
|
pub db_oper: DBOperator,
|
|
pub rt: tokio::runtime::Runtime,
|
|
pub is_admin: bool,
|
|
}
|
|
|
|
impl Default for App<'_> {
|
|
fn default() -> Self {
|
|
let mut 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();
|
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
Self {
|
|
tree,
|
|
main_viewer,
|
|
login_modal_state: LoginModalState {
|
|
is_open: true,
|
|
data: HashMap::from([("login", String::new()), ("password", String::new())]),
|
|
status: crate::models::LoginStatus::Login,
|
|
..Default::default()
|
|
},
|
|
db_oper: rt.block_on(DBOperator::new()),
|
|
rt,
|
|
is_admin: false,
|
|
}
|
|
}
|
|
}
|
|
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) {
|
|
if self.login_modal_state.is_open {
|
|
egui::Modal::new(egui::Id::new("login_modal")).show(ui.ctx(), |ui| {
|
|
ui.label("Пройдите авторизацию:");
|
|
ui.add(
|
|
egui::TextEdit::singleline(
|
|
self.login_modal_state.data.get_mut("login").unwrap(),
|
|
)
|
|
.hint_text("Введите логин"),
|
|
);
|
|
ui.add(
|
|
egui::TextEdit::singleline(
|
|
self.login_modal_state.data.get_mut("password").unwrap(),
|
|
)
|
|
.password(true)
|
|
.hint_text("Пароль"),
|
|
);
|
|
if self.login_modal_state.fail {
|
|
ui.label(&self.login_modal_state.fail_message);
|
|
}
|
|
ui.vertical_centered(|ui| {
|
|
if ui.button("Авторизоваться").clicked()
|
|
|| ui.input(|i| i.key_pressed(egui::Key::Enter))
|
|
{
|
|
let uname = self.login_modal_state.data.get("login").unwrap().clone();
|
|
|
|
self.login_modal_state.fail = false;
|
|
let mut hashed_pass = Sha256::new();
|
|
hashed_pass.update(self.login_modal_state.data.get("password").unwrap());
|
|
let pass_hash = hex::encode(hashed_pass.finalize());
|
|
if self.rt.block_on(async {
|
|
self.db_oper
|
|
.check_password(uname.clone(), pass_hash)
|
|
.await
|
|
.unwrap()
|
|
}) {
|
|
self.login_modal_state.fail = false;
|
|
self.login_modal_state.status = crate::models::LoginStatus::Finished;
|
|
self.login_modal_state.is_open = false;
|
|
if self.rt.block_on(async {
|
|
self.db_oper.check_admin(uname.clone()).await.unwrap()
|
|
}) {
|
|
self.main_viewer.is_admin = true
|
|
} else {
|
|
self.main_viewer.is_admin = false;
|
|
}
|
|
} else {
|
|
self.login_modal_state.fail = true;
|
|
self.login_modal_state.fail_message =
|
|
"Неверные логин или пароль".to_string();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
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,
|
|
equipment_modal_state: ModalWinState,
|
|
is_dark_theme: bool,
|
|
interface_scale_ratio: f32,
|
|
is_admin: bool,
|
|
}
|
|
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,
|
|
|
|
equipment_modal_state: ModalWinState {
|
|
is_open: false,
|
|
can_finish: false,
|
|
data: HashMap::from([
|
|
("id".to_owned(), String::new()),
|
|
("inv_number".to_owned(), String::new()),
|
|
("maintenance_date".to_owned(), String::new()),
|
|
("worker_id".to_owned(), String::new()),
|
|
]),
|
|
status: ModalStatus::Add,
|
|
},
|
|
is_admin: false,
|
|
}
|
|
}
|
|
}
|
|
impl MainTabViewer {
|
|
fn new(is_admin: bool) -> Self {
|
|
Self {
|
|
is_admin,
|
|
worker_tabs: WorkerTabViewer::new(is_admin),
|
|
material_tabs: MaterialTabViewer::new(is_admin),
|
|
..Default::default()
|
|
}
|
|
}
|
|
fn show_equipment(&mut self, ui: &mut egui::Ui) {
|
|
if self.is_admin {
|
|
ui.horizontal(|ui| {
|
|
if ui.button("Добавить").clicked() {
|
|
self.equipment_modal_state.is_open = true;
|
|
self.equipment_modal_state.status = ModalStatus::Add;
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("id".into(), "0".into());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("name".into(), "".into());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("inv_numver".into(), "".into());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("worker_id".into(), "0".into());
|
|
}
|
|
});
|
|
}
|
|
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())
|
|
.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("Дата последнего\nтехобслуживания");
|
|
});
|
|
})
|
|
.body(|mut body| {
|
|
body.ui_mut().style_mut().interaction.selectable_labels = false;
|
|
for eq in self.equipment.read().clone().unwrap().iter() {
|
|
body.row(20.0, |mut row| {
|
|
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());
|
|
});
|
|
row.col(|ui| {
|
|
if self.is_admin {
|
|
if ui.button("Удалить").clicked() {
|
|
self.equipment_modal_state.is_open = true;
|
|
self.equipment_modal_state.status = ModalStatus::Remove;
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("id".into(), eq.id.to_string());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("name".into(), eq.name.clone());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("inv_numver".into(), eq.inv_number.clone());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("worker_id".into(), eq.worker.id.to_string());
|
|
}
|
|
}
|
|
});
|
|
if row.response().double_clicked() {
|
|
self.equipment_modal_state.is_open = true;
|
|
self.equipment_modal_state.status = ModalStatus::Edit;
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("id".into(), eq.id.to_string());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("name".into(), eq.name.clone());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("inv_numver".into(), eq.inv_number.clone());
|
|
self.equipment_modal_state
|
|
.data
|
|
.insert("worker_id".into(), eq.worker.id.to_string());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
if self.equipment_modal_state.is_open {
|
|
egui::Modal::new(egui::Id::new("process_equipment_modal")).show(ui.ctx(), |ui| {
|
|
if ui.button("Закрыть").clicked() {
|
|
self.equipment_modal_state.is_open = false;
|
|
}
|
|
if self.equipment_modal_state.status != ModalStatus::Remove {
|
|
egui::Grid::new("process_equipment_grid").show(ui, |ui| {
|
|
ui.label("Название");
|
|
let mut name = self.equipment_modal_state.data.get_mut("name").unwrap();
|
|
ui.add_sized(Vec2::new(200.0, 20.0), egui::TextEdit::singleline(name));
|
|
ui.end_row();
|
|
|
|
ui.label("Инв. номер");
|
|
let mut inv_num = self
|
|
.equipment_modal_state
|
|
.data
|
|
.get_mut("inv_number")
|
|
.unwrap();
|
|
ui.text_edit_singleline(inv_num);
|
|
ui.end_row();
|
|
|
|
ui.label("Ответственный");
|
|
// egui::ComboBox::new("process_equipment_combobox");
|
|
ui.end_row();
|
|
|
|
ui.label("Дата последнего\nтехобслуживания");
|
|
let mut maintenance = self
|
|
.equipment_modal_state
|
|
.data
|
|
.get_mut("maintenance_date")
|
|
.unwrap();
|
|
ui.text_edit_singleline(maintenance);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|