Я устал и башка не варит

master
Алексей Алексей 2026-06-26 01:08:47 +10:00
parent f2c6de7137
commit 09ed906aa7
8 changed files with 242 additions and 49 deletions

1
code/Cargo.lock generated
View File

@ -777,6 +777,7 @@ dependencies = [
"egui_extras", "egui_extras",
"hex", "hex",
"jiff", "jiff",
"ordered-float",
"rust_decimal", "rust_decimal",
"rust_xlsxwriter", "rust_xlsxwriter",
"sha2 0.11.0", "sha2 0.11.0",

View File

@ -15,6 +15,7 @@ egui_dock = "0.19.1"
egui_extras = {version = "0.34.2", features = ["datepicker"]} egui_extras = {version = "0.34.2", features = ["datepicker"]}
hex = "0.4.3" hex = "0.4.3"
jiff = "0.2.29" jiff = "0.2.29"
ordered-float = "5.3.0"
rust_decimal = {version = "1.42.0", features = ["macros"]} rust_decimal = {version = "1.42.0", features = ["macros"]}
rust_xlsxwriter = {version="0.95.0",features=["chrono"]} rust_xlsxwriter = {version="0.95.0",features=["chrono"]}
sha2 = "0.11.0" sha2 = "0.11.0"

View File

@ -388,6 +388,7 @@ impl MainTabViewer {
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), recipe_tab: RecipeTabViewer::new(is_admin),
order_tabs: OrderTabViewer::new(is_admin),
..Default::default() ..Default::default()
} }
} }

View File

