Compare commits

..

No commits in common. "aecee8b8d03d1759dc9aff82d9e01c1d21a5702c" and "35c83ed9eb970058d0d686b5db8ed5ff148e47b5" have entirely different histories.

4 changed files with 9 additions and 322 deletions

View File

@ -2,7 +2,7 @@
Система позволяет вести учёт: Система позволяет вести учёт:
- [ ] Оборудования - [ ] Оборудования
- [x] Сотрудников - [ ] Сотрудников
- [ ] Сырья - [ ] Сырья
- [ ] Произведённой продукции - [ ] Произведённой продукции
- [ ] Доходов от продажи продукции - [ ] Доходов от продажи продукции

View File

@ -1,10 +1,9 @@
use std::{collections::HashMap, ops::Deref, sync::Arc}; use std::sync::Arc;
use egui::{TextBuffer, mutex::RwLock}; use egui::mutex::RwLock;
use egui_dock::{DockArea, Style, TabViewer}; use egui_dock::{DockArea, Style, TabViewer};
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, Position, Worker}};
static TABS_CAN_BE_WINDOWS: bool = false; static TABS_CAN_BE_WINDOWS: bool = false;
@ -20,8 +19,6 @@ enum TabTypes{
Settings, Settings,
WorkerList, WorkerList,
WorkerPosition, WorkerPosition,
MaterialList,
MaterialTypeList
} }
struct Tab{ struct Tab{
tab_type: TabTypes, tab_type: TabTypes,
@ -100,8 +97,6 @@ struct MainTabViewer {
db_oper: DBOperator, db_oper: DBOperator,
worker_tabs: WorkerTabViewer, worker_tabs: WorkerTabViewer,
worker_tree: egui_dock::DockState<Tab>, worker_tree: egui_dock::DockState<Tab>,
material_tabs: MaterialTabViewer,
material_tree: egui_dock::DockState<Tab>,
rt: tokio::runtime::Runtime, rt: tokio::runtime::Runtime,
is_dark_theme: bool, is_dark_theme: bool,
interface_scale_ratio: f32, interface_scale_ratio: f32,
@ -130,17 +125,6 @@ impl Default for MainTabViewer{
tab_type:TabTypes::WorkerPosition, tab_type:TabTypes::WorkerPosition,
} }
]), ]),
material_tabs: MaterialTabViewer::default(),
material_tree: egui_dock::DockState::new(vec![
Tab{
title:"Сырьё".to_owned(),
tab_type: TabTypes::MaterialList,
},
Tab{
title:"Тип".to_owned(),
tab_type: TabTypes::MaterialTypeList,
}
]),
rt, rt,
is_dark_theme: true, is_dark_theme: true,
interface_scale_ratio: 1.2, interface_scale_ratio: 1.2,
@ -208,10 +192,7 @@ impl MainTabViewer{
.show_inside(ui, &mut self.worker_tabs); .show_inside(ui, &mut self.worker_tabs);
} }
fn show_material(&mut self, ui: &mut egui::Ui){ fn show_material(&mut self, ui: &mut egui::Ui){
let id = ui.make_persistent_id("MaterialMenu"); ui.label("Сырьё короче да");
DockArea::new(&mut self.material_tree)
.id(id)
.show_inside(ui, &mut self.material_tabs);
} }
fn show_salary(&mut self, ui: &mut egui::Ui){ fn show_salary(&mut self, ui: &mut egui::Ui){
ui.label("Помогите"); ui.label("Помогите");
@ -641,203 +622,3 @@ impl Default for WorkerTabViewer{
} }
} }
} }
struct MaterialTabViewer{
db_oper: DBOperator,
rt: tokio::runtime::Runtime,
process_mcat_state: ModalWinState,
process_material_state: ModalWinState,
mat_cats: Arc<RwLock<Vec<MaterialCategory>>>,
mats: Arc<RwLock<Vec<Material>>>,
}
impl MaterialTabViewer {
fn show_material(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui|{
if ui.button("Добавить").clicked(){
self.process_material_state.is_open = true;
self.process_material_state.status = "add".to_owned();
}
if ui.button("Редактировать").clicked(){
self.process_material_state.is_open = true;
self.process_material_state.status = "edit".to_owned();
}
if ui.button("Удалить").clicked(){
self.process_material_state.is_open = true;
self.process_material_state.status = "remove".to_owned();
}
if ui.button("Обновить").clicked(){
}
});
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)
.striped(true)
.cell_layout(egui::Layout::centered_and_justified(egui::Direction::LeftToRight))
.vscroll(true)
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.header(20.0, |mut header|{
header.col(|ui|{ui.heading("ID");});
header.col(|ui|{ui.heading("Название");});
header.col(|ui|{ui.heading("Количество");});
header.col(|ui|{ui.heading("Тип");});
})
.body(|mut body|{
self.rt.block_on(async{
for mat in self.mats.read().clone().iter(){
body.row(30.0,|mut row|{
row.col(|ui|{ui.label(mat.id.to_string());});
row.col(|ui|{ui.label(&mat.name);});
row.col(|ui|{ui.label(mat.quantity.to_string());});
row.col(|ui|{ui.label(&mat.category.name);});
});
}
})
});
}
fn show_material_type(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui|{
if ui.button("Добавить").clicked(){
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "add".to_owned();
}
if ui.button("Редактировать").clicked(){
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "edit".to_owned();
}
if ui.button("Удалить").clicked(){
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = "remove".to_owned();
}
if ui.button("Обновить").clicked(){
}
});
if self.process_mcat_state.is_open{
egui::Modal::new("process_mcat".into()).show(ui.ctx(), |ui|{
if ui.button("Закрыть").clicked(){
self.process_mcat_state.is_open = false;
}
egui::Grid::new("process_mcat_grid")
.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 selected_id = self.process_mcat_state.data.get("id")
.map(|s| s.as_str()) // если там что-то, у чего есть as_str()
.unwrap_or("");
let current_name = iterr.iter()
.find(|mc| mc.id.to_string() == *selected_id)
.map(|mc | mc.name.as_str())
.unwrap_or("Выбрать");
egui::ComboBox::new("process_mcat_grid_selector","Выбрать")
.selected_text(current_name)
.show_ui(ui, |ui|{
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(), &mcat.name);
}
});
});
ui.end_row();
ui.label("Название");
ui.text_edit_singleline(self.process_mcat_state.data.get_mut("name").unwrap());
});
});
}
TableBuilder::new(ui)
.striped(true)
.column(Column::auto())
.column(Column::auto())
.header(20.0, |mut header|{
header.col(|ui|{
ui.heading("ID");
});
header.col(|ui|{
ui.heading("Название");
});
})
.body(|mut body|{
self.rt.block_on(async{
for mcat in self.mat_cats.read().clone().iter(){
body.row(20.0,|mut row|{
row.col(|ui|{ui.label(mcat.id.to_string());});
row.col(|ui|{ui.label(&mcat.name);});
});
}
});
});
}
}
impl egui_dock::TabViewer for MaterialTabViewer{
type Tab = Tab;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
(&*tab.title).into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
match &tab.tab_type{
TabTypes::MaterialList => self.show_material(ui),
TabTypes::MaterialTypeList => self.show_material_type(ui),
_ => {ui.label("Каким образом?");},
}
}
fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool {
TABS_CAN_BE_WINDOWS
}
fn is_closeable(&self, _tab: &Self::Tab) -> bool {
false
}
}
impl Default for MaterialTabViewer{
fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap();
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()})));
Self {
mats: Arc::new(RwLock::new(rt.block_on(async{db_oper.get_materials().await.unwrap()}))),
db_oper,
rt,
process_mcat_state: ModalWinState{
data: HashMap::from([
(String::from("id"), mat_cats.clone().read().clone()[0].id.to_string()),
(String::from("name"), mat_cats.clone().read().clone()[0].name.clone()),
]),
status: "none".to_owned(),
..Default::default()
},
process_material_state: ModalWinState{
data: HashMap::from([
("id".to_owned(),String::new()),
("name".to_owned(), String::new()),
("category_id".to_owned(), "1".to_owned())
]),
..Default::default()
},
mat_cats,
}
}
}

