я допишу я допишу я тесты напишу я всё напишу и защищусь
parent
776f40cd11
commit
0c88a19a40
|
|
@ -174,7 +174,7 @@ impl eframe::App for App<'_> {
|
|||
|
||||
struct MainTabViewer {
|
||||
workers: Arc<RwLock<Vec<Worker>>>,
|
||||
equipment: Arc<RwLock<Option<Vec<Equipment>>>>,
|
||||
equipment: Arc<RwLock<Vec<Equipment>>>,
|
||||
salaries: Arc<RwLock<Vec<Salary>>>,
|
||||
|
||||
db_oper: DBOperator,
|
||||
|
|
@ -199,9 +199,9 @@ impl Default for MainTabViewer {
|
|||
workers: Arc::new(RwLock::new(
|
||||
rt.block_on(async { db_oper.get_workers().await.unwrap() }),
|
||||
)),
|
||||
equipment: Arc::new(RwLock::new(Option::Some(
|
||||
equipment: Arc::new(RwLock::new(
|
||||
rt.block_on(async { db_oper.get_equipment().await.unwrap() }),
|
||||
))),
|
||||
)),
|
||||
salaries: Arc::new(RwLock::new(
|
||||
rt.block_on(async { db_oper.get_salaries().await.unwrap() }),
|
||||
)),
|
||||
|
|
@ -268,6 +268,12 @@ impl MainTabViewer {
|
|||
.block_on(async { self.db_oper.get_salaries().await.unwrap() }),
|
||||
));
|
||||
}
|
||||
fn update_equipment(&mut self) {
|
||||
self.equipment = Arc::new(RwLock::new(
|
||||
self.rt
|
||||
.block_on(async { self.db_oper.get_equipment().await.unwrap() }),
|
||||
));
|
||||
}
|
||||
fn get_salary(&self) -> Salary {
|
||||
Salary {
|
||||
id: self
|
||||
|
|
@ -358,7 +364,7 @@ impl MainTabViewer {
|
|||
})
|
||||
.body(|mut body| {
|
||||
body.ui_mut().style_mut().interaction.selectable_labels = false;
|
||||
for eq in self.equipment.read().clone().unwrap().iter() {
|
||||
for eq in self.equipment.read().clone().iter() {
|
||||
body.row(20.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(&eq.name);
|
||||
|
|
@ -452,7 +458,7 @@ impl MainTabViewer {
|
|||
.unwrap()
|
||||
.clone()
|
||||
})
|
||||
.unwrap()
|
||||
.unwrap_or(&Worker::default())
|
||||
.full_name
|
||||
.clone();
|
||||
egui::ComboBox::new("process_equipment_combobox", "")
|
||||
|
|
@ -610,6 +616,8 @@ impl MainTabViewer {
|
|||
});
|
||||
}
|
||||
}
|
||||
self.equipment_modal_state.is_open = false;
|
||||
self.update_equipment();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use sqlx::mysql::MySqlPoolOptions;
|
|||
|
||||
use dotenvy::dotenv_override;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
// use crate::schema::equipment::dsl::*;
|
||||
// use crate::schema::worker::dsl::*;
|
||||
|
|
@ -448,11 +449,47 @@ impl DBOperator {
|
|||
ret.push(Recipe {
|
||||
id: pr.id,
|
||||
name: pr.name.clone(),
|
||||
elements: els,
|
||||
elements: els.into_iter().collect(),
|
||||
});
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
pub async fn add_recipe(&self, rec: Recipe) -> Result<u64, sqlx::Error> {
|
||||
let mut tx = self.pool.begin().await?;
|
||||
sqlx::query("INSERT INTO `recipe` (id,name) VALUES (?,?)")
|
||||
.bind(rec.id)
|
||||
.bind(rec.name)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let ret = sqlx::query("SELECT LAST_INSERT_ID();")
|
||||
.fetch_one(&mut *tx)
|
||||
.await?;
|
||||
match tx.commit().await {
|
||||
Ok(_) => Ok(ret.get(0)),
|
||||
Err(_) => Ok(0),
|
||||
}
|
||||
}
|
||||
pub async fn remove_recipe(&self, rec_id: i32) -> Result<bool, sqlx::Error> {
|
||||
match sqlx::query("DELETE FROM `recipe` WHERE id=?")
|
||||
.bind(rec_id)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(true),
|
||||
Err(_) => Ok(false),
|
||||
}
|
||||
}
|
||||
pub async fn update_recipe(&self, recipe: Recipe) -> Result<bool, sqlx::Error> {
|
||||
match sqlx::query("UPDATE Brewery.recipe SET name=? WHERE id=?;")
|
||||
.bind(recipe.name)
|
||||
.bind(recipe.id)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(true),
|
||||
Err(_) => Ok(false),
|
||||
}
|
||||
}
|
||||
pub async fn get_recipe_elements(&self) -> Result<Vec<RecipeElement>, sqlx::Error> {
|
||||
let pre_ret = sqlx::query_as::<_, RecipeElementRow>("SELECT id, recipe_id, material_id, equipment_id, quantity FROM Brewery.recipe_element;").fetch_all(&self.pool).await;
|
||||
|
||||
|
|
@ -477,6 +514,36 @@ impl DBOperator {
|
|||
}
|
||||
Ok(ret)
|
||||
}
|
||||
pub async fn add_recipe_elems(
|
||||
&self,
|
||||
elems: HashSet<RecipeElement>,
|
||||
rec_id: i32,
|
||||
) -> Result<bool, sqlx::Error> {
|
||||
let mut tx = self.pool.begin().await?;
|
||||
for el in elems.iter() {
|
||||
sqlx::query("INSERT INTO `recipe_element` (id, recipe_id, material_id, equipment_id, quantity) VALUES(0, ?, ?, ?, ?);")
|
||||
.bind(rec_id)
|
||||
.bind(el.material.id)
|
||||
.bind(el.equipment.id)
|
||||
.bind(el.quantity)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
match tx.commit().await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub async fn remove_recipe_elements(&self, rec_id: i32) -> Result<bool, sqlx::Error> {
|
||||
match sqlx::query("DELETE FROM `recipe_element` WHERE recipe_id=?")
|
||||
.bind(rec_id)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(true),
|
||||
Err(_) => Ok(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn estabilish_connection() -> Result<(), sqlx::Error> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ mod database;
|
|||
mod material_tab;
|
||||
mod models;
|
||||
mod payment_tab;
|
||||
mod production_tab;
|
||||
mod recipe_tab;
|
||||
mod reports;
|
||||
mod tab;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ pub struct RecipeElementRow {
|
|||
pub struct Recipe {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub elements: std::vec::Vec<RecipeElement>,
|
||||
pub elements: HashSet<RecipeElement>,
|
||||
}
|
||||
#[derive(FromRow)]
|
||||
pub struct RecipeRow {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
pub struct ProductionTabViewer {
|
||||
is_admin: bool,
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
use bigdecimal::ToPrimitive;
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -37,6 +38,12 @@ impl RecipeTabViewer {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
fn update_recipes(&mut self) {
|
||||
self.recipes =
|
||||
Arc::new(RwLock::new(self.rt.block_on(async {
|
||||
self.db_oper.get_recipes().await.unwrap_or(Vec::new())
|
||||
})));
|
||||
}
|
||||
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() {
|
||||
|
|
@ -79,7 +86,11 @@ impl RecipeTabViewer {
|
|||
});
|
||||
});
|
||||
if ui.button("Добавить").clicked() {
|
||||
|
||||
self.process_recipe_status
|
||||
.recipe
|
||||
.elements
|
||||
.insert(self.process_element_status.element.clone());
|
||||
self.process_element_status.is_open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -100,29 +111,99 @@ impl RecipeTabViewer {
|
|||
ui.end_row();
|
||||
|
||||
ui.label("Составляющие:");
|
||||
let text = match self.process_recipe_status.recipe.elements.len() {
|
||||
0 => "Пусто",
|
||||
1 => "1 элемент",
|
||||
2..=4 => &format!(
|
||||
"{} элемента",
|
||||
self.process_recipe_status.recipe.elements.len()
|
||||
),
|
||||
_ => &format!(
|
||||
"{} элементов",
|
||||
self.process_recipe_status.recipe.elements.len()
|
||||
),
|
||||
};
|
||||
egui::ComboBox::new("recipe_element_combobox", "")
|
||||
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
||||
.selected_text(text)
|
||||
.show_ui(ui, |ui| {
|
||||
if ui.button("Новый элемент").clicked() {
|
||||
self.process_element_status.is_open = true;
|
||||
self.process_element_status.status = ModalStatus::Add;
|
||||
self.process_element_status.element = RecipeElement::default();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
for el in self.process_recipe_status.recipe.elements.clone().iter() {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("x").clicked() {
|
||||
self.process_recipe_status.recipe.elements.remove(el);
|
||||
}
|
||||
ui.label(format!(
|
||||
"{} ({})\n{}",
|
||||
el.material.name, el.material.category.name, el.equipment.name
|
||||
));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
let btext = match self.process_recipe_status.status {
|
||||
ModalStatus::Add => "Добавить",
|
||||
ModalStatus::Edit => "Сохранить",
|
||||
ModalStatus::Remove => "Удалить",
|
||||
};
|
||||
if ui.button(btext).clicked() {
|
||||
match self.process_recipe_status.status {
|
||||
ModalStatus::Add => {
|
||||
self.rt.block_on(async {
|
||||
let a = self
|
||||
.db_oper
|
||||
.add_recipe(self.process_recipe_status.recipe.clone())
|
||||
.await
|
||||
.ok();
|
||||
self.db_oper
|
||||
.add_recipe_elems(
|
||||
self.process_recipe_status.recipe.elements.clone(),
|
||||
a.unwrap().to_i32().unwrap(),
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
ModalStatus::Edit => {
|
||||
self.rt.block_on(async {
|
||||
self.db_oper
|
||||
.update_recipe(self.process_recipe_status.recipe.clone())
|
||||
.await
|
||||
.ok();
|
||||
self.db_oper
|
||||
.remove_recipe_elements(self.process_recipe_status.recipe.id)
|
||||
.await
|
||||
.ok();
|
||||
self.db_oper
|
||||
.add_recipe_elems(
|
||||
self.process_recipe_status.recipe.elements.clone(),
|
||||
self.process_recipe_status.recipe.id,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
ModalStatus::Remove => {
|
||||
self.rt.block_on(async {
|
||||
self.db_oper
|
||||
.remove_recipe_elements(self.process_recipe_status.recipe.id)
|
||||
.await
|
||||
.ok();
|
||||
self.db_oper
|
||||
.remove_recipe(self.process_recipe_status.recipe.id)
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
self.update_recipes();
|
||||
self.process_recipe_status.is_open = false;
|
||||
}
|
||||
});
|
||||
if self.process_element_status.is_open {
|
||||
self.new_element_modal(ui);
|
||||
|
|
|
|||
Loading…
Reference in New Issue