На две вкладки больше

master
Алексей Алексей 2026-05-29 01:21:57 +10:00
parent aecee8b8d0
commit 13e2d79260
3 changed files with 296 additions and 79 deletions

View File

@ -4,7 +4,7 @@ use egui::{TextBuffer, mutex::RwLock};
use egui_dock::{DockArea, Style, TabViewer}; use egui_dock::{DockArea, Style, TabViewer};
use egui_extras::{Column, TableBuilder}; use egui_extras::{Column, TableBuilder};
use sqlx::types::BigDecimal; use sqlx::types::BigDecimal;
use crate::{database::DBOperator, models::{Equipment, Material, MaterialCategory, ModalDataType, ModalWinState, Position, Worker}}; use crate::{database::DBOperator, models::{Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position, Worker}};
static TABS_CAN_BE_WINDOWS: bool = false; static TABS_CAN_BE_WINDOWS: bool = false;
@ -654,31 +654,30 @@ struct MaterialTabViewer{
} }
impl MaterialTabViewer { impl MaterialTabViewer {
fn update_material_category(&mut self){
self.mat_cats = Arc::new(RwLock::new(self.rt.block_on(async{self.db_oper.get_mcat().await.unwrap()})));
}
fn update_materials(&mut self){
self.mats = Arc::new(RwLock::new(self.rt.block_on(async{self.db_oper.get_materials().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|{
if ui.button("Добавить").clicked(){ if ui.button("Добавить").clicked(){
self.process_material_state.is_open = true; self.process_material_state.is_open = true;
self.process_material_state.status = "add".to_owned(); self.process_material_state.status = ModalStatus::Add;
} }
if ui.button("Редактировать").clicked(){ if ui.button("Редактировать").clicked(){
self.process_material_state.is_open = true; self.process_material_state.is_open = true;
self.process_material_state.status = "edit".to_owned(); self.process_material_state.status = ModalStatus::Edit;
} }
if ui.button("Удалить").clicked(){ if ui.button("Удалить").clicked(){
self.process_material_state.is_open = true; self.process_material_state.is_open = true;
self.process_material_state.status = "remove".to_owned(); self.process_material_state.status = ModalStatus::Remove;
} }
if ui.button("Обновить").clicked(){ if ui.button("Обновить").clicked(){
self.update_materials();
} }
}); });
if self.process_material_state.is_open{
egui::Modal::new("add_material".into()).show(ui.ctx(), |ui|{
if ui.button("Закрыть").clicked(){
self.process_material_state.is_open = false;
}
});
}
TableBuilder::new(ui) TableBuilder::new(ui)
.striped(true) .striped(true)
@ -691,8 +690,8 @@ impl MaterialTabViewer {
.header(20.0, |mut header|{ .header(20.0, |mut header|{
header.col(|ui|{ui.heading("ID");}); header.col(|ui|{ui.heading("ID");});
header.col(|ui|{ui.heading("Название");}); header.col(|ui|{ui.heading("Название");});
header.col(|ui|{ui.heading("Количество");});
header.col(|ui|{ui.heading("Тип");}); header.col(|ui|{ui.heading("Тип");});
header.col(|ui|{ui.heading("Количество");});
}) })
.body(|mut body|{ .body(|mut body|{
self.rt.block_on(async{ self.rt.block_on(async{
@ -702,14 +701,127 @@ impl MaterialTabViewer {
body.row(30.0,|mut row|{ body.row(30.0,|mut row|{
row.col(|ui|{ui.label(mat.id.to_string());}); row.col(|ui|{ui.label(mat.id.to_string());});
row.col(|ui|{ui.label(&mat.name);}); row.col(|ui|{ui.label(&mat.name);});
row.col(|ui|{ui.label(mat.quantity.to_string());});
row.col(|ui|{ui.label(&mat.category.name);}); row.col(|ui|{ui.label(&mat.category.name);});
row.col(|ui|{ui.label(mat.quantity.to_string());});
}); });
} }
}) })
}); });
if self.process_material_state.is_open{
egui::Modal::new("process_material".into()).show(ui.ctx(), |ui|{
if ui.button("Закрыть").clicked(){
self.process_material_state.is_open = false;
}
egui::Grid::new("process_material_grid").show(ui, |ui|{
let old = self.process_material_state.data.get("id").unwrap().clone();
if self.process_material_state.status != ModalStatus::Add{
ui.label("Материал");
let mats = self.mats.read().clone();
let sel_id = self.process_material_state.data.get("id")
.map(|d| d.as_str())
.unwrap_or("");
let cur_name = mats
.iter()
.find(|m| m.id.to_string() == sel_id)
.map(|m| m.name.clone())
.unwrap_or_default();
egui::ComboBox::from_id_salt("process_material_combobox_mat")
.selected_text(cur_name)
.show_ui(ui, |ui|{
for mat in self.mats.read().iter().clone(){
ui.selectable_value(self.process_material_state.data.get_mut("id").unwrap(), mat.id.to_string(), &mat.name);
}
let id = self.process_material_state.data.get_mut("id").unwrap().clone();
if id != old{
self.process_material_state.data.insert("name".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().name.clone());
self.process_material_state.data.insert("quantity".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().quantity.to_string());
self.process_material_state.data.insert("category_id".to_owned(), mats.iter().find(|m| m.id.to_string() == id).unwrap().category.id.to_string());
}
});
ui.end_row();
}
let old = self.process_material_state.data.get("category_id").unwrap().clone();
if self.process_material_state.status != ModalStatus::Remove{
ui.label("Название");
ui.text_edit_singleline( self.process_material_state.data.get_mut("name").unwrap());
ui.end_row();
ui.label("Количество");
ui.text_edit_singleline(self.process_material_state.data.get_mut("quantity").unwrap());
ui.end_row();
ui.label("Тип");
let mats = self.mat_cats.read().clone();
let sel_id = self.process_material_state.data.get("category_id")
.map(|d| d.as_str())
.unwrap_or_default();
let cur_name = mats
.iter()
.find(|m| m.id.to_string() == sel_id)
.map(|m| m.name.clone())
.unwrap_or_default();
egui::ComboBox::from_id_salt("process_material_combobox_cat")
.selected_text(cur_name)
.show_ui(ui, |ui|{
for mat in self.mat_cats.read().iter(){
ui.selectable_value(self.process_material_state.data.get_mut("category_id").unwrap(), mat.id.to_string(), &mat.name.clone());
}
});
ui.end_row();
}
});
match self.process_material_state.status{
ModalStatus::Add => {
let resp = ui.add_enabled(self.process_material_state.data.get("name").unwrap().len()>0&&
self.process_material_state.data.get("quantity").unwrap().len()>0, egui::Button::new("Добавить"));
if resp.clicked(){
self.rt.block_on(async{
self.db_oper.add_material(MaterialRow{
id: self.process_material_state.data.get("id").unwrap().parse::<i32>().unwrap(),
name: self.process_material_state.data.get("name").unwrap().to_string(),
quantity: self.process_material_state.data.get("quantity").unwrap().parse::<i32>().unwrap(),
category_id: self.process_material_state.data.get("category_id").unwrap().parse::<i32>().unwrap(),
}).await.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
},
ModalStatus::Edit => {
if ui.button("Сохранить").clicked(){
self.rt.block_on(async{
self.db_oper.update_material(MaterialRow {
id: self.process_material_state.data.get("id").unwrap().parse::<i32>().unwrap(),
name: self.process_material_state.data.get("name").unwrap().to_string(),
quantity: self.process_material_state.data.get("quantity").unwrap().parse::<i32>().unwrap(),
category_id: self.process_material_state.data.get("category_id").unwrap().parse::<i32>().unwrap() }).await.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
},
ModalStatus::Remove => {
if ui.button("Удалить").clicked(){
self.rt.block_on(async{
self.db_oper.delete_material(MaterialRow { id: self.process_material_state.data.get("id").unwrap().parse::<i32>().unwrap(), name: "".to_owned(), quantity: 0, category_id:0 }).await.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
}
}
});
}
} }
@ -717,18 +829,18 @@ impl MaterialTabViewer {
ui.horizontal(|ui|{ ui.horizontal(|ui|{
if ui.button("Добавить").clicked(){ if ui.button("Добавить").clicked(){
self.process_mcat_state.is_open = true; self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "add".to_owned(); self.process_mcat_state.status = ModalStatus::Add;
} }
if ui.button("Редактировать").clicked(){ if ui.button("Редактировать").clicked(){
self.process_mcat_state.is_open = true; self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "edit".to_owned(); self.process_mcat_state.status = ModalStatus::Edit;
} }
if ui.button("Удалить").clicked(){ if ui.button("Удалить").clicked(){
self.process_mcat_state.is_open = true; self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "remove".to_owned(); self.process_mcat_state.status = ModalStatus::Remove;
} }
if ui.button("Обновить").clicked(){ if ui.button("Обновить").clicked(){
self.update_material_category();
} }
}); });
if self.process_mcat_state.is_open{ if self.process_mcat_state.is_open{
@ -738,30 +850,81 @@ impl MaterialTabViewer {
} }
egui::Grid::new("process_mcat_grid") egui::Grid::new("process_mcat_grid")
.show(ui, |ui|{ .show(ui, |ui|{
ui.label("Тип");
// println!("{}",self.process_mcat_state.data.get("name").unwrap().as_str());
let mut iterr = self.mat_cats.read().clone();
let old = self.process_mcat_state.data.get("id").unwrap().clone();
let iterr = self.mat_cats.read().clone();
let selected_id = self.process_mcat_state.data.get("id") let selected_id = self.process_mcat_state.data.get("id")
.map(|s| s.as_str()) // если там что-то, у чего есть as_str() .map(|s| s.as_str())
.unwrap_or(""); .unwrap_or("");
let current_name = iterr.iter() let current_name = iterr.iter()
.find(|mc| mc.id.to_string() == *selected_id) .find(|mc| mc.id.to_string() == *selected_id)
.map(|mc | mc.name.as_str()) .map(|mc | mc.name.as_str())
.unwrap_or("Выбрать"); .unwrap_or("Выбрать");
egui::ComboBox::new("process_mcat_grid_selector","Выбрать") if self.process_mcat_state.status != ModalStatus::Add{
.selected_text(current_name) ui.label("Тип");
.show_ui(ui, |ui|{ egui::ComboBox::new("process_mcat_grid_selector","Выбрать")
.selected_text(current_name)
self.rt.block_on(async{ .show_ui(ui, |ui|{
for mcat in iterr{
ui.selectable_value(self.process_mcat_state.data.get_mut("id").unwrap(), mcat.id.to_string(), &mcat.name); self.rt.block_on(async{
} for mcat in iterr{
ui.selectable_value(self.process_mcat_state.data.get_mut("id").unwrap(), mcat.id.to_string(), format!("{}|{}",mcat.id,&mcat.name));
}
});
}); });
}); ui.end_row();
ui.end_row(); }
let current_id = self.process_mcat_state.data.get("id").unwrap().clone();
ui.label("Название"); if self.process_mcat_state.data.get("id").unwrap() != &old{
ui.text_edit_singleline(self.process_mcat_state.data.get_mut("name").unwrap()); self.process_mcat_state.data.insert("name".to_owned(), self.mat_cats.read().iter().find(|mc| mc.id.to_string() == current_id).unwrap().name.clone());
}
if self.process_mcat_state.status != ModalStatus::Remove{
ui.label("Название");
let mut name = self.process_mcat_state.data.get_mut("name").unwrap();
ui.text_edit_singleline(name);
ui.end_row();
}
match self.process_mcat_state.status{
ModalStatus::Add =>{
if ui.button("Добавить").clicked(){
let name = self.process_mcat_state.data.get("name").unwrap().clone();
self.rt.block_on(async{
self.db_oper.add_material_category(MaterialCategory { id: 0, name }).await.unwrap();
});
self.update_material_category();
self.process_mcat_state.is_open = false;
}
},
ModalStatus::Edit =>{
if ui.button("Сохранить").clicked(){
let id = self.process_mcat_state.data.get("id").unwrap().clone();
let name = self.process_mcat_state.data.get("name").unwrap().clone();
self.rt.block_on(async{
self.db_oper.update_material_category(MaterialCategory { id:id.parse::<i32>().unwrap(), name: name.clone()}).await.unwrap()
});
println!("{}",&name);
self.update_material_category();
self.process_mcat_state.is_open = false;
}
},
ModalStatus::Remove => {
if ui.button("Удалить").clicked(){
let idd = self.process_mcat_state.data.get("id").unwrap().clone();
self.rt.block_on(async{
self.db_oper.delete_material_category(MaterialCategory { id:idd.parse::<i32>().unwrap(), name: "".to_owned() }).await.unwrap()
});
self.update_material_category();
self.process_mcat_state.is_open = false;
}
},
}
}); });
}); });
} }
@ -814,9 +977,9 @@ impl Default for MaterialTabViewer{
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 mat_cats = Arc::new(RwLock::new(rt.block_on(async{db_oper.get_mcat().await.unwrap()}))); let mat_cats = Arc::new(RwLock::new(rt.block_on(async{db_oper.get_mcat().await.unwrap()})));
let mats = Arc::new(RwLock::new(rt.block_on(async{db_oper.get_materials().await.unwrap()})));
Self { Self {
mats: Arc::new(RwLock::new(rt.block_on(async{db_oper.get_materials().await.unwrap()}))),
db_oper, db_oper,
rt, rt,
process_mcat_state: ModalWinState{ process_mcat_state: ModalWinState{
@ -824,19 +987,21 @@ impl Default for MaterialTabViewer{
(String::from("id"), mat_cats.clone().read().clone()[0].id.to_string()), (String::from("id"), mat_cats.clone().read().clone()[0].id.to_string()),
(String::from("name"), mat_cats.clone().read().clone()[0].name.clone()), (String::from("name"), mat_cats.clone().read().clone()[0].name.clone()),
]), ]),
status: "none".to_owned(), status: ModalStatus::Add,
..Default::default() ..Default::default()
}, },
process_material_state: ModalWinState{ process_material_state: ModalWinState{
data: HashMap::from([ data: HashMap::from([
("id".to_owned(),String::new()), ("id".to_owned(),mats.clone().read().clone()[0].id.to_string()),
("name".to_owned(), String::new()), ("name".to_owned(), mats.clone().read().clone()[0].name.clone()),
("quantity".to_owned(),mats.clone().read().clone()[0].quantity.to_string()),
("category_id".to_owned(), "1".to_owned()) ("category_id".to_owned(), "1".to_owned())
]), ]),
..Default::default() ..Default::default()
}, },
mat_cats, mat_cats,
mats
} }
} }

View File

@ -121,8 +121,36 @@ impl DBOperator{
} }
} }
} }
pub async fn add_material_category(&self, mat_cat: MaterialCategory) -> Result<bool, sqlx::Error>{
match sqlx::query("INSERT INTO Brewery.`material_category` (id, name) VALUES (0, ?)")
.bind(mat_cat.name)
.execute(&self.pool)
.await{
Ok(_)=>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
pub async fn add_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{
match sqlx::query("INSERT INTO Brewery.material (id, name, quantity, category_id) VALUES(0, ?, ?, ?);")
.bind(mat.name)
.bind(mat.quantity)
.bind(mat.category_id)
.execute(&self.pool)
.await{
Ok(_)=>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
pub async fn delete_position(&self, position: Position) -> Result<bool,sqlx::Error>{ pub async fn delete_position(&self, position: Position) -> Result<bool,sqlx::Error>{
match sqlx::query("DELETE FROM Brewer.`position` WHERE id = ?;") match sqlx::query("DELETE FROM Brewery.`position` WHERE id = ?;")
.bind(position.id) .bind(position.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await{
@ -134,6 +162,32 @@ impl DBOperator{
} }
} }
} }
pub async fn delete_material_category(&self, mat_cat: MaterialCategory) -> Result<bool,sqlx::Error>{
match sqlx::query("DELETE FROM Brewery.`material_category` WHERE id = ?;")
.bind(mat_cat.id)
.execute(&self.pool)
.await{
Ok(_) =>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
pub async fn delete_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{
match sqlx::query("DELETE FROM Brewery.`material` WHERE id = ?;")
.bind(mat.id)
.execute(&self.pool)
.await{
Ok(_) =>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
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 Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;") match sqlx::query("UPDATE Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;")
@ -152,6 +206,36 @@ impl DBOperator{
} }
} }
} }
pub async fn update_material_category(&self, mat_cat: MaterialCategory) -> Result<bool, sqlx::Error>{
match sqlx::query("UPDATE Brewery.`material_category` SET name=? WHERE id=?;")
.bind(mat_cat.name)
.bind(mat_cat.id)
.execute(&self.pool)
.await{
Ok(_) =>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
pub async fn update_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{
match sqlx::query("UPDATE Brewery.material SET name=?, quantity=?, category_id=? WHERE id=?;")
.bind(mat.name)
.bind(mat.quantity)
.bind(mat.category_id)
.bind(mat.id)
.execute(&self.pool)
.await{
Ok(_) =>{
Ok(true)
},
Err(_)=>{
Ok(false)
}
}
}
pub async fn get_worker_by_id(&self, worker_id:i32) -> Result<Worker, sqlx::Error>{ pub async fn get_worker_by_id(&self, worker_id:i32) -> Result<Worker, sqlx::Error>{
let preret = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker` WHERE id = ?;").bind(worker_id).fetch_all(&self.pool).await?; let preret = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker` WHERE id = ?;").bind(worker_id).fetch_all(&self.pool).await?;
let poses = self.get_position().await?; let poses = self.get_position().await?;

View File

@ -114,45 +114,13 @@ pub struct ModalWinState{
pub is_open: bool, pub is_open: bool,
pub can_finish: bool, pub can_finish: bool,
pub data: std::collections::HashMap<String,String>, pub data: std::collections::HashMap<String,String>,
pub status: String, pub status: ModalStatus,
} }
#[derive(PartialEq)]
pub enum ModalDataType{
Pos(Position),
MatCat(MaterialCategory),
Text(String),
}
impl TextBuffer for ModalDataType{
fn is_mutable(&self) -> bool {
true
}
fn as_str(&self) -> &str { #[derive(Default, PartialEq)]
match self{ pub enum ModalStatus{
ModalDataType::Pos(pos) => &pos.name, #[default]
ModalDataType::Text(txt) => &txt, Add,
ModalDataType::MatCat(mat_cat) => &mat_cat.name, Edit,
} Remove
}
fn insert_text(&mut self, text: &str, char_index: usize) -> usize {
match self{
ModalDataType::Pos(pos) => {pos.name.insert_str(char_index, text);},
ModalDataType::Text(txt) => {txt.insert_str(char_index, text);},
ModalDataType::MatCat(mat_cat) => {mat_cat.name.insert_str(char_index, text);}
}
text.len()
}
fn delete_char_range(&mut self, char_range: std::ops::Range<usize>) {
match self{
ModalDataType::Pos(pos) => {pos.name.delete_char_range(char_range);},
ModalDataType::Text(txt) => {txt.delete_char_range(char_range);},
ModalDataType::MatCat(mat_cat) => {mat_cat.name.delete_char_range(char_range);}
}
}
fn type_id(&self) -> std::any::TypeId {
TypeId::of::<ModalDataType>()
}
} }