1
0

add report page

This commit is contained in:
Rokas Puzonas 2023-05-16 21:43:28 +03:00
parent 38a201baef
commit 10162217e3
10 changed files with 273 additions and 68 deletions

View File

@ -15,7 +15,7 @@
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.0",
"@tauri-apps/cli": "^1.2.2",
"@tauri-apps/cli": "^1.3.1",
"@tsconfig/svelte": "^3.0.0",
"@types/node": "^18.7.10",
"@unocss/transformer-directives": "^0.50.4",

62
lab2/pnpm-lock.yaml generated
View File

@ -3,7 +3,7 @@ lockfileVersion: 5.4
specifiers:
'@sveltejs/vite-plugin-svelte': ^2.0.0
'@tauri-apps/api': ^1.2.0
'@tauri-apps/cli': ^1.2.2
'@tauri-apps/cli': ^1.3.1
'@tsconfig/svelte': ^3.0.0
'@types/node': ^18.7.10
'@unocss/transformer-directives': ^0.50.4
@ -23,7 +23,7 @@ dependencies:
devDependencies:
'@sveltejs/vite-plugin-svelte': 2.0.3_svelte@3.56.0+vite@4.1.4
'@tauri-apps/cli': 1.2.3
'@tauri-apps/cli': 1.3.1
'@tsconfig/svelte': 3.0.0
'@types/node': 18.15.0
'@unocss/transformer-directives': 0.50.4
@ -370,8 +370,8 @@ packages:
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
dev: false
/@tauri-apps/cli-darwin-arm64/1.2.3:
resolution: {integrity: sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==}
/@tauri-apps/cli-darwin-arm64/1.3.1:
resolution: {integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@ -379,8 +379,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-darwin-x64/1.2.3:
resolution: {integrity: sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==}
/@tauri-apps/cli-darwin-x64/1.3.1:
resolution: {integrity: sha512-fKcAUPVFO3jfDKXCSDGY0MhZFF/wDtx3rgFnogWYu4knk38o9RaqRkvMvqJhLYPuWaEM5h6/z1dRrr9KKCbrVg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@ -388,8 +388,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-linux-arm-gnueabihf/1.2.3:
resolution: {integrity: sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==}
/@tauri-apps/cli-linux-arm-gnueabihf/1.3.1:
resolution: {integrity: sha512-+4H0dv8ltJHYu/Ma1h9ixUPUWka9EjaYa8nJfiMsdCI4LJLNE6cPveE7RmhZ59v9GW1XB108/k083JUC/OtGvA==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
@ -397,8 +397,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-gnu/1.2.3:
resolution: {integrity: sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==}
/@tauri-apps/cli-linux-arm64-gnu/1.3.1:
resolution: {integrity: sha512-Pj3odVO1JAxLjYmoXKxcrpj/tPxcA8UP8N06finhNtBtBaxAjrjjxKjO4968KB0BUH7AASIss9EL4Tr0FGnDuw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -406,8 +406,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-musl/1.2.3:
resolution: {integrity: sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==}
/@tauri-apps/cli-linux-arm64-musl/1.3.1:
resolution: {integrity: sha512-tA0JdDLPFaj42UDIVcF2t8V0tSha40rppcmAR/MfQpTCxih6399iMjwihz9kZE1n4b5O4KTq9GliYo50a8zYlQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -415,8 +415,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-linux-x64-gnu/1.2.3:
resolution: {integrity: sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==}
/@tauri-apps/cli-linux-x64-gnu/1.3.1:
resolution: {integrity: sha512-FDU+Mnvk6NLkqQimcNojdKpMN4Y3W51+SQl+NqG9AFCWprCcSg62yRb84751ujZuf2MGT8HQOfmd0i77F4Q3tQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -424,8 +424,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-linux-x64-musl/1.2.3:
resolution: {integrity: sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==}
/@tauri-apps/cli-linux-x64-musl/1.3.1:
resolution: {integrity: sha512-MpO3akXFmK8lZYEbyQRDfhdxz1JkTBhonVuz5rRqxwA7gnGWHa1aF1+/2zsy7ahjB2tQ9x8DDFDMdVE20o9HrA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -433,8 +433,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-win32-ia32-msvc/1.2.3:
resolution: {integrity: sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==}
/@tauri-apps/cli-win32-ia32-msvc/1.3.1:
resolution: {integrity: sha512-9Boeo3K5sOrSBAZBuYyGkpV2RfnGQz3ZhGJt4hE6P+HxRd62lS6+qDKAiw1GmkZ0l1drc2INWrNeT50gwOKwIQ==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@ -442,8 +442,8 @@ packages:
dev: true
optional: true
/@tauri-apps/cli-win32-x64-msvc/1.2.3:
resolution: {integrity: sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==}
/@tauri-apps/cli-win32-x64-msvc/1.3.1:
resolution: {integrity: sha512-wMrTo91hUu5CdpbElrOmcZEoJR4aooTG+fbtcc87SMyPGQy1Ux62b+ZdwLvL1sVTxnIm//7v6QLRIWGiUjCPwA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@ -451,20 +451,20 @@ packages:
dev: true
optional: true
/@tauri-apps/cli/1.2.3:
resolution: {integrity: sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==}
/@tauri-apps/cli/1.3.1:
resolution: {integrity: sha512-o4I0JujdITsVRm3/0spfJX7FcKYrYV1DXJqzlWIn6IY25/RltjU6qbC1TPgVww3RsRX63jyVUTcWpj5wwFl+EQ==}
engines: {node: '>= 10'}
hasBin: true
optionalDependencies:
'@tauri-apps/cli-darwin-arm64': 1.2.3
'@tauri-apps/cli-darwin-x64': 1.2.3
'@tauri-apps/cli-linux-arm-gnueabihf': 1.2.3
'@tauri-apps/cli-linux-arm64-gnu': 1.2.3
'@tauri-apps/cli-linux-arm64-musl': 1.2.3
'@tauri-apps/cli-linux-x64-gnu': 1.2.3
'@tauri-apps/cli-linux-x64-musl': 1.2.3
'@tauri-apps/cli-win32-ia32-msvc': 1.2.3
'@tauri-apps/cli-win32-x64-msvc': 1.2.3
'@tauri-apps/cli-darwin-arm64': 1.3.1
'@tauri-apps/cli-darwin-x64': 1.3.1
'@tauri-apps/cli-linux-arm-gnueabihf': 1.3.1
'@tauri-apps/cli-linux-arm64-gnu': 1.3.1
'@tauri-apps/cli-linux-arm64-musl': 1.3.1
'@tauri-apps/cli-linux-x64-gnu': 1.3.1
'@tauri-apps/cli-linux-x64-musl': 1.3.1
'@tauri-apps/cli-win32-ia32-msvc': 1.3.1
'@tauri-apps/cli-win32-x64-msvc': 1.3.1
dev: true
/@tsconfig/svelte/3.0.0:

View File

@ -1,4 +1,4 @@
use crate::{models::{Manager, Factory, ManagerData, FactoryData, Id, Process, ProcessData}, manager_repo, factory_repo, process_repo};
use crate::{models::{Manager, Factory, ManagerData, FactoryData, Id, Process, ProcessData}, manager_repo, factory_repo, process_repo, report_gen::{self, FactoryUsedSpace}};
use sqlx::{Pool, MySql};
use tauri::State;
use anyhow::Result;
@ -9,10 +9,10 @@ pub struct Database {
#[tauri::command]
pub async fn add_manager_factory(
factory: FactoryData,
manager: ManagerData,
db: State<'_, Database>
) -> Result<(Id, Id)> {
factory: FactoryData,
manager: ManagerData,
db: State<'_, Database>
) -> Result<(Id, Id)> {
let mut tx = db.pool.begin().await?;
let manager_id = manager_repo::add(&mut tx, &manager).await?;
let factory_id = factory_repo::add(&mut tx, manager_id, &factory).await?;
@ -117,11 +117,37 @@ pub async fn update_process(id: Id, process: ProcessData, db: State<'_, Database
#[tauri::command]
pub async fn add_process(
process: ProcessData,
db: State<'_, Database>
) -> Result<Id> {
process: ProcessData,
db: State<'_, Database>
) -> Result<Id> {
let mut tx = db.pool.begin().await?;
let id = process_repo::add(&mut tx, &process).await?;
tx.commit().await?;
Ok(id)
}
// --------------------- Report generation ---------------------------
#[tauri::command]
pub async fn get_factories_by_used_space(
from: f32,
to: f32,
location: String,
db: State<'_, Database>
) -> Result<Vec<FactoryUsedSpace>> {
let mut tx = db.pool.begin().await?;
let results = report_gen::get_factories_by_used_space(&mut tx, from, to, &location).await?;
tx.commit().await?;
Ok(results)
}
#[tauri::command]
pub async fn get_processess_of_factory(
factory: Id,
db: State<'_, Database>
) -> Result<Vec<ProcessData>> {
let mut tx = db.pool.begin().await?;
let results = report_gen::get_processess_of_factory(&mut tx, factory).await?;
tx.commit().await?;
Ok(results)
}

View File

@ -5,12 +5,13 @@ mod models;
mod factory_repo;
mod manager_repo;
mod process_repo;
mod report_gen;
mod api;
use std::{env, process::exit};
use dotenv::dotenv;
use models::{ManagerData, FactoryData, ProcessData};
use models::{ManagerData, FactoryData, ProcessData, Id};
use sqlx::{Pool, MySql, mysql::MySqlPoolOptions, Row, Transaction};
use api::*;
@ -46,9 +47,13 @@ async fn set_foreign_key_checks(pool: &Pool<MySql>, enable: bool) -> Result<()>
Ok(())
}
async fn add_test_process(tx: &mut MySqlTransaction<'_>, process: ProcessData) -> Result<()> {
process_repo::add(tx, &process).await?;
Ok(())
async fn add_test_processess(tx: &mut MySqlTransaction<'_>, processess: &[ProcessData]) -> Result<Vec<Id>> {
let mut ids = vec![];
for process in processess {
let id = process_repo::add(tx, &process).await?;
ids.push(id);
}
Ok(ids)
}
async fn add_test_data(pool: &Pool<MySql>) -> Result<()> {
@ -62,26 +67,20 @@ async fn add_test_data(pool: &Pool<MySql>) -> Result<()> {
};
let factory = FactoryData {
name: "Big factory".into(),
location: "idk".into(),
location: "Kaunas, fabriko gatve 1".into(),
floor_size: 10.0,
};
let id = manager_repo::add(&mut tx, &manager).await?;
factory_repo::add(&mut tx, id, &factory).await?;
let manager_id = manager_repo::add(&mut tx, &manager).await?;
let factory_id = factory_repo::add(&mut tx, manager_id, &factory).await?;
add_test_process(&mut tx, ProcessData {
name: "Certifuge 9000".into(),
size: 10.0
}).await?;
let process_ids = add_test_processess(&mut tx, &[
ProcessData { name: "Certifuge 9000".into(), size: 10.0 },
ProcessData { name: "Certifuge 9001".into(), size: 20.0 },
ProcessData { name: "Certifuge 9002".into(), size: 30.0 }
]).await?;
add_test_process(&mut tx, ProcessData {
name: "Certifuge 9001".into(),
size: 20.0
}).await?;
add_test_process(&mut tx, ProcessData {
name: "Certifuge 9002".into(),
size: 30.0
}).await?;
factory_repo::add_process(&mut tx, factory_id, process_ids[0]).await?;
factory_repo::add_process(&mut tx, factory_id, process_ids[1]).await?;
tx.commit().await?;
Ok(())
@ -130,7 +129,10 @@ async fn main() {
list_processess,
update_process,
delete_process,
add_process
add_process,
get_factories_by_used_space,
get_processess_of_factory
])
.run(tauri::generate_context!())
.expect("error while running tauri application");

View File

@ -45,7 +45,7 @@ pub struct Process {
pub size: f32
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Serialize, FromRow)]
pub struct ProcessData {
pub name: String,
pub size: f32

View File

@ -0,0 +1,61 @@
use anyhow::Result;
use serde::Serialize;
use sqlx::{Transaction, MySql, FromRow};
use crate::models::{Id, ProcessData};
type MySqlTransaction<'a> = Transaction<'a, MySql>;
#[derive(Debug, Serialize, FromRow)]
pub struct FactoryUsedSpace {
manager_name: String,
factory_id: Id,
used_size: f32,
used_percent: f32
}
pub async fn get_factories_by_used_space(tx: &mut MySqlTransaction<'_>, from: f32, to: f32, location: &str) -> Result<Vec<FactoryUsedSpace>> {
let results = sqlx::query_as::<_, FactoryUsedSpace>(r#"
SELECT
CONCAT(manager.FIRST_NAME, " ", manager.SURNAME) as manager_name,
factory.ID as factory_id,
SUM(process.SIZE) as used_size,
ROUND(CAST(SUM(process.SIZE) as FLOAT) / CAST(factory.FLOOR_SIZE as FLOAT) * 100, 2) as used_percent
FROM
factory
LEFT JOIN factory_supports_processes
ON factory_supports_processes.FK_FACTORY_ID = factory.ID
LEFT JOIN process
ON process.ID = factory_supports_processes.FK_PROCESS_ID
LEFT JOIN manager
ON manager.ID = factory.FK_MANAGER_ID
WHERE LOCATE(?, factory.LOCATION)>0
GROUP BY factory.ID
HAVING ? <= used_percent AND used_percent <= ?
"#)
.bind(location)
.bind(from)
.bind(to)
.fetch_all(tx).await?;
Ok(results)
}
pub async fn get_processess_of_factory(tx: &mut MySqlTransaction<'_>, factory_id: Id) -> Result<Vec<ProcessData>> {
let results = sqlx::query_as::<_, ProcessData>("
SELECT
process.NAME as name,
process.SIZE as size
FROM
factory
LEFT JOIN factory_supports_processes
ON factory_supports_processes.FK_FACTORY_ID = factory.ID
LEFT JOIN process
ON process.ID = factory_supports_processes.FK_PROCESS_ID
WHERE factory.ID = 1
")
.bind(factory_id)
.fetch_all(tx).await?;
Ok(results)
}

View File

@ -1,12 +1,14 @@
<script lang="ts">
import Router, {location} from "svelte-spa-router"
import { Header, Content, SideNav, SideNavItems, SideNavLink } from "carbon-components-svelte";
import Home from './routes/Home.svelte'
import FactoriesManagers from './routes/Factories-Managers.svelte'
import { factories, factory_processess, list_factories, list_factory_processess, list_managers, list_processess, managers, processess } from "./lib/api";
import { onMount } from "svelte";
import { Building, Calibrate, ReportData } from "carbon-icons-svelte";
import Home from './routes/Home.svelte'
import FactoriesManagers from './routes/Factories-Managers.svelte'
import Processess from "./routes/Processess.svelte";
import { Building, Calibrate } from "carbon-icons-svelte";
import Report from "./routes/Report.svelte";
onMount(async () => {
$managers = await list_managers()
@ -23,6 +25,12 @@
<Header href="/#/" company="ICE" platformName="Production" bind:isSideNavOpen />
<SideNav bind:isOpen={isSideNavOpen} rail>
<SideNavItems>
<SideNavLink
icon={ReportData}
text="Report"
href="/#/report"
isSelected={$location == "/report"}
/>
<SideNavLink
icon={Building}
text="Factories & Managers"
@ -42,6 +50,7 @@
<Router routes={{
"/": Home,
"/factories-managers": FactoriesManagers,
"/processess": Processess
"/processess": Processess,
"/report": Report
}} />
</Content>

View File

@ -1,6 +1,5 @@
<script lang="ts">
import { Form, TextInput, NumberInput, DataTable } from "carbon-components-svelte";
import { Form, TextInput, NumberInput } from "carbon-components-svelte";
import type { FactoryData } from "./api"
export let factory: FactoryData = {

View File

@ -30,6 +30,14 @@ export interface ProcessData {
}
export interface Process extends ProcessData {
id: Id
}
export interface FactoryUsedSpace {
manager_name: string
factory_id: Id,
used_size: number,
used_percent: number
}
export let factory_processess = writable<Record<Id, Id[]>>([])
@ -201,3 +209,12 @@ export async function update_factory_processess(factory_id: Id, process_ids: Id[
return factory_processess
})
}
export async function get_factories_by_used_space(from: number, to: number, location: string): Promise<FactoryUsedSpace[]> {
return await invoke("get_factories_by_used_space", { from, to, location })
}
export async function get_processess_of_factory(factory: Id): Promise<ProcessData[]> {
return await invoke("get_processess_of_factory", { factory })
}

View File

@ -0,0 +1,91 @@
<script lang="ts">
import { Button, DataTable, NumberInput, TextInput } from "carbon-components-svelte";
import { factories, processess, get_factories_by_used_space, get_processess_of_factory, type ProcessData } from "../lib/api";
import { writable } from "svelte/store";
let from_bound = 50.00
let to_bound = 100.00
let location = "Kaunas"
let rows = writable([])
async function requestReport() {
let newRows = []
const results = await get_factories_by_used_space(from_bound, to_bound, location)
for (var result of results) {
var factory = $factories.find(factory => factory.id == result.factory_id)
if (factory === undefined) continue
const processess = await get_processess_of_factory(result.factory_id) as (ProcessData & { id: string })[]
for (const process of processess) {
process.id = process.name
}
newRows.push({
id: result.factory_id,
manager_name: result.manager_name,
factory_name: factory.name,
factory_size: factory.floor_size,
used_percent: `${result.used_percent}%`,
used_size: result.used_size,
processess
})
}
$rows = newRows
}
</script>
<div class="flex flex-row gap-1rem mb-1rem">
<NumberInput
bind:value={from_bound}
required
hideSteppers
min={0}
invalidText="Can't be negative"
label="Lower used size bound (%)"
/>
<NumberInput
bind:value={to_bound}
required
hideSteppers
min={0}
invalidText="Can't be negative"
label="Upper used size bound (%)"
/>
<TextInput
bind:value={location}
required
invalidText="Location can't be empty"
labelText="Location"
/>
<div class="pt">
<Button on:click={requestReport}>
Go
</Button>
</div>
</div>
<DataTable
expandable
zebra
rows={$rows}
headers={[
{ key: "manager_name", value: "Manager" },
{ key: "factory_name", value: "Factory name" },
{ key: "factory_size", value: "Factory size"},
{ key: "used_size", value: "Used size" },
{ key: "used_percent", value: "Used percent" }
]}
>
<svelte:fragment slot="expanded-row" let:row>
<DataTable
size="compact"
rows={row.processess}
headers={[
{ key: "name", value: "Process Name" },
{ key: "size", value: "Process Size" }
]}
>
</DataTable>
</svelte:fragment>
</DataTable>