From 0e4cb900237c805be38dfe24c9e466fed7a5d8de Mon Sep 17 00:00:00 2001 From: ultrageese Date: Thu, 18 Jun 2026 08:45:03 +1000 Subject: [PATCH] =?UTF-8?q?=D0=B5=D1=81=D0=BB=D0=B8=20=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BD=D0=B0=20=D1=81=D0=B2=D0=B5=D1=82=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B9=20-=20=D1=8D=D1=82=D0=BE=20=D0=BD=D0=B5=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BC=D1=87=D0=B0=D1=82=D1=81=D0=BA=D0=B8=D0=B9=20=D0=BA?= =?UTF-8?q?=D1=80=D0=B0=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/src/app.rs | 64 +++++++++++++++++++++++++++++++++++-- code/src/database.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++ code/src/models.rs | 32 ++++++++++++++++--- 3 files changed, 163 insertions(+), 8 deletions(-) diff --git a/code/src/app.rs b/code/src/app.rs index 68cdda0..75bc1d0 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -5,7 +5,7 @@ use crate::{ material_tab::MaterialTabViewer, models::{ Equipment, LoginModalState, LoginStatus, Material, MaterialCategory, MaterialRow, - ModalStatus, ModalWinState, Position, Worker, + ModalStatus, ModalWinState, Position, Salary, Worker, }, tab::*, worker_tab::{self, *}, @@ -166,6 +166,7 @@ impl eframe::App for App<'_> { struct MainTabViewer { workers: Arc>>, equipment: Arc>>>, + salaries: Arc>>, db_oper: DBOperator, worker_tabs: WorkerTabViewer, @@ -189,6 +190,9 @@ impl Default for MainTabViewer { equipment: Arc::new(RwLock::new(Option::Some( rt.block_on(async { db_oper.get_equipment().await.unwrap() }), ))), + salaries: Arc::new(RwLock::new( + rt.block_on(async { db_oper.get_salaries().await.unwrap() }), + )), db_oper, worker_tabs: WorkerTabViewer::default(), worker_tree: egui_dock::DockState::new(vec![ @@ -303,7 +307,7 @@ impl MainTabViewer { }); row.col(|ui| { if self.is_admin { - if ui.button("Удалить").clicked() { + if ui.button("Списать").clicked() { self.equipment_modal_state.is_open = true; self.equipment_modal_state.status = ModalStatus::Remove; self.equipment_modal_state @@ -415,6 +419,32 @@ impl MainTabViewer { self.equipment_modal_state.data.get("inv_number").unwrap() )); } + let btext = match self.equipment_modal_state.status { + ModalStatus::Add => "Добавить", + ModalStatus::Edit => "Сохранить", + ModalStatus::Remove => "Списать", + }; + if ui.button(btext).clicked() { + match self.equipment_modal_state.status { + ModalStatus::Add => {} + ModalStatus::Edit => {} + ModalStatus::Remove => { + self.rt.block_on(async { + self.db_oper + .write_off_equipment( + self.equipment_modal_state + .data + .get("id") + .unwrap() + .parse::() + .unwrap(), + ) + .await + .unwrap(); + }); + } + } + } }); } } @@ -432,7 +462,35 @@ impl MainTabViewer { .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) { + /* + * Чё надо: + * 1. Список платежей. + */ + let table = TableBuilder::new(ui) + .striped(true) + .columns(Column::auto(), 4) + .header(30.0, |mut header| { + header.col(|ui| { + ui.heading("Имя сотрудника"); + }); + header.col(|ui| { + ui.heading("Размер"); + }); + header.col(|ui| { + ui.heading("Дата"); + }); + header.col(|ui| { + ui.heading("Описание"); + }); + }) + .body(|mut body| {}); + /* + * 2. Возможность добавить платежи. + * 3. Возможность назначить платежи сразу нескольким сотрудникам. + * 4. Возможность отменить платежи. + */ + } fn show_settings(&mut self, ui: &mut egui::Ui) { ui.checkbox(&mut self.is_dark_theme, "Тёмная тема"); diff --git a/code/src/database.rs b/code/src/database.rs index de8728a..0e1927f 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -1,3 +1,5 @@ +use bigdecimal::BigDecimal; +use chrono::DateTime; use sqlx::Row; use sqlx::mysql::MySqlPool; use sqlx::mysql::MySqlPoolOptions; @@ -71,6 +73,7 @@ impl DBOperator { inv_number: eq.inv_number, maintenance_date: eq.maintenance_date, worker: pworker, + is_written_off: eq.is_written_off, }); } Ok(rets) @@ -329,6 +332,78 @@ impl DBOperator { .unwrap(); Ok(ans) } + pub async fn write_off_equipment(&self, equipment_id: i32) -> Result { + match sqlx::query("UPDATE `equipment` SET is_written_off=1 WHERE id=?") + .bind(equipment_id) + .execute(&self.pool) + .await + { + Ok(_) => Ok(true), + Err(_) => Ok(false), + } + } + pub async fn get_salaries(&self) -> Result, sqlx::Error> { + let sals = sqlx::query_as::<_, SalaryRow>("SELECT * FROM `salary`") + .fetch_all(&self.pool) + .await?; + let mut rets: Vec = Vec::new(); + let workers = self.get_workers().await.unwrap(); + for sal in sals { + match workers.iter().find(|w| w.id == sal.worker_id) { + Some(w) => rets.push(Salary { + id: sal.id, + worker: w.clone(), + salary_date: sal.salary_date, + salary_size: sal.salary_size, + cluster_id: sal.cluster_id, + comment: sal.comment, + }), + None => {} + } + } + + Ok(rets) + } + pub async fn get_salary_clusters(&self) -> Result, sqlx::Error> { + let clus = sqlx::query_as::<_, SalaryCluster>("SELECT * FROM `salary_cluster`") + .fetch_all(&self.pool) + .await?; + Ok(clus) + } + pub async fn add_salary( + &self, + worker: Worker, + salary_date: DateTime, + salary_size: Option, + cluster: SalaryCluster, + comment: Option, + ) -> Result { + match sqlx::query("INSERT INTO Brewery.salary (id, worker_id, salary_size, salary_date, comment, cluster_id) VALUES(0, ?, ?, ?, ?, ?);") + .bind(worker.id) + .bind(salary_size.unwrap_or(worker.position.wage)) + .bind(salary_date) + .bind(comment.unwrap_or(String::new())) + .bind(cluster.id) + .execute(&self.pool) + .await{ + Ok(_) => Ok(true), + Err(_) => Ok(false) + } + } + pub async fn add_salary_cluster(&self, name: String) -> Result { + match sqlx::query("INSERT INTO `salary_cluster` (id, name) VALUES (0, ?)") + .bind(name) + .execute(&self.pool) + .await + { + Ok(_) => Ok(sqlx::query("SELECT LAST_INSERT_ID();") + .fetch_one(&self.pool) + .await + .unwrap() + .get(0)), + Err(_) => Ok(-1), + } + } } pub async fn estabilish_connection() -> Result<(), sqlx::Error> { diff --git a/code/src/models.rs b/code/src/models.rs index 6190428..4342cac 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -1,7 +1,10 @@ use std::{any::TypeId, ops::Deref}; use egui::TextBuffer; -use sqlx::types::{BigDecimal, chrono::DateTime}; +use sqlx::{ + prelude::FromRow, + types::{BigDecimal, chrono::DateTime}, +}; #[derive(Clone, Hash, sqlx::FromRow, PartialEq)] pub struct Position { @@ -34,11 +37,28 @@ pub struct WorkerRow { pub position_id: i32, pub is_fired: bool, } +#[derive(sqlx::FromRow, sqlx::Decode)] +pub struct SalaryRow { + pub id: i32, + pub worker_id: i32, + pub salary_size: BigDecimal, + pub salary_date: chrono::DateTime, + pub comment: String, + pub cluster_id: i32, +} + pub struct Salary { - id: i32, - worker: Worker, - salary_size: rust_decimal::Decimal, - salary_date: chrono::DateTime, + pub id: i32, + pub worker: Worker, + pub salary_size: BigDecimal, + pub salary_date: chrono::DateTime, + pub comment: String, + pub cluster_id: i32, +} +#[derive(sqlx::Decode, sqlx::FromRow, sqlx::Encode)] +pub struct SalaryCluster { + pub id: i32, + pub name: String, } #[derive(Default, Clone, Hash)] @@ -48,6 +68,7 @@ pub struct Equipment { pub inv_number: String, pub maintenance_date: chrono::DateTime, pub worker: Worker, + pub is_written_off: bool, } #[derive(sqlx::FromRow)] pub struct EquipmentRow { @@ -56,6 +77,7 @@ pub struct EquipmentRow { pub inv_number: String, pub maintenance_date: chrono::DateTime, pub worker_id: i32, + pub is_written_off: bool, } #[derive(Clone)] pub struct Material {