@ -5,6 +5,7 @@ use sqlx::mysql::MySqlPool;
use sqlx::mysql::MySqlPoolOptions; use sqlx::mysql::MySqlPoolOptions;
use dotenvy::dotenv_override; use dotenvy::dotenv_override;
use std::collections::BTreeSet;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::env; use std::env;
@ -524,7 +525,7 @@ impl DBOperator {
.await .await
.unwrap(); .unwrap();
let pelems = self.get_recipe_elements().await.unwrap_or(Vec::new()); let pelems = self.get_recipe_elements().await.unwrap_or(Vec::new());
let mut elems: HashSet<RecipeElement> = HashSet::new(); let mut elems: BTreeSet<RecipeElement> = BTreeSet::new();
for pr in pelems { for pr in pelems {
if pr.recipe_id == pret.id { if pr.recipe_id == pret.id {
elems.insert(pr.clone()); elems.insert(pr.clone());
@ -536,8 +537,10 @@ impl DBOperator {
elements: elems, elements: elems,
} }
} }
pub async fn get_recipes(&self) -> Result<Vec<Recipe>, sqlx::Error> { pub async fn get_recipes(&self, start: i32, length: i32) -> Result<Vec<Recipe>, sqlx::Error> {
let pre_ret = sqlx::query_as::<_, RecipeRow>("SELECT * FROM `recipe`") let pre_ret = sqlx::query_as::<_, RecipeRow>("SELECT * FROM `recipe` LIMIT ? OFFSET ?")
.bind(length)
.bind(start)
.fetch_all(&self.pool) .fetch_all(&self.pool)
.await .await
.unwrap_or(Vec::new()); .unwrap_or(Vec::new());
@ -624,7 +627,7 @@ impl DBOperator {
} }
pub async fn add_recipe_elems( pub async fn add_recipe_elems(
&self, &self,
elems: HashSet<RecipeElement>, elems: BTreeSet<RecipeElement>,
rec_id: i32, rec_id: i32,
) -> Result<bool, sqlx::Error> { ) -> Result<bool, sqlx::Error> {
let mut tx = self.pool.begin().await?; let mut tx = self.pool.begin().await?;
@ -665,11 +668,17 @@ impl DBOperator {
let mut ret: Vec<Order> = Vec::new(); let mut ret: Vec<Order> = Vec::new();
for or in pret { for or in pret {
let hs: BTreeSet<OrderElement> = self
.get_order_elements_by_order_id(or.id)
.await
.iter()
.cloned()
.collect();
ret.push(Order { ret.push(Order {
id: or.id, id: or.id,
order_date: or.order_date, order_date: or.order_date,
client: self.get_client_by_id(or.client_id).await.unwrap(), client: self.get_client_by_id(or.client_id).await.unwrap(),
elements: self.get_order_elements_by_order_id(or.id).await, elements: hs,
total_price: or.total_price, total_price: or.total_price,
}) })
} }
@ -706,17 +715,11 @@ impl DBOperator {
.fetch_one(&self.pool) .fetch_one(&self.pool)
.await .await
.unwrap(); .unwrap();
let mut recipe: Recipe = Recipe::default();
for rec in self.get_recipes().await.unwrap() {
if rec.id == pret.recipe_id {
recipe = rec.clone();
}
}
Product { Product {
id: pret.id, id: pret.id,
recipe, recipe: self.get_recipe_by_id(pret.recipe_id).await,
price_per_unit: pret.price_per_unit, price_per_unit: pret.price_per_unit,
volume: pret.volume, volume: ordered_float::OrderedFloat(pret.volume),
} }
} }
pub async fn get_products(&self, start: i32, length: i32) -> Vec<Product> { pub async fn get_products(&self, start: i32, length: i32) -> Vec<Product> {
@ -732,7 +735,7 @@ impl DBOperator {
ret.push(Product { ret.push(Product {
id: pr.id, id: pr.id,
recipe: self.get_recipe_by_id(pr.recipe_id).await, recipe: self.get_recipe_by_id(pr.recipe_id).await,
volume: pr.volume, volume: ordered_float::OrderedFloat(pr.volume),
price_per_unit: pr.price_per_unit, price_per_unit: pr.price_per_unit,
}); });
} }
@ -744,7 +747,7 @@ impl DBOperator {
"INSERT INTO `product` (recipe_id, volume, price_per_unit) VALUES(?, ?, ?);", "INSERT INTO `product` (recipe_id, volume, price_per_unit) VALUES(?, ?, ?);",
) )
.bind(prod.recipe.id) .bind(prod.recipe.id)
.bind(prod.volume) .bind(prod.volume.into_inner())
.bind(prod.price_per_unit) .bind(prod.price_per_unit)
.execute(&self.pool) .execute(&self.pool)
.await .await
@ -756,7 +759,7 @@ impl DBOperator {
pub async fn update_product(&self, prod: Product) -> Result<(), sqlx::Error> { pub async fn update_product(&self, prod: Product) -> Result<(), sqlx::Error> {
match sqlx::query("UPDATE product SET recipe_id=?, volume=?, price_per_unit=? WHERE id=?;") match sqlx::query("UPDATE product SET recipe_id=?, volume=?, price_per_unit=? WHERE id=?;")
.bind(prod.recipe.id) .bind(prod.recipe.id)
.bind(prod.volume) .bind(prod.volume.into_inner())
.bind(prod.price_per_unit) .bind(prod.price_per_unit)
.bind(prod.id) .bind(prod.id)
.execute(&self.pool) .execute(&self.pool)

View File

@ -1,4 +1,8 @@
use std::{any::TypeId, collections::HashSet, ops::Deref}; use std::{
any::TypeId,
collections::{BTreeSet, HashSet},
ops::Deref,
};
use chrono::Local; use chrono::Local;
use egui::TextBuffer; use egui::TextBuffer;
@ -7,7 +11,7 @@ use sqlx::{
types::{BigDecimal, chrono::DateTime}, types::{BigDecimal, chrono::DateTime},
}; };
#[derive(Clone, Hash, sqlx::FromRow, PartialEq, std::cmp::Eq)] #[derive(Clone, Hash, sqlx::FromRow, PartialEq, std::cmp::Eq, PartialOrd, Ord)]
pub struct Position { pub struct Position {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -22,7 +26,7 @@ impl Default for Position {
} }
} }
} }
#[derive(Default, Clone, Hash, std::cmp::Eq, PartialEq)] #[derive(Default, Clone, Hash, std::cmp::Eq, PartialEq, PartialOrd, Ord)]
pub struct Worker { pub struct Worker {
pub id: i32, pub id: i32,
pub full_name: String, pub full_name: String,
@ -57,7 +61,7 @@ pub struct Salary {
pub comment: String, pub comment: String,
} }
#[derive(Default, Clone, Hash, PartialEq, Eq)] #[derive(Default, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Equipment { pub struct Equipment {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -75,7 +79,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, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
pub struct Material { pub struct Material {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
@ -89,12 +93,12 @@ 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, Eq, Hash, PartialOrd, Ord)]
pub struct MaterialCategory { pub struct MaterialCategory {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(Clone, PartialEq, Eq, Hash, Default)] #[derive(Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
pub struct RecipeElement { pub struct RecipeElement {
pub id: i32, pub id: i32,
pub material: Material, pub material: Material,
@ -110,29 +114,30 @@ pub struct RecipeElementRow {
pub quantity: i32, pub quantity: i32,
pub recipe_id: i32, pub recipe_id: i32,
} }
#[derive(Default, Clone)] #[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Recipe { pub struct Recipe {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
pub elements: HashSet<RecipeElement>, pub elements: BTreeSet<RecipeElement>,
} }
#[derive(FromRow)] #[derive(FromRow)]
pub struct RecipeRow { pub struct RecipeRow {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(FromRow)] #[derive(FromRow, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Client { pub struct Client {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
pub address: String, pub address: String,
} }
#[derive(Default, PartialEq, PartialOrd, Eq, Ord)]
pub struct Order { pub struct Order {
pub id: i32, pub id: i32,
pub client: Client, pub client: Client,
pub order_date: chrono::DateTime<chrono::Local>, pub order_date: chrono::DateTime<chrono::Local>,
pub total_price: BigDecimal, pub total_price: BigDecimal,
pub elements: std::vec::Vec<OrderElement>, pub elements: BTreeSet<OrderElement>,
} }
#[derive(FromRow)] #[derive(FromRow)]
pub struct OrderRow { pub struct OrderRow {
@ -141,6 +146,7 @@ pub struct OrderRow {
pub order_date: chrono::DateTime<chrono::Local>, pub order_date: chrono::DateTime<chrono::Local>,
pub total_price: BigDecimal, pub total_price: BigDecimal,
} }
#[derive(PartialEq, PartialOrd, Ord, Eq, Clone, Default)]
pub struct OrderElement { pub struct OrderElement {
pub id: i32, pub id: i32,
pub product: Product, pub product: Product,
@ -155,11 +161,11 @@ pub struct OrderElementRow {
pub total_price: BigDecimal, pub total_price: BigDecimal,
pub is_incoming: bool, pub is_incoming: bool,
} }
#[derive(Default, Clone)] #[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Product { pub struct Product {
pub id: i32, pub id: i32,
pub recipe: Recipe, pub recipe: Recipe,
pub volume: f64, pub volume: ordered_float::OrderedFloat<f64>,
pub price_per_unit: BigDecimal, pub price_per_unit: BigDecimal,
} }
#[derive(FromRow)] #[derive(FromRow)]
@ -236,13 +242,20 @@ pub struct RecipeModalState {
} }
#[derive(Default)] #[derive(Default)]
pub struct ElementModalState { pub struct RecipeElementModalState {
pub is_open: bool, pub is_open: bool,
pub can_finish: bool, pub can_finish: bool,
pub element: RecipeElement, pub element: RecipeElement,
pub status: ModalStatus, pub status: ModalStatus,
} }
#[derive(Default)] #[derive(Default)]
pub struct OrderElementModalState {
pub is_open: bool,
pub can_finish: bool,
pub element: OrderElement,
pub status: ModalStatus,
}
#[derive(Default)]
pub struct ProductModalState { pub struct ProductModalState {
pub is_open: bool, pub is_open: bool,
pub can_finish: bool, pub can_finish: bool,
@ -250,6 +263,13 @@ pub struct ProductModalState {
pub recipe: Recipe, pub recipe: Recipe,
pub status: ModalStatus, pub status: ModalStatus,
} }
#[derive(Default)]
pub struct OrderModalState {
pub is_open: bool,
pub can_finish: bool,
pub order: Order,
pub status: ModalStatus,
}
#[derive(Default, PartialEq)] #[derive(Default, PartialEq)]
pub enum ModalStatus { pub enum ModalStatus {

View File

@ -1,12 +1,13 @@
use std::sync::Arc; use std::sync::Arc;
use bigdecimal::ToPrimitive;
use egui::{Sense, mutex::RwLock}; use egui::{Sense, mutex::RwLock};
use egui_extras::Column; use egui_extras::Column;
use crate::{ use crate::{
database::DBOperator, database::DBOperator,
misc, misc,
models::Order, models::{ModalStatus, Order, OrderElement, OrderElementModalState, OrderModalState},
tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes}, tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes},
}; };
@ -20,6 +21,8 @@ pub struct OrderTabViewer {
outcoming_order_page: i32, outcoming_order_page: i32,
is_admin: bool, is_admin: bool,
process_order_state: OrderModalState,
process_element_state: OrderElementModalState,
} }
impl OrderTabViewer { impl OrderTabViewer {
@ -29,21 +32,105 @@ impl OrderTabViewer {
..Default::default() ..Default::default()
} }
} }
fn update_orders(&mut self) {
self.rt.block_on(async {
self.incoming_orders = Arc::new(RwLock::new(
self.db_oper
.get_orders(
self.incoming_order_page * misc::ELEMENTS_PER_PAGE,
misc::ELEMENTS_PER_PAGE,
true,
)
.await,
));
self.outcoming_orders = Arc::new(RwLock::new(
self.db_oper
.get_orders(
self.outcoming_order_page * misc::ELEMENTS_PER_PAGE,
misc::ELEMENTS_PER_PAGE,
false,
)
.await,
));
});
}
fn show_order_element_modal(&mut self, ui: &mut egui::Ui) {
egui::Modal::new(egui::Id::new("order_element_modal")).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_element_state.is_open = false;
}
egui::Grid::new("order_element_grid").show(ui, |ui| {
ui.label("Продукт:");
///
ui.end_row();
ui.label("Количество:");
ui.add(
egui::Slider::new(&mut self.process_element_state.element.quantity, 0..=100)
.clamping(egui::SliderClamping::Never),
);
ui.end_row();
ui.label("Итоговая цена:");
ui.label(format!(
"{}",
self.process_element_state
.element
.product
.price_per_unit
.clone()
* self.process_element_state.element.quantity
))
});
});
}
pub fn show_orders(&mut self, ui: &mut egui::Ui, incoming_orders: bool) { pub fn show_orders(&mut self, ui: &mut egui::Ui, incoming_orders: bool) {
let orders = if incoming_orders { let orders = if incoming_orders {
&self.incoming_orders self.incoming_orders.clone()
} else { } else {
&self.outcoming_orders self.outcoming_orders.clone()
}; };
ui.horizontal(|ui| { ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {} if self.is_admin {
if ui.button("<-").clicked() {} if ui.button("Добавить").clicked() {
self.process_order_state.is_open = true;
self.process_order_state.order = Order::default();
}
}
if ui.button("<-").clicked() {
if incoming_orders {
if self.incoming_orders.read().len() > 0 {
self.incoming_order_page -= 1;
self.update_orders();
}
} else {
if self.outcoming_orders.read().len() > 0 {
self.outcoming_order_page -= 1;
self.update_orders();
}
}
}
ui.monospace(if incoming_orders { ui.monospace(if incoming_orders {
self.incoming_order_page.to_string() self.incoming_order_page.to_string()
} else { } else {
self.outcoming_order_page.to_string() self.outcoming_order_page.to_string()
}); });
if ui.button("->").clicked() {} if ui.button("->").clicked() {
if incoming_orders {
if self.incoming_orders.read().len().to_i32().unwrap()
== misc::ELEMENTS_PER_PAGE
{
self.incoming_order_page += 1;
}
} else {
if self.outcoming_orders.read().len().to_i32().unwrap()
== misc::ELEMENTS_PER_PAGE
{
self.outcoming_order_page += 1;
}
}
}
}); });
egui_extras::TableBuilder::new(ui) egui_extras::TableBuilder::new(ui)
@ -92,6 +179,58 @@ impl OrderTabViewer {
}); });
} }
}); });
if self.process_order_state.is_open {
egui::Modal::new(egui::Id::new("order_process_modal")).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_order_state.is_open = false
}
egui::Grid::new("order_process_grid").show(ui, |ui| {
ui.label("ID заказа:");
ui.label(self.process_order_state.order.id.to_string());
ui.end_row();
ui.label(if incoming_orders {
"Заказчик"
} else {
"Клиент"
});
//ВЫБОР КЛИЕНТА
ui.end_row();
ui.label("Элементы");
egui::ComboBox::new("order_process_combobox", "")
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
.selected_text(match self.process_order_state.order.elements.len() {
0 => "Пусто".to_owned(),
_ => format!("{} элем.", self.process_order_state.order.elements.len()),
})
.show_ui(ui, |ui| {
if ui.button("Новый элемент").clicked() {
self.process_element_state.is_open = true;
self.process_element_state.status = ModalStatus::Add;
self.process_element_state.element = OrderElement::default();
}
for el in self.process_order_state.order.elements.clone().iter() {
ui.horizontal(|ui| {
if ui.button("x").clicked() {
self.process_order_state.order.elements.remove(el);
}
ui.label(format!(
"{} ({})\n{}/шт.",
el.product.recipe.name,
el.quantity,
el.product.price_per_unit
));
});
}
});
});
});
}
if self.process_element_state.is_open {
self.show_order_element_modal(ui);
}
} }
} }
@ -140,6 +279,8 @@ impl Default for OrderTabViewer {
db_oper, db_oper,
rt, rt,
is_admin: false, is_admin: false,
process_order_state: OrderModalState::default(),
process_element_state: OrderElementModalState::default(),
} }
} }
} }

View File

@ -5,7 +5,7 @@ use crate::{
database::DBOperator, database::DBOperator,
misc, misc,
models::{ models::{
ElementModalState, Equipment, Material, ModalStatus, Product, ProductModalState, Recipe, RecipeElementModalState, Equipment, Material, ModalStatus, Product, ProductModalState, Recipe,
RecipeElement, RecipeModalState, RecipeElement, RecipeModalState,
}, },
tab::{self, Tab, TabTypes}, tab::{self, Tab, TabTypes},
@ -29,10 +29,11 @@ pub struct RecipeTabViewer {
products: Arc<RwLock<Vec<Product>>>, products: Arc<RwLock<Vec<Product>>>,
process_recipe_status: RecipeModalState, process_recipe_status: RecipeModalState,
process_element_status: ElementModalState, process_element_status: RecipeElementModalState,
process_product_status: ProductModalState, process_product_status: ProductModalState,
old_price: BigDecimal, old_price: BigDecimal,
product_page: i32, product_page: i32,
recipe_page: i32,
} }
impl RecipeTabViewer { impl RecipeTabViewer {
@ -43,10 +44,12 @@ impl RecipeTabViewer {
} }
} }
fn update_recipes(&mut self) { fn update_recipes(&mut self) {
self.recipes = self.recipes = Arc::new(RwLock::new(self.rt.block_on(async {
Arc::new(RwLock::new(self.rt.block_on(async { self.db_oper
self.db_oper.get_recipes().await.unwrap_or(Vec::new()) .get_recipes(self.recipe_page, misc::ELEMENTS_PER_PAGE)
}))); .await
.unwrap_or(Vec::new())
})));
} }
pub fn update_products(&mut self) { pub fn update_products(&mut self) {
self.products = Arc::new(RwLock::new(self.rt.block_on(async { self.products = Arc::new(RwLock::new(self.rt.block_on(async {
@ -229,6 +232,19 @@ impl RecipeTabViewer {
self.process_recipe_status.status = ModalStatus::Add; self.process_recipe_status.status = ModalStatus::Add;
} }
} }
if ui.button("<-").clicked() {
if self.recipe_page > 0 {
self.recipe_page -= 1;
self.update_recipes();
}
}
ui.monospace(self.recipe_page.to_string());
if ui.button("->").clicked() {
if self.recipes.read().len().to_i32().unwrap() > misc::ELEMENTS_PER_PAGE {
self.recipe_page += 1;
self.update_recipes();
}
}
}); });
TableBuilder::new(ui) TableBuilder::new(ui)
.striped(true) .striped(true)
@ -293,12 +309,14 @@ impl RecipeTabViewer {
if ui.button("<-").clicked() { if ui.button("<-").clicked() {
if self.product_page > 0 { if self.product_page > 0 {
self.product_page -= 1; self.product_page -= 1;
self.update_products();
} }
} }
ui.monospace(self.product_page.to_string()); ui.monospace(self.product_page.to_string());
if ui.button("->").clicked() { if ui.button("->").clicked() {
if self.products.read().len() == 5 { if self.products.read().len() == 5 {
self.product_page += 1; self.product_page += 1;
self.update_products();
} }
} }
}); });
@ -319,7 +337,7 @@ impl RecipeTabViewer {
ui.heading("Цена за ед."); ui.heading("Цена за ед.");
}); });
head.col(|ui| { head.col(|ui| {
ui.heading(" "); ui.heading(" ");
}); });
}) })
.body(|mut body| { .body(|mut body| {
@ -386,7 +404,7 @@ impl egui_dock::TabViewer for RecipeTabViewer {
ui.add_sized( ui.add_sized(
size, size,
egui::Slider::new( egui::Slider::new(
&mut self.process_product_status.product.volume, &mut self.process_product_status.product.volume.into_inner(),
0.0..=100.0, 0.0..=100.0,
) )
.clamping(egui::SliderClamping::Never), .clamping(egui::SliderClamping::Never),
@ -414,7 +432,7 @@ impl egui_dock::TabViewer for RecipeTabViewer {
ModalStatus::Remove => true, ModalStatus::Remove => true,
_ => { _ => {
self.process_product_status.product.price_per_unit > 0 self.process_product_status.product.price_per_unit > 0
&& self.process_product_status.product.volume > 0.0 && self.process_product_status.product.volume.into_inner() > 0.0
} }
}; };
let btext = match self.process_product_status.status { let btext = match self.process_product_status.status {
@ -475,9 +493,12 @@ impl Default for RecipeTabViewer {
Self { Self {
is_admin: false, is_admin: false,
recipes: Arc::new(RwLock::new( recipes: Arc::new(RwLock::new(rt.block_on(async {
rt.block_on(async { db_oper.get_recipes().await.unwrap_or(Vec::new()) }), db_oper
)), .get_recipes(0, misc::ELEMENTS_PER_PAGE)
.await
.unwrap_or(Vec::new())
}))),
materials: Arc::new(RwLock::new( materials: Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_materials().await.unwrap_or(Vec::new()) }), rt.block_on(async { db_oper.get_materials().await.unwrap_or(Vec::new()) }),
)), )),
@ -498,7 +519,7 @@ impl Default for RecipeTabViewer {
status: crate::models::ModalStatus::Add, status: crate::models::ModalStatus::Add,
elements: HashSet::new(), elements: HashSet::new(),
}, },
process_element_status: ElementModalState { process_element_status: RecipeElementModalState {
is_open: false, is_open: false,
can_finish: false, can_finish: false,
element: RecipeElement::default(), element: RecipeElement::default(),
@ -508,6 +529,7 @@ impl Default for RecipeTabViewer {
old_price: BigDecimal::default(), old_price: BigDecimal::default(),
product_page: 0, product_page: 0,
recipe_page: 0,
rt, rt,
db_oper, db_oper,

4
ЧЁСДЕЛАТЬ Normal file
View File

@ -0,0 +1,4 @@
1 - Добавить пагниацию там, где её ещё нет
2 - Доделать проверки при нажатии кнопок в модальных окнах
3 - Написать часть с клиентом
4 - доделать заказы