View File

@ -3,12 +3,10 @@ use sqlx::mysql::MySqlPool;
use dotenvy::dotenv_override; use dotenvy::dotenv_override;
use std::collections::HashMap;
use std::env; use std::env;
// use crate::schema::equipment::dsl::*; // use crate::schema::equipment::dsl::*;
// use crate::schema::worker::dsl::*; // use crate::schema::worker::dsl::*;
use crate::models::*; use crate::models::*;
use anyhow::anyhow;
pub struct DBOperator{ pub struct DBOperator{
pool: MySqlPool, pool: MySqlPool,
@ -56,33 +54,6 @@ impl DBOperator{
} }
Ok(rets) Ok(rets)
} }
pub async fn get_mcat(&self) -> Result<Vec<MaterialCategory>,sqlx::Error>{
let rets = sqlx::query_as::<_, MaterialCategory>("SELECT * FROM `material_category`").fetch_all(&self.pool).await?;
Ok(rets)
}
pub async fn get_materials(&self) -> Result<Vec<Material>, sqlx::Error>{
let mats = sqlx::query_as::<_,MaterialRow>("SELECT * FROM `material`").fetch_all(&self.pool).await?;
let cats = self.get_mcat().await?;
let cat_map : HashMap<_, MaterialCategory> = cats
.into_iter()
.map(|cat| (cat.id, cat))
.collect();
let mut rets = Vec::with_capacity(mats.len());
for mat in mats{
let cat = cat_map
.get(&mat.category_id)
.expect("Никто не знает как, но БД не смогла связать материал с его категорией. Заставьте разраба это починить.")
.clone();
rets.push(Material{
id: mat.id,
name: mat.name,
quantity: mat.quantity,
category: cat,
});
}
Ok(rets)
}
pub async fn check_worker(&self, worker: Worker) -> Result<bool, sqlx::Error>{ pub async fn check_worker(&self, worker: Worker) -> Result<bool, sqlx::Error>{
let ret = sqlx::query(&format!("SELECT * FROM `worker` WHERE full_name = {}, position_id = {}, hire_date = {}", worker.full_name, worker.position.id, worker.hire_date.to_string())).fetch_all(&self.pool).await?; let ret = sqlx::query(&format!("SELECT * FROM `worker` WHERE full_name = {}, position_id = {}, hire_date = {}", worker.full_name, worker.position.id, worker.hire_date.to_string())).fetch_all(&self.pool).await?;
if ret.len() > 0{ if ret.len() > 0{
@ -165,8 +136,6 @@ impl DBOperator{
}); });
ret ret
} }
} }

View File

@ -1,6 +1,3 @@
use std::{any::TypeId, ops::Deref};
use egui::TextBuffer;
use sqlx::types::{BigDecimal, chrono::DateTime}; use sqlx::types::{BigDecimal, chrono::DateTime};
@ -54,24 +51,11 @@ pub struct EquipmentRow{
pub maintenance_date: chrono::DateTime<chrono::Local>, pub maintenance_date: chrono::DateTime<chrono::Local>,
pub worker_id: i32, pub worker_id: i32,
} }
#[derive(Clone)]
pub struct Material{ pub struct Material{
pub id: i32, id: i32,
pub name: String, name: String,
pub quantity: i32, quantity: i32,
pub category: MaterialCategory category: String
}
#[derive(sqlx::FromRow)]
pub struct MaterialRow{
pub id: i32,
pub name: String,
pub quantity: i32,
pub category_id: i32,
}
#[derive(sqlx::FromRow, Default, Clone, PartialEq)]
pub struct MaterialCategory{
pub id: i32,
pub name: String,
} }
pub struct RecipeElement{ pub struct RecipeElement{
id:i32, id:i32,
@ -109,50 +93,3 @@ pub struct Product<'a>{
price_per_unit: rust_decimal::Decimal, price_per_unit: rust_decimal::Decimal,
} }
#[derive(Default)]
pub struct ModalWinState{
pub is_open: bool,
pub can_finish: bool,
pub data: std::collections::HashMap<String,String>,
pub status: String,
}
#[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 {
match self{
ModalDataType::Pos(pos) => &pos.name,
ModalDataType::Text(txt) => &txt,
ModalDataType::MatCat(mat_cat) => &mat_cat.name,
}
}
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>()
}
}