Compare commits
2 Commits
09ed906aa7
...
a1cc8e4e86
| Author | SHA1 | Date |
|---|---|---|
|
|
a1cc8e4e86 | |
|
|
69525d37d2 |
|
|
@ -6,6 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
client_tab::ClientTab,
|
||||||
database::DBOperator,
|
database::DBOperator,
|
||||||
material_tab::MaterialTabViewer,
|
material_tab::MaterialTabViewer,
|
||||||
misc::{self, ELEMENTS_PER_PAGE},
|
misc::{self, ELEMENTS_PER_PAGE},
|
||||||
|
|
@ -195,6 +196,7 @@ struct MainTabViewer {
|
||||||
recipe_tab: RecipeTabViewer,
|
recipe_tab: RecipeTabViewer,
|
||||||
order_tabs: OrderTabViewer,
|
order_tabs: OrderTabViewer,
|
||||||
order_tree: egui_dock::DockState<Tab>,
|
order_tree: egui_dock::DockState<Tab>,
|
||||||
|
client_tab: ClientTab,
|
||||||
|
|
||||||
equipment_modal_state: EquipmentModalState,
|
equipment_modal_state: EquipmentModalState,
|
||||||
salary_modal_state: SalaryModalState,
|
salary_modal_state: SalaryModalState,
|
||||||
|
|
@ -265,7 +267,7 @@ impl Default for MainTabViewer {
|
||||||
tab_type: TabTypes::Recipe,
|
tab_type: TabTypes::Recipe,
|
||||||
},
|
},
|
||||||
Tab {
|
Tab {
|
||||||
title: "Производство".to_owned(),
|
title: "Продукция".to_owned(),
|
||||||
tab_type: TabTypes::Product,
|
tab_type: TabTypes::Product,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|
@ -280,6 +282,7 @@ impl Default for MainTabViewer {
|
||||||
tab_type: TabTypes::OutcomingOrderList,
|
tab_type: TabTypes::OutcomingOrderList,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
client_tab: ClientTab::default(),
|
||||||
rt,
|
rt,
|
||||||
is_dark_theme: true,
|
is_dark_theme: true,
|
||||||
interface_scale_ratio: 1.2,
|
interface_scale_ratio: 1.2,
|
||||||
|
|
@ -389,6 +392,7 @@ impl MainTabViewer {
|
||||||
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),
|
order_tabs: OrderTabViewer::new(is_admin),
|
||||||
|
client_tab: ClientTab::new(is_admin),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -660,12 +664,9 @@ impl MainTabViewer {
|
||||||
.show_inside(ui, &mut self.order_tabs);
|
.show_inside(ui, &mut self.order_tabs);
|
||||||
}
|
}
|
||||||
fn show_salary(&mut self, ui: &mut egui::Ui) {
|
fn show_salary(&mut self, ui: &mut egui::Ui) {
|
||||||
/*
|
ui.horizontal(|ui| {
|
||||||
* Чё надо:
|
|
||||||
* 1. Список платежей.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if self.is_admin && ui.button("Добавить").clicked() {
|
if self.is_admin && ui.button("Добавить").clicked() {
|
||||||
|
self.update_workers();
|
||||||
self.salary_modal_state
|
self.salary_modal_state
|
||||||
.data
|
.data
|
||||||
.insert("id".to_owned(), String::new());
|
.insert("id".to_owned(), String::new());
|
||||||
|
|
@ -685,6 +686,20 @@ impl MainTabViewer {
|
||||||
self.salary_modal_state.is_open = true;
|
self.salary_modal_state.is_open = true;
|
||||||
self.salary_modal_state.status = ModalStatus::Add;
|
self.salary_modal_state.status = ModalStatus::Add;
|
||||||
}
|
}
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.salaries_page > 0 {
|
||||||
|
self.salaries_page -= 1;
|
||||||
|
self.update_salary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.salaries_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.salaries.read().len().to_i32().unwrap() == misc::ELEMENTS_PER_PAGE {
|
||||||
|
self.salaries_page += 1;
|
||||||
|
self.update_salary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.striped(true)
|
.striped(true)
|
||||||
.columns(Column::auto(), 5)
|
.columns(Column::auto(), 5)
|
||||||
|
|
@ -791,6 +806,7 @@ impl MainTabViewer {
|
||||||
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
for wrkr in self.workers.read().clone().iter() {
|
for wrkr in self.workers.read().clone().iter() {
|
||||||
|
if !wrkr.is_fired {
|
||||||
let mut checked =
|
let mut checked =
|
||||||
self.salary_modal_state.workers.contains(wrkr);
|
self.salary_modal_state.workers.contains(wrkr);
|
||||||
let res = ui.add(egui::Checkbox::new(
|
let res = ui.add(egui::Checkbox::new(
|
||||||
|
|
@ -807,6 +823,7 @@ impl MainTabViewer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
}
|
}
|
||||||
|
|
@ -1024,6 +1041,9 @@ impl egui_dock::TabViewer for MainTabViewer {
|
||||||
TabTypes::Order => {
|
TabTypes::Order => {
|
||||||
&self.show_order(ui);
|
&self.show_order(ui);
|
||||||
}
|
}
|
||||||
|
TabTypes::Client => {
|
||||||
|
&self.client_tab.show_tab(ui);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
ui.label("Welcome to Avalonia!");
|
ui.label("Welcome to Avalonia!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bigdecimal::ToPrimitive;
|
||||||
|
use egui::{Sense, mutex::RwLock};
|
||||||
|
use egui_extras::Column;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
database::DBOperator,
|
||||||
|
misc,
|
||||||
|
models::{Client, ClientModalState, ModalStatus},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ClientTab {
|
||||||
|
db_oper: DBOperator,
|
||||||
|
rt: tokio::runtime::Runtime,
|
||||||
|
|
||||||
|
clients: Arc<RwLock<Vec<Client>>>,
|
||||||
|
|
||||||
|
client_page: i32,
|
||||||
|
is_admin: bool,
|
||||||
|
|
||||||
|
process_client_state: ClientModalState,
|
||||||
|
}
|
||||||
|
impl ClientTab {
|
||||||
|
fn update_clients(&mut self) {
|
||||||
|
self.clients = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.get_clients(
|
||||||
|
self.client_page * misc::ELEMENTS_PER_PAGE,
|
||||||
|
misc::ELEMENTS_PER_PAGE,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
pub fn new(is_admin: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
is_admin,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn show_tab(&mut self, ui: &mut egui::Ui) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if self.is_admin {
|
||||||
|
if ui.button("Добавить").clicked() {
|
||||||
|
self.process_client_state.is_open = true;
|
||||||
|
self.process_client_state.status = ModalStatus::Add;
|
||||||
|
self.process_client_state.client = Client::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.client_page > 0 {
|
||||||
|
self.client_page -= 1;
|
||||||
|
self.update_clients();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.client_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.clients.read().len().to_i32().unwrap() == misc::ELEMENTS_PER_PAGE {
|
||||||
|
self.client_page += 1;
|
||||||
|
self.update_clients();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
egui_extras::TableBuilder::new(ui)
|
||||||
|
.striped(true)
|
||||||
|
.vscroll(false)
|
||||||
|
.sense(Sense::click())
|
||||||
|
.columns(Column::auto(), 3)
|
||||||
|
.header(25.0, |mut head| {
|
||||||
|
head.col(|ui| {
|
||||||
|
ui.heading("Название ");
|
||||||
|
});
|
||||||
|
head.col(|ui| {
|
||||||
|
ui.heading("Адрес");
|
||||||
|
});
|
||||||
|
head.col(|ui| {
|
||||||
|
ui.heading(" ");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.body(|mut body| {
|
||||||
|
for cl in self.clients.read().iter() {
|
||||||
|
body.row(25.0, |mut row| {
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label(cl.name.clone());
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label(cl.address.clone());
|
||||||
|
});
|
||||||
|
if self.is_admin {
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui.button("Удалить").clicked() {
|
||||||
|
self.process_client_state.is_open = true;
|
||||||
|
self.process_client_state.client = cl.clone();
|
||||||
|
self.process_client_state.status = ModalStatus::Remove;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if row.response().double_clicked() {
|
||||||
|
self.process_client_state.is_open = true;
|
||||||
|
self.process_client_state.client = cl.clone();
|
||||||
|
self.process_client_state.status = ModalStatus::Edit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if self.process_client_state.is_open {
|
||||||
|
egui::Modal::new(egui::Id::new("process_client_modal")).show(ui.ctx(), |ui| {
|
||||||
|
if ui.button("Закрыть").clicked() {
|
||||||
|
self.process_client_state.is_open = false;
|
||||||
|
}
|
||||||
|
if self.process_client_state.status != ModalStatus::Remove {
|
||||||
|
egui::Grid::new("process_client_grid").show(ui, |ui| {
|
||||||
|
let mut size = ui.available_size();
|
||||||
|
size.x = 80.0;
|
||||||
|
ui.label("Имя клиента:");
|
||||||
|
ui.add_sized(
|
||||||
|
size,
|
||||||
|
egui::TextEdit::singleline(&mut self.process_client_state.client.name),
|
||||||
|
);
|
||||||
|
ui.end_row();
|
||||||
|
|
||||||
|
ui.label("Адрес клиента:");
|
||||||
|
ui.add_sized(
|
||||||
|
size,
|
||||||
|
egui::TextEdit::singleline(
|
||||||
|
&mut self.process_client_state.client.address,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
ui.end_row();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ui.label(format!(
|
||||||
|
"Удалить {}?",
|
||||||
|
self.process_client_state.client.name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let btext = match self.process_client_state.status {
|
||||||
|
ModalStatus::Add => "Добавить",
|
||||||
|
ModalStatus::Edit => "Сохранить",
|
||||||
|
ModalStatus::Remove => "Удалить",
|
||||||
|
};
|
||||||
|
self.process_client_state.can_finish = match self.process_client_state.status {
|
||||||
|
ModalStatus::Remove => true,
|
||||||
|
_ => {
|
||||||
|
self.process_client_state.client.name.len() > 0
|
||||||
|
&& self.process_client_state.client.address.len() > 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
self.process_client_state.can_finish,
|
||||||
|
egui::Button::new(btext),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
match self.process_client_state.status {
|
||||||
|
ModalStatus::Add => {
|
||||||
|
self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.add_client(self.process_client_state.client.clone())
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ModalStatus::Edit => {
|
||||||
|
self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.update_client(self.process_client_state.client.clone())
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ModalStatus::Remove => {
|
||||||
|
self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.remove_client(self.process_client_state.client.id)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.update_clients();
|
||||||
|
self.process_client_state.is_open = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for ClientTab {
|
||||||
|
fn default() -> Self {
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
let db_oper = rt.block_on(async { DBOperator::new().await });
|
||||||
|
Self {
|
||||||
|
clients: Arc::new(RwLock::new(rt.block_on(async {
|
||||||
|
db_oper.get_clients(0, misc::ELEMENTS_PER_PAGE).await
|
||||||
|
}))),
|
||||||
|
db_oper,
|
||||||
|
rt,
|
||||||
|
is_admin: Default::default(),
|
||||||
|
client_page: 0,
|
||||||
|
process_client_state: ClientModalState::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use bigdecimal::BigDecimal;
|
use bigdecimal::BigDecimal;
|
||||||
|
use bigdecimal::ToPrimitive;
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
|
|
@ -24,8 +25,15 @@ impl DBOperator {
|
||||||
pool: MySqlPool::connect(&db_url).await.unwrap(),
|
pool: MySqlPool::connect(&db_url).await.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn get_position(&self) -> Result<Vec<Position>, sqlx::Error> {
|
pub async fn get_positions(
|
||||||
let rets: Vec<Position> = sqlx::query_as::<_, Position>("SELECT * FROM `position`")
|
&self,
|
||||||
|
start: i32,
|
||||||
|
length: i32,
|
||||||
|
) -> Result<Vec<Position>, sqlx::Error> {
|
||||||
|
let rets: Vec<Position> =
|
||||||
|
sqlx::query_as::<_, Position>("SELECT * FROM `position` LIMIT ? OFFSET ?")
|
||||||
|
.bind(length)
|
||||||
|
.bind(start)
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(rets)
|
Ok(rets)
|
||||||
|
|
@ -53,15 +61,11 @@ impl DBOperator {
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await?;
|
.await?;
|
||||||
let mut rets: Vec<Worker> = Vec::new();
|
let mut rets: Vec<Worker> = Vec::new();
|
||||||
let pos = self.get_position().await.unwrap();
|
|
||||||
for worker in pre_rets {
|
for worker in pre_rets {
|
||||||
let mut ppos = Position::default();
|
let ppos = self
|
||||||
for position in pos.clone() {
|
.get_position_by_id(worker.position_id)
|
||||||
if position.id == worker.position_id {
|
.await
|
||||||
ppos = position.clone();
|
.unwrap_or(Position::default());
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rets.push(Worker {
|
rets.push(Worker {
|
||||||
id: worker.id,
|
id: worker.id,
|
||||||
full_name: worker.full_name,
|
full_name: worker.full_name,
|
||||||
|
|
@ -187,8 +191,14 @@ impl DBOperator {
|
||||||
.await?;
|
.await?;
|
||||||
Ok(rets)
|
Ok(rets)
|
||||||
}
|
}
|
||||||
pub async fn get_materials(&self) -> Result<Vec<Material>, sqlx::Error> {
|
pub async fn get_materials(
|
||||||
let mats = sqlx::query_as::<_, MaterialRow>("SELECT * FROM `material`")
|
&self,
|
||||||
|
start: i32,
|
||||||
|
length: i32,
|
||||||
|
) -> Result<Vec<Material>, sqlx::Error> {
|
||||||
|
let mats = sqlx::query_as::<_, MaterialRow>("SELECT * FROM `material` LIMIT ? OFFSET ?")
|
||||||
|
.bind(length)
|
||||||
|
.bind(start)
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await?;
|
.await?;
|
||||||
let cats = self.get_mcat().await?;
|
let cats = self.get_mcat().await?;
|
||||||
|
|
@ -346,10 +356,13 @@ impl DBOperator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_worker(&self, worker: Worker) -> Result<bool, sqlx::Error> {
|
pub async fn update_worker(&self, worker: Worker) -> Result<bool, sqlx::Error> {
|
||||||
match sqlx::query("UPDATE `worker` SET hire_date=?, is_fired=?, full_name=? WHERE id=?;")
|
match sqlx::query(
|
||||||
|
"UPDATE `worker` SET hire_date=?, is_fired=?, full_name=?, fire_date=? WHERE id=?;",
|
||||||
|
)
|
||||||
.bind(worker.hire_date)
|
.bind(worker.hire_date)
|
||||||
.bind(worker.is_fired)
|
.bind(worker.is_fired)
|
||||||
.bind(worker.full_name)
|
.bind(worker.full_name)
|
||||||
|
.bind(worker.fire_date)
|
||||||
.bind(worker.id)
|
.bind(worker.id)
|
||||||
.execute(&self.pool)
|
.execute(&self.pool)
|
||||||
.await
|
.await
|
||||||
|
|
@ -587,6 +600,24 @@ impl DBOperator {
|
||||||
Err(_) => Ok(false),
|
Err(_) => Ok(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub async fn get_mat_by_id(&self, mat_id: i32) -> Result<Material, sqlx::Error> {
|
||||||
|
let pret = sqlx::query_as::<_, MaterialRow>("SELECT * FROM material WHERE id=?")
|
||||||
|
.bind(mat_id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(Material {
|
||||||
|
id: pret.id,
|
||||||
|
name: pret.name,
|
||||||
|
category: self.get_mcat_by_id(pret.category_id).await.unwrap(),
|
||||||
|
quantity: pret.quantity,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub async fn get_mcat_by_id(&self, mcat_id: i32) -> Result<MaterialCategory, sqlx::Error> {
|
||||||
|
sqlx::query_as::<_, MaterialCategory>("SELECT * FROM material_category WHERE id=?")
|
||||||
|
.bind(mcat_id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await
|
||||||
|
}
|
||||||
pub async fn update_recipe(&self, recipe: Recipe) -> Result<bool, sqlx::Error> {
|
pub async fn update_recipe(&self, recipe: Recipe) -> Result<bool, sqlx::Error> {
|
||||||
match sqlx::query("UPDATE `recipe` SET name=? WHERE id=?;")
|
match sqlx::query("UPDATE `recipe` SET name=? WHERE id=?;")
|
||||||
.bind(recipe.name)
|
.bind(recipe.name)
|
||||||
|
|
@ -605,10 +636,9 @@ impl DBOperator {
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let mats = self.get_materials().await.unwrap();
|
|
||||||
let mut 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 = self.get_mat_by_id(re.material_id).await.ok();
|
||||||
let eq = self.get_equipment_by_id(re.equipment_id).await.ok();
|
let eq = self.get_equipment_by_id(re.equipment_id).await.ok();
|
||||||
match (mat, eq) {
|
match (mat, eq) {
|
||||||
(Some(m), Some(e)) => {
|
(Some(m), Some(e)) => {
|
||||||
|
|
@ -704,7 +734,7 @@ impl DBOperator {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
pub async fn get_client_by_id(&self, id: i32) -> Result<Client, sqlx::Error> {
|
pub async fn get_client_by_id(&self, id: i32) -> Result<Client, sqlx::Error> {
|
||||||
sqlx::query_as::<_, Client>("SELECT FROM `client` WHERE id=?")
|
sqlx::query_as::<_, Client>("SELECT * FROM `client` WHERE id=?")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.fetch_one(&self.pool)
|
.fetch_one(&self.pool)
|
||||||
.await
|
.await
|
||||||
|
|
@ -789,6 +819,107 @@ impl DBOperator {
|
||||||
None => Err(sqlx::Error::BeginFailed),
|
None => Err(sqlx::Error::BeginFailed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub async fn get_order_id_by_order_element_id(
|
||||||
|
&self,
|
||||||
|
element_id: i32,
|
||||||
|
) -> Result<i32, sqlx::Error> {
|
||||||
|
let ret: i32 = sqlx::query_scalar("SELECT order_id FROM order_element WHERE id=?")
|
||||||
|
.bind(element_id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
pub async fn add_order_element(
|
||||||
|
&self,
|
||||||
|
order_elems: BTreeSet<OrderElement>,
|
||||||
|
order_id: i32,
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
let mut tx = self.pool.begin().await?;
|
||||||
|
for el in order_elems.iter() {
|
||||||
|
sqlx::query("INSERT INTO order_element (order_id, product_id, quantity, total_amount) VALUES(?, ?, ?, ?);")
|
||||||
|
.bind(order_id)
|
||||||
|
.bind(el.product.id)
|
||||||
|
.bind(el.quantity)
|
||||||
|
.bind(el.total_price.clone())
|
||||||
|
.execute(&mut *tx).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
match tx.commit().await {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn remove_order_elements(&self, order_id: i32) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("DELETE FROM order_element WHERE order_id=?")
|
||||||
|
.bind(order_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn add_order(&self, order: Order, incoming: bool) -> Result<i32, sqlx::Error> {
|
||||||
|
let res = sqlx::query("INSERT INTO `order` (client_id, order_date, total_price, is_incoming) VALUES(?, ?, ?, ?);").bind(order.client.id).bind(order.order_date).bind(order.total_price).bind(incoming).execute(&self.pool).await?;
|
||||||
|
Ok(res.last_insert_id().to_i32().unwrap())
|
||||||
|
}
|
||||||
|
pub async fn update_order(&self, order: Order, incoming: bool) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("UPDATE `order` SET client_id=?, order_date=?, total_price=?, is_incoming=? WHERE id=?;").bind(order.client.id).bind(order.order_date).bind(order.total_price).bind(incoming).bind(order.id).execute(&self.pool).await{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn remove_order(&self, order_id: i32) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("DELETE FROM `order` WHERE id=?")
|
||||||
|
.bind(order_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_clients(&self, start: i32, length: i32) -> Vec<Client> {
|
||||||
|
let pret = sqlx::query_as::<_, Client>("SELECT * FROM client LIMIT ? OFFSET ?")
|
||||||
|
.bind(length)
|
||||||
|
.bind(start)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await;
|
||||||
|
pret.unwrap()
|
||||||
|
}
|
||||||
|
pub async fn add_client(&self, client: Client) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("INSERT INTO client (name, address) VALUES(?, ?);")
|
||||||
|
.bind(client.name)
|
||||||
|
.bind(client.address)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn update_client(&self, client: Client) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("UPDATE client SET name=?, address=? WHERE id=?;")
|
||||||
|
.bind(client.name)
|
||||||
|
.bind(client.address)
|
||||||
|
.bind(client.id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn remove_client(&self, client_id: i32) -> Result<(), sqlx::Error> {
|
||||||
|
match sqlx::query("DELETE FROM client WHERE id=?")
|
||||||
|
.bind(client_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn estabilish_connection() -> Result<(), sqlx::Error> {
|
pub async fn estabilish_connection() -> Result<(), sqlx::Error> {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
|
mod client_tab;
|
||||||
mod database;
|
mod database;
|
||||||
mod material_tab;
|
mod material_tab;
|
||||||
|
mod misc;
|
||||||
mod models;
|
mod models;
|
||||||
mod order_tab;
|
mod order_tab;
|
||||||
mod recipe_tab;
|
mod recipe_tab;
|
||||||
mod reports;
|
mod reports;
|
||||||
mod tab;
|
mod tab;
|
||||||
mod worker_tab;
|
mod worker_tab;
|
||||||
mod misc;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use egui_extras::{Column, TableBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::DBOperator,
|
database::DBOperator,
|
||||||
|
misc::ELEMENTS_PER_PAGE,
|
||||||
models::{Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState},
|
models::{Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState},
|
||||||
tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes},
|
tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes},
|
||||||
};
|
};
|
||||||
|
|
@ -19,6 +20,8 @@ pub struct MaterialTabViewer {
|
||||||
mat_cats: Arc<RwLock<Vec<MaterialCategory>>>,
|
mat_cats: Arc<RwLock<Vec<MaterialCategory>>>,
|
||||||
mats: Arc<RwLock<Vec<Material>>>,
|
mats: Arc<RwLock<Vec<Material>>>,
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
|
mat_page: i32,
|
||||||
|
mcat_page: i32,
|
||||||
}
|
}
|
||||||
impl MaterialTabViewer {
|
impl MaterialTabViewer {
|
||||||
pub fn new(is_admin: bool) -> Self {
|
pub fn new(is_admin: bool) -> Self {
|
||||||
|
|
@ -34,10 +37,12 @@ impl MaterialTabViewer {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
fn update_materials(&mut self) {
|
fn update_materials(&mut self) {
|
||||||
self.mats = Arc::new(RwLock::new(
|
self.mats = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
self.rt
|
self.db_oper
|
||||||
.block_on(async { self.db_oper.get_materials().await.unwrap() }),
|
.get_materials(self.mat_page * ELEMENTS_PER_PAGE, ELEMENTS_PER_PAGE)
|
||||||
));
|
.await
|
||||||
|
.unwrap()
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
fn show_material(&mut self, ui: &mut egui::Ui) {
|
fn show_material(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|
@ -546,9 +551,9 @@ impl Default for MaterialTabViewer {
|
||||||
let mat_cats = Arc::new(RwLock::new(
|
let mat_cats = Arc::new(RwLock::new(
|
||||||
rt.block_on(async { db_oper.get_mcat().await.unwrap() }),
|
rt.block_on(async { db_oper.get_mcat().await.unwrap() }),
|
||||||
));
|
));
|
||||||
let mats = Arc::new(RwLock::new(
|
let mats = Arc::new(RwLock::new(rt.block_on(async {
|
||||||
rt.block_on(async { db_oper.get_materials().await.unwrap() }),
|
db_oper.get_materials(0, ELEMENTS_PER_PAGE).await.unwrap()
|
||||||
));
|
})));
|
||||||
Self {
|
Self {
|
||||||
db_oper,
|
db_oper,
|
||||||
rt,
|
rt,
|
||||||
|
|
@ -588,6 +593,8 @@ impl Default for MaterialTabViewer {
|
||||||
mat_cats,
|
mat_cats,
|
||||||
mats,
|
mats,
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
|
mat_page: 0,
|
||||||
|
mcat_page: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,13 +125,13 @@ pub struct RecipeRow {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
#[derive(FromRow, Default, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(FromRow, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||||
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)]
|
#[derive(Default, PartialEq, PartialOrd, Eq, Ord, Clone)]
|
||||||
pub struct Order {
|
pub struct Order {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
|
|
@ -159,7 +159,6 @@ pub struct OrderElementRow {
|
||||||
pub product_id: i32,
|
pub product_id: i32,
|
||||||
pub quantity: i32,
|
pub quantity: i32,
|
||||||
pub total_price: BigDecimal,
|
pub total_price: BigDecimal,
|
||||||
pub is_incoming: bool,
|
|
||||||
}
|
}
|
||||||
#[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
|
|
@ -213,6 +212,7 @@ pub struct WorkerModalState {
|
||||||
pub worker: Worker,
|
pub worker: Worker,
|
||||||
pub status: ModalStatus,
|
pub status: ModalStatus,
|
||||||
pub old_pos: Position,
|
pub old_pos: Position,
|
||||||
|
pub old_fired: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -270,6 +270,13 @@ pub struct OrderModalState {
|
||||||
pub order: Order,
|
pub order: Order,
|
||||||
pub status: ModalStatus,
|
pub status: ModalStatus,
|
||||||
}
|
}
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ClientModalState {
|
||||||
|
pub is_open: bool,
|
||||||
|
pub can_finish: bool,
|
||||||
|
pub client: Client,
|
||||||
|
pub status: ModalStatus,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq)]
|
#[derive(Default, PartialEq)]
|
||||||
pub enum ModalStatus {
|
pub enum ModalStatus {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ use egui_extras::Column;
|
||||||
use crate::{
|
use crate::{
|
||||||
database::DBOperator,
|
database::DBOperator,
|
||||||
misc,
|
misc,
|
||||||
models::{ModalStatus, Order, OrderElement, OrderElementModalState, OrderModalState},
|
models::{
|
||||||
|
Client, ModalStatus, Order, OrderElement, OrderElementModalState, OrderModalState, Product,
|
||||||
|
},
|
||||||
tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes},
|
tab::{TABS_CAN_BE_WINDOWS, Tab, TabTypes},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -17,12 +19,16 @@ pub struct OrderTabViewer {
|
||||||
|
|
||||||
incoming_orders: Arc<RwLock<Vec<Order>>>,
|
incoming_orders: Arc<RwLock<Vec<Order>>>,
|
||||||
outcoming_orders: Arc<RwLock<Vec<Order>>>,
|
outcoming_orders: Arc<RwLock<Vec<Order>>>,
|
||||||
|
products: Arc<RwLock<Vec<Product>>>,
|
||||||
|
clients: Arc<RwLock<Vec<Client>>>,
|
||||||
incoming_order_page: i32,
|
incoming_order_page: i32,
|
||||||
outcoming_order_page: i32,
|
outcoming_order_page: i32,
|
||||||
|
products_page: i32,
|
||||||
|
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
process_order_state: OrderModalState,
|
process_order_state: OrderModalState,
|
||||||
process_element_state: OrderElementModalState,
|
process_element_state: OrderElementModalState,
|
||||||
|
client_page: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrderTabViewer {
|
impl OrderTabViewer {
|
||||||
|
|
@ -54,6 +60,16 @@ impl OrderTabViewer {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
fn update_clients(&mut self) {
|
||||||
|
self.clients = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.get_clients(
|
||||||
|
self.client_page * misc::ELEMENTS_PER_PAGE,
|
||||||
|
misc::ELEMENTS_PER_PAGE,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})));
|
||||||
|
}
|
||||||
fn show_order_element_modal(&mut self, ui: &mut egui::Ui) {
|
fn show_order_element_modal(&mut self, ui: &mut egui::Ui) {
|
||||||
egui::Modal::new(egui::Id::new("order_element_modal")).show(ui.ctx(), |ui| {
|
egui::Modal::new(egui::Id::new("order_element_modal")).show(ui.ctx(), |ui| {
|
||||||
if ui.button("Закрыть").clicked() {
|
if ui.button("Закрыть").clicked() {
|
||||||
|
|
@ -61,7 +77,44 @@ impl OrderTabViewer {
|
||||||
}
|
}
|
||||||
egui::Grid::new("order_element_grid").show(ui, |ui| {
|
egui::Grid::new("order_element_grid").show(ui, |ui| {
|
||||||
ui.label("Продукт:");
|
ui.label("Продукт:");
|
||||||
///
|
egui::ComboBox::new("process_element_combobox", "")
|
||||||
|
.selected_text(
|
||||||
|
self.process_element_state
|
||||||
|
.element
|
||||||
|
.product
|
||||||
|
.recipe
|
||||||
|
.name
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.products_page > 0 {
|
||||||
|
self.products_page -= 1;
|
||||||
|
self.update_products();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.products_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.products.read().len().to_i32().unwrap()
|
||||||
|
== misc::ELEMENTS_PER_PAGE
|
||||||
|
{
|
||||||
|
self.products_page += 1;
|
||||||
|
self.update_products();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for prod in self.products.read().clone() {
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut self.process_element_state.element.product,
|
||||||
|
prod.clone(),
|
||||||
|
format!(
|
||||||
|
"{} {} ед. | {}/шт.",
|
||||||
|
prod.recipe.name, prod.volume, prod.price_per_unit
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("Количество:");
|
ui.label("Количество:");
|
||||||
|
|
@ -80,7 +133,39 @@ impl OrderTabViewer {
|
||||||
.price_per_unit
|
.price_per_unit
|
||||||
.clone()
|
.clone()
|
||||||
* self.process_element_state.element.quantity
|
* self.process_element_state.element.quantity
|
||||||
))
|
));
|
||||||
|
ui.end_row();
|
||||||
|
let btext = match self.process_element_state.status {
|
||||||
|
ModalStatus::Add => "Добавить",
|
||||||
|
_ => "Подтвердить",
|
||||||
|
};
|
||||||
|
self.process_element_state.can_finish = match self.process_element_state.status {
|
||||||
|
ModalStatus::Add => {
|
||||||
|
self.process_element_state.element.product.id != 0
|
||||||
|
&& self.process_element_state.element.quantity > 0
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
self.process_element_state.can_finish,
|
||||||
|
egui::Button::new(btext),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.process_element_state.element.total_price = self
|
||||||
|
.process_element_state
|
||||||
|
.element
|
||||||
|
.product
|
||||||
|
.price_per_unit
|
||||||
|
.clone()
|
||||||
|
* self.process_element_state.element.quantity;
|
||||||
|
self.process_order_state
|
||||||
|
.order
|
||||||
|
.elements
|
||||||
|
.insert(self.process_element_state.element.clone());
|
||||||
|
self.process_element_state.is_open = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +178,7 @@ impl OrderTabViewer {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if self.is_admin {
|
if self.is_admin {
|
||||||
if ui.button("Добавить").clicked() {
|
if ui.button("Добавить").clicked() {
|
||||||
|
self.update_clients();
|
||||||
self.process_order_state.is_open = true;
|
self.process_order_state.is_open = true;
|
||||||
self.process_order_state.order = Order::default();
|
self.process_order_state.order = Order::default();
|
||||||
}
|
}
|
||||||
|
|
@ -100,12 +186,12 @@ impl OrderTabViewer {
|
||||||
|
|
||||||
if ui.button("<-").clicked() {
|
if ui.button("<-").clicked() {
|
||||||
if incoming_orders {
|
if incoming_orders {
|
||||||
if self.incoming_orders.read().len() > 0 {
|
if self.incoming_order_page > 0 {
|
||||||
self.incoming_order_page -= 1;
|
self.incoming_order_page -= 1;
|
||||||
self.update_orders();
|
self.update_orders();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.outcoming_orders.read().len() > 0 {
|
if self.outcoming_order_page > 0 {
|
||||||
self.outcoming_order_page -= 1;
|
self.outcoming_order_page -= 1;
|
||||||
self.update_orders();
|
self.update_orders();
|
||||||
}
|
}
|
||||||
|
|
@ -155,9 +241,13 @@ impl OrderTabViewer {
|
||||||
heading.col(|ui| {
|
heading.col(|ui| {
|
||||||
ui.heading("Дата создания");
|
ui.heading("Дата создания");
|
||||||
});
|
});
|
||||||
|
heading.col(|ui| {
|
||||||
|
ui.heading(" ");
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
for or in orders.read().iter() {
|
for or in orders.read().iter() {
|
||||||
|
body.ui_mut().style_mut().interaction.selectable_labels = false;
|
||||||
body.row(25.0, |mut row| {
|
body.row(25.0, |mut row| {
|
||||||
let len = orders.read().iter().clone().len();
|
let len = orders.read().iter().clone().len();
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
|
|
@ -175,7 +265,21 @@ impl OrderTabViewer {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(or.order_date.date_naive().to_string());
|
ui.label(or.order_date.date_naive().to_string());
|
||||||
});
|
});
|
||||||
row.col(|ui| if ui.button("Удалить").clicked() {});
|
if self.is_admin {
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui.button("Удалить").clicked() {
|
||||||
|
self.process_order_state.is_open = true;
|
||||||
|
self.process_order_state.order = or.clone();
|
||||||
|
self.process_order_state.status = ModalStatus::Remove;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if row.response().double_clicked() {
|
||||||
|
self.update_clients();
|
||||||
|
self.process_order_state.is_open = true;
|
||||||
|
self.process_order_state.order = or.clone();
|
||||||
|
self.process_order_state.status = ModalStatus::Edit;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -185,16 +289,43 @@ impl OrderTabViewer {
|
||||||
self.process_order_state.is_open = false
|
self.process_order_state.is_open = false
|
||||||
}
|
}
|
||||||
egui::Grid::new("order_process_grid").show(ui, |ui| {
|
egui::Grid::new("order_process_grid").show(ui, |ui| {
|
||||||
|
if self.process_order_state.status != ModalStatus::Add {
|
||||||
ui.label("ID заказа:");
|
ui.label("ID заказа:");
|
||||||
ui.label(self.process_order_state.order.id.to_string());
|
ui.label(self.process_order_state.order.id.to_string());
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
}
|
||||||
|
if self.process_order_state.status != ModalStatus::Remove {
|
||||||
ui.label(if incoming_orders {
|
ui.label(if incoming_orders {
|
||||||
"Заказчик"
|
"Заказчик"
|
||||||
} else {
|
} else {
|
||||||
"Клиент"
|
"Клиент"
|
||||||
});
|
});
|
||||||
//ВЫБОР КЛИЕНТА
|
egui::ComboBox::new("select_client_combobox", "")
|
||||||
|
.selected_text(&self.process_order_state.order.client.name)
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.client_page > 0 {
|
||||||
|
self.client_page -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.client_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.clients.read().len().to_i32().unwrap()
|
||||||
|
== misc::ELEMENTS_PER_PAGE
|
||||||
|
{
|
||||||
|
self.client_page += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for cl in self.clients.read().iter() {
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut self.process_order_state.order.client,
|
||||||
|
cl.clone(),
|
||||||
|
&cl.name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("Элементы");
|
ui.label("Элементы");
|
||||||
|
|
@ -202,7 +333,10 @@ impl OrderTabViewer {
|
||||||
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
||||||
.selected_text(match self.process_order_state.order.elements.len() {
|
.selected_text(match self.process_order_state.order.elements.len() {
|
||||||
0 => "Пусто".to_owned(),
|
0 => "Пусто".to_owned(),
|
||||||
_ => format!("{} элем.", self.process_order_state.order.elements.len()),
|
_ => format!(
|
||||||
|
"{} элем.",
|
||||||
|
self.process_order_state.order.elements.len()
|
||||||
|
),
|
||||||
})
|
})
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
if ui.button("Новый элемент").clicked() {
|
if ui.button("Новый элемент").clicked() {
|
||||||
|
|
@ -225,13 +359,107 @@ impl OrderTabViewer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.end_row();
|
||||||
|
ui.label("Дата заказа: ");
|
||||||
|
let ndate = self.process_order_state.order.order_date.date_naive();
|
||||||
|
let mut date = misc::naivedate_to_jiff(ndate);
|
||||||
|
ui.add(egui_extras::DatePickerButton::new(&mut date));
|
||||||
|
if self.process_order_state.order.order_date.date_naive()
|
||||||
|
!= misc::jiff_to_naivedate(date)
|
||||||
|
{
|
||||||
|
self.process_order_state.order.order_date =
|
||||||
|
misc::jiff_to_naivedate(date)
|
||||||
|
.and_hms_opt(0, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.and_local_timezone(chrono::Local)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
let btext = match self.process_order_state.status {
|
||||||
|
ModalStatus::Add => "Добавить",
|
||||||
|
ModalStatus::Edit => "Сохранить",
|
||||||
|
ModalStatus::Remove => "Удалить",
|
||||||
|
};
|
||||||
|
self.process_order_state.can_finish = match self.process_order_state.status {
|
||||||
|
ModalStatus::Remove => true,
|
||||||
|
_ => {
|
||||||
|
self.process_order_state.order.client.name.len() > 0
|
||||||
|
&& self.process_order_state.order.elements.len() > 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
self.process_order_state.can_finish,
|
||||||
|
egui::Button::new(btext),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.rt.block_on(async {
|
||||||
|
match self.process_order_state.status {
|
||||||
|
ModalStatus::Add => {
|
||||||
|
let id = self
|
||||||
|
.db_oper
|
||||||
|
.add_order(
|
||||||
|
self.process_order_state.order.clone(),
|
||||||
|
incoming_orders,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
self.db_oper
|
||||||
|
.add_order_element(
|
||||||
|
self.process_order_state.order.elements.clone(),
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ModalStatus::Edit => {
|
||||||
|
self.db_oper
|
||||||
|
.remove_order_elements(self.process_order_state.order.id)
|
||||||
|
.await;
|
||||||
|
self.db_oper
|
||||||
|
.update_order(
|
||||||
|
self.process_order_state.order.clone(),
|
||||||
|
incoming_orders,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
self.db_oper
|
||||||
|
.add_order_element(
|
||||||
|
self.process_order_state.order.elements.clone(),
|
||||||
|
self.process_order_state.order.id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ModalStatus::Remove => {
|
||||||
|
self.db_oper
|
||||||
|
.remove_order_elements(self.process_order_state.order.id)
|
||||||
|
.await;
|
||||||
|
self.db_oper
|
||||||
|
.remove_order(self.process_order_state.order.id)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.update_orders();
|
||||||
|
self.process_order_state.is_open = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if self.process_element_state.is_open {
|
if self.process_element_state.is_open {
|
||||||
self.show_order_element_modal(ui);
|
self.show_order_element_modal(ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_products(&mut self) {
|
||||||
|
self.products = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.get_products(
|
||||||
|
self.products_page * misc::ELEMENTS_PER_PAGE,
|
||||||
|
misc::ELEMENTS_PER_PAGE,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl egui_dock::TabViewer for OrderTabViewer {
|
impl egui_dock::TabViewer for OrderTabViewer {
|
||||||
|
|
@ -273,9 +501,17 @@ impl Default for OrderTabViewer {
|
||||||
outcoming_orders: Arc::new(RwLock::new(
|
outcoming_orders: Arc::new(RwLock::new(
|
||||||
rt.block_on(async { db_oper.get_orders(0, misc::ELEMENTS_PER_PAGE, false).await }),
|
rt.block_on(async { db_oper.get_orders(0, misc::ELEMENTS_PER_PAGE, false).await }),
|
||||||
)),
|
)),
|
||||||
|
products: Arc::new(RwLock::new(rt.block_on(async {
|
||||||
|
db_oper.get_products(0, misc::ELEMENTS_PER_PAGE).await
|
||||||
|
}))),
|
||||||
|
clients: Arc::new(RwLock::new(rt.block_on(async {
|
||||||
|
db_oper.get_clients(0, misc::ELEMENTS_PER_PAGE).await
|
||||||
|
}))),
|
||||||
|
|
||||||
incoming_order_page: 0,
|
incoming_order_page: 0,
|
||||||
outcoming_order_page: 0,
|
outcoming_order_page: 0,
|
||||||
|
products_page: 0,
|
||||||
|
client_page: 0,
|
||||||
db_oper,
|
db_oper,
|
||||||
rt,
|
rt,
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ use egui_extras::{Column, TableBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::DBOperator,
|
database::DBOperator,
|
||||||
misc,
|
misc::{self, ELEMENTS_PER_PAGE},
|
||||||
models::{
|
models::{
|
||||||
RecipeElementModalState, Equipment, Material, ModalStatus, Product, ProductModalState, Recipe,
|
Equipment, Material, ModalStatus, Product, ProductModalState, Recipe, RecipeElement,
|
||||||
RecipeElement, RecipeModalState,
|
RecipeElementModalState, RecipeModalState,
|
||||||
},
|
},
|
||||||
tab::{self, Tab, TabTypes},
|
tab::{self, Tab, TabTypes},
|
||||||
};
|
};
|
||||||
|
|
@ -34,6 +34,7 @@ pub struct RecipeTabViewer {
|
||||||
old_price: BigDecimal,
|
old_price: BigDecimal,
|
||||||
product_page: i32,
|
product_page: i32,
|
||||||
recipe_page: i32,
|
recipe_page: i32,
|
||||||
|
mat_page: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecipeTabViewer {
|
impl RecipeTabViewer {
|
||||||
|
|
@ -68,6 +69,21 @@ impl RecipeTabViewer {
|
||||||
egui::ComboBox::new("material_select_combobox", "")
|
egui::ComboBox::new("material_select_combobox", "")
|
||||||
.selected_text(&self.process_element_status.element.material.name)
|
.selected_text(&self.process_element_status.element.material.name)
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.mat_page > 0 {
|
||||||
|
self.mat_page -= 1;
|
||||||
|
self.update_materials();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.mat_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.materials.read().len().to_i32().unwrap()
|
||||||
|
== misc::ELEMENTS_PER_PAGE
|
||||||
|
{
|
||||||
|
self.mat_page += 1;
|
||||||
|
self.update_materials();
|
||||||
|
}
|
||||||
|
}
|
||||||
for mat in self.materials.read().clone().iter() {
|
for mat in self.materials.read().clone().iter() {
|
||||||
ui.selectable_value(
|
ui.selectable_value(
|
||||||
&mut self.process_element_status.element.material,
|
&mut self.process_element_status.element.material,
|
||||||
|
|
@ -370,6 +386,15 @@ impl RecipeTabViewer {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_materials(&mut self) {
|
||||||
|
self.materials = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
|
self.db_oper
|
||||||
|
.get_materials(self.mat_page, ELEMENTS_PER_PAGE)
|
||||||
|
.await
|
||||||
|
.unwrap_or(Vec::new())
|
||||||
|
})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl egui_dock::TabViewer for RecipeTabViewer {
|
impl egui_dock::TabViewer for RecipeTabViewer {
|
||||||
type Tab = Tab;
|
type Tab = Tab;
|
||||||
|
|
@ -499,9 +524,12 @@ impl Default for RecipeTabViewer {
|
||||||
.await
|
.await
|
||||||
.unwrap_or(Vec::new())
|
.unwrap_or(Vec::new())
|
||||||
}))),
|
}))),
|
||||||
materials: Arc::new(RwLock::new(
|
materials: Arc::new(RwLock::new(rt.block_on(async {
|
||||||
rt.block_on(async { db_oper.get_materials().await.unwrap_or(Vec::new()) }),
|
db_oper
|
||||||
)),
|
.get_materials(0, ELEMENTS_PER_PAGE)
|
||||||
|
.await
|
||||||
|
.unwrap_or(Vec::new())
|
||||||
|
}))),
|
||||||
equipment: Arc::new(RwLock::new(rt.block_on(async {
|
equipment: Arc::new(RwLock::new(rt.block_on(async {
|
||||||
db_oper
|
db_oper
|
||||||
.get_equipment(0, 5, false)
|
.get_equipment(0, 5, false)
|
||||||
|
|
@ -530,7 +558,7 @@ impl Default for RecipeTabViewer {
|
||||||
|
|
||||||
product_page: 0,
|
product_page: 0,
|
||||||
recipe_page: 0,
|
recipe_page: 0,
|
||||||
|
mat_page: 0,
|
||||||
rt,
|
rt,
|
||||||
db_oper,
|
db_oper,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use bigdecimal::BigDecimal;
|
use bigdecimal::{BigDecimal, ToPrimitive};
|
||||||
use egui::mutex::RwLock;
|
use egui::mutex::RwLock;
|
||||||
use egui_extras::{Column, TableBuilder};
|
use egui_extras::{Column, TableBuilder};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -26,6 +26,7 @@ pub struct WorkerTabViewer {
|
||||||
|
|
||||||
only_not_fired_workers: bool,
|
only_not_fired_workers: bool,
|
||||||
workers_page: i32,
|
workers_page: i32,
|
||||||
|
positions_page: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerTabViewer {
|
impl WorkerTabViewer {
|
||||||
|
|
@ -39,7 +40,7 @@ impl WorkerTabViewer {
|
||||||
self.workers = Arc::new(RwLock::new(self.rt.block_on(async {
|
self.workers = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
self.db_oper
|
self.db_oper
|
||||||
.get_workers(
|
.get_workers(
|
||||||
self.workers_page,
|
self.workers_page * ELEMENTS_PER_PAGE,
|
||||||
ELEMENTS_PER_PAGE,
|
ELEMENTS_PER_PAGE,
|
||||||
self.only_not_fired_workers,
|
self.only_not_fired_workers,
|
||||||
)
|
)
|
||||||
|
|
@ -48,21 +49,42 @@ impl WorkerTabViewer {
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
fn update_positions(&mut self) {
|
fn update_positions(&mut self) {
|
||||||
self.positions = Arc::new(RwLock::new(
|
self.positions = Arc::new(RwLock::new(self.rt.block_on(async {
|
||||||
self.rt
|
self.db_oper
|
||||||
.block_on(async { self.db_oper.get_position().await.unwrap() }),
|
.get_positions(self.positions_page * ELEMENTS_PER_PAGE, ELEMENTS_PER_PAGE)
|
||||||
));
|
.await
|
||||||
|
.unwrap()
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_worker(&mut self, ui: &mut egui::Ui) {
|
fn show_worker(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
if self.is_admin {
|
||||||
if ui.button("Добавить").clicked() {
|
if ui.button("Добавить").clicked() {
|
||||||
self.process_worker_state.is_open = true;
|
self.process_worker_state.is_open = true;
|
||||||
self.process_worker_state.worker = Worker::default();
|
self.process_worker_state.worker = Worker::default();
|
||||||
};
|
};
|
||||||
if ui.button("Обновить").clicked() {
|
}
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.workers_page > 0 {
|
||||||
|
self.workers_page -= 1;
|
||||||
self.update_workers();
|
self.update_workers();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.workers_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.workers.read().len().to_i32().unwrap() == misc::ELEMENTS_PER_PAGE {
|
||||||
|
self.workers_page += 1;
|
||||||
|
self.update_workers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.checkbox(&mut self.only_not_fired_workers, "Без уволенных")
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
self.update_workers();
|
||||||
|
};
|
||||||
});
|
});
|
||||||
if self.process_worker_state.is_open {
|
if self.process_worker_state.is_open {
|
||||||
let pos = self.process_worker_state.worker.position.clone();
|
let pos = self.process_worker_state.worker.position.clone();
|
||||||
|
|
@ -90,6 +112,21 @@ impl WorkerTabViewer {
|
||||||
&self.process_worker_state.worker.position.name
|
&self.process_worker_state.worker.position.name
|
||||||
})
|
})
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.workers_page > 0 {
|
||||||
|
self.workers_page -= 1;
|
||||||
|
self.update_workers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.workers_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.workers.read().len().to_i32().unwrap()
|
||||||
|
== misc::ELEMENTS_PER_PAGE
|
||||||
|
{
|
||||||
|
self.workers_page += 1;
|
||||||
|
self.update_workers();
|
||||||
|
}
|
||||||
|
}
|
||||||
for pos in self.positions.read().clone().iter() {
|
for pos in self.positions.read().clone().iter() {
|
||||||
ui.selectable_value(
|
ui.selectable_value(
|
||||||
&mut self.process_worker_state.worker.position,
|
&mut self.process_worker_state.worker.position,
|
||||||
|
|
@ -165,6 +202,13 @@ impl WorkerTabViewer {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
if self.process_worker_state.worker.is_fired
|
||||||
|
!= self.process_worker_state.old_fired
|
||||||
|
{
|
||||||
|
self.process_worker_state.worker.fire_date =
|
||||||
|
Some(chrono::Local::now());
|
||||||
|
}
|
||||||
|
|
||||||
self.db_oper
|
self.db_oper
|
||||||
.update_worker(self.process_worker_state.worker.clone())
|
.update_worker(self.process_worker_state.worker.clone())
|
||||||
.await
|
.await
|
||||||
|
|
@ -214,13 +258,18 @@ impl WorkerTabViewer {
|
||||||
ui.label(&wk.position.name);
|
ui.label(&wk.position.name);
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(if wk.is_fired { "Да" } else { "Нет" });
|
ui.label(if wk.is_fired {
|
||||||
|
wk.fire_date.unwrap().date_naive().to_string()
|
||||||
|
} else {
|
||||||
|
"Нет".to_owned()
|
||||||
|
});
|
||||||
});
|
});
|
||||||
if row.response().double_clicked() {
|
if row.response().double_clicked() {
|
||||||
self.process_worker_state.is_open = true;
|
self.process_worker_state.is_open = true;
|
||||||
self.process_worker_state.status = ModalStatus::Edit;
|
self.process_worker_state.status = ModalStatus::Edit;
|
||||||
self.process_worker_state.worker = wk.clone();
|
self.process_worker_state.worker = wk.clone();
|
||||||
self.process_worker_state.old_pos = wk.position.clone();
|
self.process_worker_state.old_pos = wk.position.clone();
|
||||||
|
self.process_worker_state.old_fired = wk.is_fired.clone();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -229,6 +278,7 @@ impl WorkerTabViewer {
|
||||||
|
|
||||||
fn show_position(&mut self, ui: &mut egui::Ui) {
|
fn show_position(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
if self.is_admin {
|
||||||
if ui.button("Добавить").clicked() {
|
if ui.button("Добавить").clicked() {
|
||||||
// self.show_position_add_modal = true;
|
// self.show_position_add_modal = true;
|
||||||
self.process_position_state.is_open = true;
|
self.process_position_state.is_open = true;
|
||||||
|
|
@ -243,9 +293,20 @@ impl WorkerTabViewer {
|
||||||
.data
|
.data
|
||||||
.insert("wage".into(), String::from("0"));
|
.insert("wage".into(), String::from("0"));
|
||||||
}
|
}
|
||||||
if ui.button("Обновить").clicked() {
|
}
|
||||||
|
if ui.button("<-").clicked() {
|
||||||
|
if self.positions_page > 0 {
|
||||||
|
self.positions_page -= 1;
|
||||||
self.update_positions();
|
self.update_positions();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ui.monospace(self.positions_page.to_string());
|
||||||
|
if ui.button("->").clicked() {
|
||||||
|
if self.positions.read().len().to_i32().unwrap() == ELEMENTS_PER_PAGE {
|
||||||
|
self.positions_page += 1;
|
||||||
|
self.update_positions();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.column(Column::auto())
|
.column(Column::auto())
|
||||||
|
|
@ -368,6 +429,7 @@ impl WorkerTabViewer {
|
||||||
match self.process_position_state.status {
|
match self.process_position_state.status {
|
||||||
ModalStatus::Add => {
|
ModalStatus::Add => {
|
||||||
let pos = self.process_position_state.data.clone();
|
let pos = self.process_position_state.data.clone();
|
||||||
|
|
||||||
self.rt.block_on(async {
|
self.rt.block_on(async {
|
||||||
self.db_oper
|
self.db_oper
|
||||||
.add_position(Position {
|
.add_position(Position {
|
||||||
|
|
@ -378,7 +440,8 @@ impl WorkerTabViewer {
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
})
|
})
|
||||||
.await;
|
.await
|
||||||
|
.unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ModalStatus::Edit => {
|
ModalStatus::Edit => {
|
||||||
|
|
@ -488,9 +551,10 @@ impl Default for WorkerTabViewer {
|
||||||
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 });
|
||||||
let positions = Arc::new(RwLock::new(
|
let positions =
|
||||||
rt.block_on(async { db_oper.get_position().await.unwrap() }),
|
Arc::new(RwLock::new(rt.block_on(async {
|
||||||
));
|
db_oper.get_positions(0, ELEMENTS_PER_PAGE).await.unwrap()
|
||||||
|
})));
|
||||||
let workers = Arc::new(RwLock::new(rt.block_on(async {
|
let workers = Arc::new(RwLock::new(rt.block_on(async {
|
||||||
db_oper
|
db_oper
|
||||||
.get_workers(0, misc::ELEMENTS_PER_PAGE, false)
|
.get_workers(0, misc::ELEMENTS_PER_PAGE, false)
|
||||||
|
|
@ -520,6 +584,7 @@ impl Default for WorkerTabViewer {
|
||||||
process_worker_state: WorkerModalState {
|
process_worker_state: WorkerModalState {
|
||||||
is_open: false,
|
is_open: false,
|
||||||
can_finish: false,
|
can_finish: false,
|
||||||
|
old_fired: worker.is_fired,
|
||||||
worker,
|
worker,
|
||||||
status: ModalStatus::Add,
|
status: ModalStatus::Add,
|
||||||
old_pos: Position::default(),
|
old_pos: Position::default(),
|
||||||
|
|
@ -533,6 +598,7 @@ impl Default for WorkerTabViewer {
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
only_not_fired_workers: false,
|
only_not_fired_workers: false,
|
||||||
workers_page: 0,
|
workers_page: 0,
|
||||||
|
positions_page: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
1 - Добавить пагниацию там, где её ещё нет
|
1 - Добавить пагниацию там, где её ещё нет
|
||||||
2 - Доделать проверки при нажатии кнопок в модальных окнах
|
2 - Доделать проверки при нажатии кнопок в модальных окнах
|
||||||
3 - Написать часть с клиентом
|
3 - Сделать отчёты
|
||||||
4 - доделать заказы
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue