мямямя мямямя
parent
37d9ae5474
commit
0d558c1063
|
|
@ -306,6 +306,7 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -410,9 +410,21 @@ impl DBOperator {
|
||||||
.await
|
.await
|
||||||
.unwrap_or(Vec::new());
|
.unwrap_or(Vec::new());
|
||||||
|
|
||||||
let ret: Vec<Recipe> = Vec::new();
|
let mut 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> {
|
||||||
|
|
@ -420,7 +432,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 ret: Vec<RecipeElement> = Vec::new();
|
let mut 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);
|
||||||
|
|
@ -431,6 +443,7 @@ 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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(_, _) => {}
|
(_, _) => {}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ pub struct Salary {
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Hash)]
|
#[derive(Default, Clone, Hash, PartialEq, Eq)]
|
||||||
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)]
|
#[derive(Clone, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct Material {
|
pub struct Material {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -86,16 +86,18 @@ pub struct MaterialRow {
|
||||||
pub quantity: i32,
|
pub quantity: i32,
|
||||||
pub category_id: i32,
|
pub category_id: i32,
|
||||||
}
|
}
|
||||||
#[derive(sqlx::FromRow, Default, Clone, PartialEq)]
|
#[derive(sqlx::FromRow, Default, Clone, PartialEq, Eq, Hash)]
|
||||||
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 {
|
||||||
|
|
@ -103,7 +105,9 @@ 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,
|
||||||
|
|
@ -161,6 +165,23 @@ 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]
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,20 @@
|
||||||
use tokio::sync::RwLock;
|
use egui_extras::{Column, TableBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::DBOperator,
|
database::DBOperator,
|
||||||
models::{Equipment, Material, Recipe, RecipeElement},
|
models::{
|
||||||
|
ElementModalState, Equipment, Material, ModalStatus, Recipe, RecipeElement,
|
||||||
|
RecipeModalState,
|
||||||
|
},
|
||||||
tab::{Tab, TabTypes},
|
tab::{Tab, TabTypes},
|
||||||
};
|
};
|
||||||
use std::{default::Default, sync::Arc};
|
use egui::{Sense, mutex::RwLock};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
default::Default,
|
||||||
|
ops::Deref,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct RecipeTabViewer {
|
pub struct RecipeTabViewer {
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
|
|
@ -16,6 +25,9 @@ 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 {
|
||||||
|
|
@ -25,8 +37,156 @@ 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.label("Goida");
|
ui.horizontal(|ui| {
|
||||||
|
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 {
|
||||||
|
|
@ -51,11 +211,39 @@ 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 { is_admin: false,
|
Self {
|
||||||
|
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:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue