Compare commits

..

No commits in common. "1c8aba9066d9d6cc9c661402c711af0b0a424c57" and "37d9ae54743db6397a93b5d739e7ccd5282e3c1d" have entirely different histories.

4 changed files with 15 additions and 362 deletions

View File

@ -306,7 +306,6 @@ impl MainTabViewer {
is_admin, is_admin,
worker_tabs: WorkerTabViewer::new(is_admin), worker_tabs: WorkerTabViewer::new(is_admin),
material_tabs: MaterialTabViewer::new(is_admin), material_tabs: MaterialTabViewer::new(is_admin),
recipe_tab: RecipeTabViewer::new(is_admin),
..Default::default() ..Default::default()
} }
} }
@ -494,106 +493,8 @@ impl MainTabViewer {
}; };
if ui.button(btext).clicked() { if ui.button(btext).clicked() {
match self.equipment_modal_state.status { match self.equipment_modal_state.status {
ModalStatus::Add => self.rt.block_on(async { ModalStatus::Add => {}
self.db_oper ModalStatus::Edit => {}
.add_equipment(Equipment {
id: 0,
name: self
.equipment_modal_state
.data
.get("name")
.unwrap_or(&String::new())
.clone(),
inv_number: self
.equipment_modal_state
.data
.get("inv_number")
.unwrap_or(&String::new())
.clone(),
maintenance_date: chrono::NaiveDate::from_str(
self.equipment_modal_state
.data
.get("maintenance_date")
.unwrap_or(&"1970.01.01".to_owned()),
)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(chrono::Local)
.unwrap(),
worker: self
.workers
.read()
.clone()
.iter()
.find(|w| {
&w.id.to_string()
== self
.equipment_modal_state
.data
.get("worker_id")
.unwrap_or(&"0".to_owned())
})
.unwrap()
.clone(),
is_written_off: false,
})
.await
.unwrap();
}),
ModalStatus::Edit => self.rt.block_on(async {
self.db_oper
.update_equipment(Equipment {
id: self
.equipment_modal_state
.data
.get("id")
.unwrap()
.parse::<i32>()
.unwrap(),
name: self
.equipment_modal_state
.data
.get("name")
.unwrap_or(&String::new())
.clone(),
inv_number: self
.equipment_modal_state
.data
.get("inv_number")
.unwrap_or(&String::new())
.clone(),
maintenance_date: chrono::NaiveDate::from_str(
self.equipment_modal_state
.data
.get("maintenance_date")
.unwrap_or(&"1970.01.01".to_owned()),
)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(chrono::Local)
.unwrap(),
worker: self
.workers
.read()
.clone()
.iter()
.find(|w| {
&w.id.to_string()
== self
.equipment_modal_state
.data
.get("worker_id")
.unwrap_or(&"0".to_owned())
})
.unwrap()
.clone(),
is_written_off: false,
})
.await
.unwrap();
}),
ModalStatus::Remove => { ModalStatus::Remove => {
self.rt.block_on(async { self.rt.block_on(async {
self.db_oper self.db_oper

View File

@ -78,32 +78,6 @@ impl DBOperator {
} }
Ok(rets) Ok(rets)
} }
pub async fn add_equipment(&self, equipment: Equipment) -> Result<bool, sqlx::Error> {
match sqlx::query("INSERT INTO `equipment` (id, inv_number, maintenance_date, worker_id, name, is_written_off) VALUES(0, ?, ?, ?, ?, 0);")
.bind(equipment.inv_number)
.bind(equipment.maintenance_date)
.bind(equipment.worker.id)
.bind(equipment.name)
.execute(&self.pool)
.await{
Ok(_) => Ok(true),
Err(_) => Ok(false)
}
}
pub async fn update_equipment(&self, equipment: Equipment) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE Brewery.equipment SET inv_number=?, maintenance_date=?, worker_id=?, name=?, is_written_off=? WHERE id=?;")
.bind(equipment.inv_number)
.bind(equipment.maintenance_date)
.bind(equipment.worker.id)
.bind(equipment.name)
.bind(equipment.is_written_off)
.bind(equipment.id)
.execute(&self.pool)
.await{
Ok(_) => Ok(true),
Err(_) => Ok(false)
}
}
pub async fn get_mcat(&self) -> Result<Vec<MaterialCategory>, sqlx::Error> { pub async fn get_mcat(&self) -> Result<Vec<MaterialCategory>, sqlx::Error> {
let rets = sqlx::query_as::<_, MaterialCategory>("SELECT * FROM `material_category`") let rets = sqlx::query_as::<_, MaterialCategory>("SELECT * FROM `material_category`")
.fetch_all(&self.pool) .fetch_all(&self.pool)
@ -436,21 +410,9 @@ impl DBOperator {
.await .await
.unwrap_or(Vec::new()); .unwrap_or(Vec::new());
let mut ret: Vec<Recipe> = Vec::new(); let ret: Vec<Recipe> = Vec::new();
let elements = self.get_recipe_elements().await.unwrap_or(Vec::new()); let elements = self.get_recipe_elements().await.unwrap_or(Vec::new());
for pr in pre_ret.iter() { for pr in pre_ret.iter() {}
let mut els: Vec<RecipeElement> = Vec::new();
for elem in elements.clone() {
if elem.recipe_id == pr.id {
els.push(elem.clone());
}
}
ret.push(Recipe {
id: pr.id,
name: pr.name.clone(),
elements: els,
});
}
Ok(ret) Ok(ret)
} }
pub async fn get_recipe_elements(&self) -> Result<Vec<RecipeElement>, sqlx::Error> { pub async fn get_recipe_elements(&self) -> Result<Vec<RecipeElement>, sqlx::Error> {
@ -458,7 +420,7 @@ impl DBOperator {
let mats = self.get_materials().await.unwrap(); let mats = self.get_materials().await.unwrap();
let eqs = self.get_equipment().await.unwrap(); let eqs = self.get_equipment().await.unwrap();
let mut ret: Vec<RecipeElement> = Vec::new(); let ret: Vec<RecipeElement> = Vec::new();
for re in pre_ret.unwrap().iter() { for re in pre_ret.unwrap().iter() {
let mat = mats.iter().find(|m| m.id == re.material_id); let mat = mats.iter().find(|m| m.id == re.material_id);
let eq = eqs.iter().find(|e| e.id == re.equipment_id); let eq = eqs.iter().find(|e| e.id == re.equipment_id);
@ -469,7 +431,6 @@ impl DBOperator {
material: m.clone(), material: m.clone(),
equipment: e.clone(), equipment: e.clone(),
quantity: re.quantity, quantity: re.quantity,
recipe_id: re.recipe_id,
}); });
} }
(_, _) => {} (_, _) => {}

View File

@ -54,7 +54,7 @@ pub struct Salary {
pub comment: String, pub comment: String,
} }
#[derive(Default, Clone, Hash, PartialEq, Eq)] #[derive(Default, Clone, Hash)]
pub struct Equipment { pub struct Equipment {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -72,7 +72,7 @@ pub struct EquipmentRow {
pub worker_id: i32, pub worker_id: i32,
pub is_written_off: bool, pub is_written_off: bool,
} }
#[derive(Clone, PartialEq, Eq, Hash, Default)] #[derive(Clone)]
pub struct Material { pub struct Material {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -86,18 +86,16 @@ pub struct MaterialRow {
pub quantity: i32, pub quantity: i32,
pub category_id: i32, pub category_id: i32,
} }
#[derive(sqlx::FromRow, Default, Clone, PartialEq, Eq, Hash)] #[derive(sqlx::FromRow, Default, Clone, PartialEq)]
pub struct MaterialCategory { pub struct MaterialCategory {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(Clone, PartialEq, Eq, Hash, Default)]
pub struct RecipeElement { pub struct RecipeElement {
pub id: i32, pub id: i32,
pub material: Material, pub material: Material,
pub equipment: Equipment, pub equipment: Equipment,
pub quantity: i32, pub quantity: i32,
pub recipe_id: i32,
} }
#[derive(FromRow)] #[derive(FromRow)]
pub struct RecipeElementRow { pub struct RecipeElementRow {
@ -105,9 +103,7 @@ pub struct RecipeElementRow {
pub material_id: i32, pub material_id: i32,
pub equipment_id: i32, pub equipment_id: i32,
pub quantity: i32, pub quantity: i32,
pub recipe_id: i32,
} }
#[derive(Default, Clone)]
pub struct Recipe { pub struct Recipe {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -165,23 +161,6 @@ pub struct SalaryModalState {
pub status: ModalStatus, pub status: ModalStatus,
} }
#[derive(Default)]
pub struct RecipeModalState {
pub is_open: bool,
pub can_finish: bool,
pub recipe: Recipe,
pub elements: HashSet<RecipeElement>,
pub status: ModalStatus,
}
#[derive(Default)]
pub struct ElementModalState {
pub is_open: bool,
pub can_finish: bool,
pub element: RecipeElement,
pub status: ModalStatus,
}
#[derive(Default, PartialEq)] #[derive(Default, PartialEq)]
pub enum ModalStatus { pub enum ModalStatus {
#[default] #[default]

View File

@ -1,20 +1,11 @@
use egui_extras::{Column, TableBuilder}; use tokio::sync::RwLock;
use crate::{ use crate::{
database::DBOperator, database::DBOperator,
models::{ models::{Equipment, Material, Recipe, RecipeElement},
ElementModalState, Equipment, Material, ModalStatus, Recipe, RecipeElement,
RecipeModalState,
},
tab::{Tab, TabTypes}, tab::{Tab, TabTypes},
}; };
use egui::{Sense, mutex::RwLock}; use std::{default::Default, sync::Arc};
use std::{
collections::{HashMap, HashSet},
default::Default,
ops::Deref,
sync::Arc,
};
pub struct RecipeTabViewer { pub struct RecipeTabViewer {
is_admin: bool, is_admin: bool,
@ -25,9 +16,6 @@ pub struct RecipeTabViewer {
recipe_elements: Arc<RwLock<Vec<RecipeElement>>>, recipe_elements: Arc<RwLock<Vec<RecipeElement>>>,
materials: Arc<RwLock<Vec<Material>>>, materials: Arc<RwLock<Vec<Material>>>,
equipment: Arc<RwLock<Vec<Equipment>>>, equipment: Arc<RwLock<Vec<Equipment>>>,
process_recipe_status: RecipeModalState,
process_element_status: ElementModalState,
} }
impl RecipeTabViewer { impl RecipeTabViewer {
@ -37,156 +25,8 @@ impl RecipeTabViewer {
..Default::default() ..Default::default()
} }
} }
fn new_element_modal(&mut self, ui: &mut egui::Ui) {
egui::Modal::new(egui::Id::new("new_element_modal")).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_element_status.is_open = false;
}
ui.horizontal(|ui| {
ui.label("Использовать:");
egui::ComboBox::new("material_select_combobox", "")
.selected_text(&self.process_element_status.element.material.name)
.show_ui(ui, |ui| {
for mat in self.materials.read().clone().iter() {
ui.selectable_value(
&mut self.process_element_status.element.material,
mat.clone(),
&mat.name,
);
}
});
});
ui.horizontal(|ui| {
ui.label("В количестве:");
ui.add(
egui::DragValue::new(&mut self.process_element_status.element.quantity)
.range(0..=100),
);
ui.label("ед.");
});
ui.horizontal(|ui| {
ui.label("С использованием:");
egui::ComboBox::new("equipment_select_combobox", "")
.selected_text(&self.process_element_status.element.equipment.name)
.show_ui(ui, |ui| {
for eq in self.equipment.read().clone().iter() {
ui.selectable_value(
&mut self.process_element_status.element.equipment,
eq.clone(),
&eq.name,
);
}
});
});
if ui.button("Добавить").clicked(){
}
});
}
fn process_recipe_modal(&mut self, ui: &mut egui::Ui) {
egui::Modal::new(egui::Id::new("process_recipe_modal")).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_recipe_status.is_open = false;
}
egui::Grid::new("process_recipe_grid").show(ui, |ui| {
let size = ui.available_size();
ui.label("Название:");
ui.add_sized(
size,
egui::TextEdit::singleline(&mut self.process_recipe_status.recipe.name)
.hint_text("Пиво"),
);
ui.end_row();
ui.label("Составляющие:");
egui::ComboBox::new("recipe_element_combobox", "")
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
.show_ui(ui, |ui| {
if ui.button("Новый элемент").clicked() {
self.process_element_status.is_open = true;
self.process_element_status.status = ModalStatus::Add;
}
for el in self.recipe_elements.read().clone().iter() {
let resp = ui.checkbox(
&mut self.process_recipe_status.elements.contains(el),
&el.material.name,
);
if resp.clicked() {
if self.process_recipe_status.elements.contains(el) {
self.process_recipe_status.elements.remove(el);
} else {
self.process_recipe_status.elements.insert(el.clone());
}
}
}
});
});
});
if self.process_element_status.is_open {
self.new_element_modal(ui);
}
}
pub fn show_recipe_list(&mut self, ui: &mut egui::Ui) { pub fn show_recipe_list(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| { ui.label("Goida");
if self.is_admin {
if ui.button("Добавить").clicked() {
self.process_recipe_status.is_open = true;
self.process_recipe_status.recipe = Recipe::default();
self.process_recipe_status.status = ModalStatus::Add;
}
}
});
TableBuilder::new(ui)
.striped(true)
.columns(Column::auto(), 3)
.vscroll(false)
.sense(Sense::click())
.header(30.0, |mut head| {
head.col(|mut ui| {
ui.heading("Название");
});
head.col(|mut ui| {
ui.heading("Элементы");
});
})
.body(|mut body| {
for rec in self.recipes.read().iter() {
body.row(30.0, |mut row| {
row.col(|ui| {
ui.label(rec.name.clone());
});
row.col(|ui| {
let text = match rec.elements.len() {
0 => "Пусто",
1 => "1 элемент",
2..=4 => &format!("{} элемента", rec.elements.len()),
_ => &format!("{} элементов", rec.elements.len()),
};
ui.label(text);
});
if self.is_admin {
row.col(|ui| {
if ui.button("Удалить").clicked() {
self.process_recipe_status.is_open = true;
self.process_recipe_status.recipe = rec.clone();
self.process_recipe_status.status =
crate::models::ModalStatus::Remove;
}
});
}
if row.response().clicked() {
self.process_recipe_status.is_open = true;
self.process_recipe_status.recipe = rec.clone();
self.process_recipe_status.status = crate::models::ModalStatus::Edit;
}
});
}
});
if self.process_recipe_status.is_open {
self.process_recipe_modal(ui);
}
} }
} }
impl egui_dock::TabViewer for RecipeTabViewer { impl egui_dock::TabViewer for RecipeTabViewer {
@ -211,39 +51,11 @@ impl egui_dock::TabViewer for RecipeTabViewer {
impl Default for RecipeTabViewer { impl Default for RecipeTabViewer {
fn default() -> Self { fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let db_oper = rt.block_on(async { DBOperator::new().await }); let db_oper = rt.block_on(async{DBOperator::new().await});
Self { Self { is_admin: false,
is_admin: false,
recipes: Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_recipes().await.unwrap_or(Vec::new()) }),
)),
recipe_elements: Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_recipe_elements().await.unwrap_or(Vec::new()) }),
)),
materials: Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_materials().await.unwrap_or(Vec::new()) }),
)),
equipment: Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_equipment().await.unwrap_or(Vec::new()) }),
)),
process_recipe_status: RecipeModalState {
is_open: false,
can_finish: false,
recipe: Recipe::default(),
status: crate::models::ModalStatus::Add,
elements: HashSet::new(),
},
process_element_status: ElementModalState {
is_open: false,
can_finish: false,
element: RecipeElement::default(),
status: crate::models::ModalStatus::Add,
},
rt, rt,
db_oper, db_oper,
recipes:
} }
} }
} }