CSS WIP i cooked

This commit is contained in:
Léo 2025-02-07 01:01:54 +01:00
parent c33fb5a06e
commit c6a918a265
8 changed files with 192 additions and 152 deletions

View File

@ -2,7 +2,7 @@
<html lang="fr">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/png" href="src/assets/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>StockSeeker</title>
</head>

View File

@ -58,8 +58,11 @@
</script>
<template>
<h1>StockSeeker</h1>
<div class="header">
<img src="./assets/logo.png" alt="" style="width: 8rem">
<h1>StockSeeker</h1>
</div>
<Toast />
<Menubar :model="getMenuItems()" />
<Menubar class="menubar" :model="getMenuItems()" />
<RouterView />
</template>
</template>

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -31,4 +31,32 @@ h1 {
#app {
max-width: 1600px;
margin: 0 auto;
}
.menubar{
margin-bottom: 2rem;
}
.header{
display: flex;
}
.fieldset-container{
display: grid;
grid-template-columns: 2fr 2fr 1fr;
grid-template-rows: auto auto auto;
gap: 20px;
}
.fieldset-section{
padding:20px
}
.fieldset-wh-graph{
grid-column: 1;
}
.fieldset-quickadd{
grid-row: 1;
grid-column: 3;
}
.fieldset-list-wh-p{
grid-row: 1;
grid-column: 2;
}

View File

@ -11,6 +11,7 @@ import InputNumber from 'primevue/inputnumber';
import IftaLabel from 'primevue/iftalabel';
import Button from 'primevue/button'
import { useToast } from 'primevue/usetoast';
import Divider from 'primevue/divider';
const toast = useToast();
@ -131,64 +132,67 @@ function makeAlert(productsAlerts){
</script>
<template>
<div class="fieldset-container">
<Fieldset class="fieldset-section fieldset-p-graph" legend="Produits stockés" >
<Chart type="pie" :data="chartProductsData" :options="chartOptions"></Chart>
</Fieldset>
<Fieldset class="fieldset-section fieldset-wh-graph" legend="Listes des Entrepôts" >
<Chart type="bar" :data="chartWarehousesData" :options="chartOptions"></Chart>
</Fieldset>
<Fieldset class="fieldset-section fieldset-capacity-usage" legend="Used capacity" >
<ul>
<li v-for="warehouse in warehouses" :key="warehouse.id" style="list-style-type: none;">
{{ warehouse.name }}
<MeterGroup :value="getProductValues(warehouse)"></MeterGroup>
</li>
</ul>
</Fieldset>
<Fieldset class="fieldset-section fieldset-quickadd" legend="Ajout Rapide" >
<form @submit.prevent="productValueModifier">
<IftaLabel>
<AutoComplete inputId="reference" name="reference" optionLabel="reference" variant="filled" :suggestions="filteredRef" v-model="selectedRef" @complete="search" fluid></AutoComplete>
<label for="reference">Reference</label>
</IftaLabel>
<IftaLabel>
<InputNumber inputId="number-value" showButtons v-model="newValue" mode="decimal" fluid></InputNumber>
<label for="number-value">Ajouter/Soustraire</label>
</IftaLabel>
<Button
label="update"
type="submit"
class="p-button-primary"> </Button>
</form>
</Fieldset>
<Fieldset class="fieldset-section fieldset-list-wh-p" legend="Products et Entrepôt" >
<Carousel :value="products"
:numVisible="3"
:numScroll="1"
>
<template #item="slotProps">
<span v-if="slotProps.data.alert_enabled && slotProps.data.is_stock_low" style="color:red">
<Tag severity="danger" value="STOCK FAIBLE" rounded> </Tag>
</span>
<span v-else>
<Tag severity="info" value="STOCK OK" rounded> </Tag>
</span>
<p>{{ slotProps.data.name }}</p>
<p>{{ slotProps.data.reference }}</p>
<p>{{ slotProps.data.quantity }}</p>
<img :src="slotProps.data.image" alt="" style="border-radius: 8px; width: 150px;">
</template>
</Carousel>
<Divider />
<Carousel :value="warehouses"
:numVisible="3"
:numScroll="1"
>
<template #item="slotProps">
<p>{{ slotProps.data.name }}</p>
<p>{{ slotProps.data.location }}</p>
<p>{{ slotProps.data.max_capacity }}</p>
</template>
</Carousel>
</Fieldset>
<Fieldset legend="Produits stockés" style="max-width: 600px; margin: auto; padding:20px" toggleable>
<Chart type="pie" :data="chartProductsData" :options="chartOptions"></Chart>
</Fieldset>
<Fieldset legend="Listes des Entrepôts" style="max-width: 600px; margin: auto; padding:20px" toggleable>
<Chart type="bar" :data="chartWarehousesData" :options="chartOptions"></Chart>
</Fieldset>
<Fieldset legend="Used capacity" style="max-width: 600px; margin: auto; padding:20px" toggleable>
<ul>
<li v-for="warehouse in warehouses" :key="warehouse.id" style="list-style-type: none;">
{{ warehouse.name }}
<MeterGroup :value="getProductValues(warehouse)"></MeterGroup>
</li>
</ul>
</Fieldset>
<Fieldset legend="Products" style="max-width: 600px; margin: auto; padding:20px" toggleable>
<form @submit.prevent="productValueModifier">
<IftaLabel>
<AutoComplete inputId="reference" name="reference" optionLabel="reference" variant="filled" :suggestions="filteredRef" v-model="selectedRef" @complete="search"></AutoComplete>
<label for="reference">Reference</label>
</IftaLabel>
<IftaLabel>
<InputNumber inputId="number-value" showButtons v-model="newValue" mode="decimal"></InputNumber>
<label for="number-value">Ajouter/Soustraire</label>
</IftaLabel>
<Button
label="update"
type="submit"
class="p-button-primary"> </Button>
</form>
<Carousel :value="products"
:numVisible="3"
:numScroll="1"
>
<template #item="slotProps">
<span v-if="slotProps.data.alert_enabled && slotProps.data.is_stock_low" style="color:red">
<Tag severity="danger" value="STOCK FAIBLE" rounded> </Tag>
</span>
<span v-else>
<Tag severity="info" value="STOCK OK" rounded> </Tag>
</span>
<p>{{ slotProps.data.name }}</p>
<p>{{ slotProps.data.reference }}</p>
<p>{{ slotProps.data.quantity }}</p>
<img :src="slotProps.data.image" alt="" style="border-radius: 8px; width: 150px;">
</template>
</Carousel>
</Fieldset>
<Fieldset legend="Warehouses" style="max-width: 600px; margin: auto; padding:20px" toggleable>
<Carousel :value="warehouses"
:numVisible="3"
:numScroll="1"
>
<template #item="slotProps">
<p>{{ slotProps.data.name }}</p>
<p>{{ slotProps.data.location }}</p>
<p>{{ slotProps.data.max_capacity }}</p>
</template>
</Carousel>
</Fieldset>
</div>
</template>

View File

@ -8,6 +8,7 @@ import Dialog from 'primevue/dialog';
import InputText from 'primevue/inputtext';
import Password from 'primevue/password';
import Button from 'primevue/button';
import IftaLabel from 'primevue/iftalabel';
const { userInfo, isAuth } = useAuth();
@ -127,25 +128,25 @@ async function modify_user() {
<Dialog header="Modifier l'utilisateur" v-model:visible="showDialog" :style="{ width: '30vw' }" modal:draggable="false">
<form @submit.prevent="modify_user">
<div class="field">
<label for="modify-username">
Nom d'utilisateur
</label>
<InputText id="modify-username" v-model="usernameModify" placeholder="Nom d'utilisateur" class="w-full" required />
<IftaLabel>
<InputText id="modify-username" v-model="usernameModify" placeholder="" class="w-full" required fluid />
<label for="modify-username">Nom d'utilisateur :</label>
</IftaLabel>
</div>
<div class="field">
<label for="modify-email">
Email
</label>
<InputText id="modify-email" v-model="emailModify" type="email" placeholder="Adresse email" class="w-full" required />
<IftaLabel>
<InputText id="modify-email" v-model="emailModify" type="email" class="w-full" required fluid />
<label for="modify-email">Email :</label>
</IftaLabel>
</div>
<div class="field">
<label for="modify-password">
Mot de passe
</label>
<Password id="modify-password" v-model="passwordModify" feedback toggleMask placeholder="Nouveau mot de passe" class="w-full" required />
<IftaLabel>
<Password id="modify-password" v-model="passwordModify" feedback toggleMask class="w-full" required fluid/>
<label for="modify-password">Mot de passe :</label>
</IftaLabel>
</div>
<div class="flex justify-content-end mt-3">
<Button label="Annuler" class="p-button-text" @click="showDialog = false">
<Button label="Annuler" severity="secondary" class="p-button-text" @click="showDialog = false">
Annuler
</Button>
<Button label="Enregistrer" type="submit" class="p-button-primary">

View File

@ -8,8 +8,7 @@ import InputText from 'primevue/inputtext';
import Button from 'primevue/button';
import PMessage from 'primevue/message';
import InputNumber from 'primevue/inputnumber';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
import IftaLabel from 'primevue/iftalabel';
import Checkbox from 'primevue/checkbox';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
@ -17,12 +16,17 @@ import Tag from 'primevue/tag';
import Badge from 'primevue/badge';
import FileUpload from 'primevue/fileupload';
import MultiSelect from 'primevue/multiselect';
import Dialog from 'primevue/dialog';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
const toast = useToast();
const formatDate = (date) => DateTime.fromISO(date).toLocaleString(DateTime.DATETIME_MED);
const products = ref([]);
const visible = ref(false);
const productName = ref('');
const productReference = ref('');
const productDescription = ref('');
@ -266,18 +270,21 @@ try {
<div>
<h2>Tableau de bord</h2>
<div class="register form-container">
<h2>Créer un produit</h2>
<Button label="Crée un nouveau produit" @click="visible = true" />
<Dialog v-model:visible="visible" modal header="Nouveau Produit" :style="{ width: '25rem' }">
<form @submit.prevent="create_product">
<div class="form">
<InputGroup>
<InputGroupAddon>Nom :</InputGroupAddon>
<IftaLabel>
<InputText
name="register-product"
type="text"
id="register-product"
v-model="productName"
required
fluid
/>
</InputGroup>
<label for="register-product">Nom :</label>
</IftaLabel>
<p-message
v-if="registerErrors.name"
severity="error"
@ -285,16 +292,16 @@ try {
{{ registerErrors.name }}
</p-message>
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Reference :</InputGroupAddon>
<IftaLabel>
<InputText
type="text"
id="register-reference"
v-model="productReference"
fluid
/>
</InputGroup>
<label for="register-reference">Reference :</label>
</IftaLabel>
<p-message
v-if="registerErrors.description"
severity="error"
@ -304,14 +311,15 @@ try {
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Description :</InputGroupAddon>
<IftaLabel>
<InputText
type="text"
id="register-description"
v-model="productDescription"
fluid
/>
</InputGroup>
<label for="register-description">Description :</label>
</IftaLabel>
<p-message
v-if="registerErrors.description"
severity="error"
@ -321,8 +329,7 @@ try {
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Quantité :</InputGroupAddon>
<IftaLabel>
<InputNumber
id="register-quantity"
inputId="integeronly"
@ -330,36 +337,47 @@ try {
fluid
required
/>
</InputGroup>
<label for="register-quantity">Quantité :</label>
</IftaLabel>
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>
Activer une alerte ?
<InputGroupAddon>
<Checkbox
:binary="true"
id="register-alert"
v-model="productAlert"
/>
</InputGroupAddon>
<InputNumber
v-if="productAlert"
id="register-stock-limit"
inputId="integeronly"
v-model="productStockLimit"
fluid
/>
<IftaLabel>
<InputNumber
:disabled="!productAlert"
id="register-stock-limit"
inputId="integeronly"
v-model="productStockLimit"
fluid
/>
<label for="register-stock-limit">Alerte en dessous de :</label>
</IftaLabel>
</InputGroup>
</div>
<div class="form">
<IftaLabel>
<MultiSelect
name="register-warehouses"
v-model="selectedWarehouses"
:options="warehouses"
optionLabel="name"
placeholder="Sélectionner un entrepôt"
:invalid="!!registerErrors.warehouses"
fluid
></MultiSelect>
<label for="register-warehouses">Entrepôt :</label>
</IftaLabel>
</div>
<div class="form">
<InputGroup >
<InputGroupAddon>Image :</InputGroupAddon>
<InputGroupAddon v-if="b64Img">
<img :src="b64Img" alt="Image" style="width: 6rem">
<Button icon="pi pi-times" severity="secondary" @click="resetForms()"/>
</InputGroupAddon>
<FileUpload
<FileUpload
name="productImage"
accept="image/*"
mode="basic"
@ -370,20 +388,10 @@ try {
:chooseLabel="'Choisir une image'"
@uploader="handleFileUpload($event,true)"
/>
</InputGroup>
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Entrepôt :</InputGroupAddon>
<MultiSelect
v-model="selectedWarehouses"
:options="warehouses"
optionLabel="name"
placeholder="Sélectionner un entrepôt"
display="chip"
:invalid="!!registerErrors.warehouses"
></MultiSelect>
</InputGroup>
<div v-if="b64Img">
<img :src="b64Img" alt="Image" style="width: 6rem">
<Button icon="pi pi-times" severity="secondary" @click="resetForms()"/>
</div>
</div>
<div class="alert">
<p-message
@ -419,12 +427,15 @@ try {
{{ registerErrors.reference }}
</p-message>
</div>
<Button type="button" label="Cancel" severity="secondary" class="p-button-text" @click="visible = false" autofocus />
<Button
label="Créer"
type="submit"
class="p-button-primary"
@click="visible = false"
/>
</form>
</Dialog>
</div>
<DataTable
@ -437,15 +448,7 @@ try {
tableStyle="min-width: 50rem"
removableSort
>
<template #header>
<div class="text-end pb-4">
<Button
icon="pi pi-external-link"
label="Export"
@click="exportCSV($event)"
/>
</div>
</template>
<Column field="image"editor="true">
<template #body="slotProps">
@ -454,7 +457,7 @@ try {
style="width: 6rem"
/>
</template>
<template #editor="slotProps">
<template #editor>
<FileUpload
name="editProductImage"
accept="image/*"
@ -471,9 +474,6 @@ try {
<img :src="b64Modif" alt="Image" style="width: 6rem">
<Button icon="pi pi-times" severity="secondary" @click="resetImg(true)"/>
</div>
<div v-else>
<img :src="slotProps.data.image" alt="Image" style="width: 6rem;">
</div>
</template>
</Column>

View File

@ -6,10 +6,10 @@ import InputText from 'primevue/inputtext';
import Button from 'primevue/button';
import PMessage from 'primevue/message';
import InputNumber from 'primevue/inputnumber';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Dialog from 'primevue/dialog';
import IftaLabel from 'primevue/iftalabel';
const toast = useToast();
@ -17,6 +17,7 @@ const warehouses = ref([]);
const warehouseName = ref('');
const warehouseLocation = ref('');
const warehouseMaxCapacity = ref(0);
const visible = ref(false);
const registerErrors = ref({ name: '', location: '', max_capacity: ''});
const modifyErrors = ref({name:'', location:'', max_capacity:''})
@ -129,36 +130,39 @@ onMounted(async () => {
<template>
<div>
<h2>Gérer les entrepôts</h2>
<Button label="Crée un nouvel entrepôt" @click="visible = true"></Button>
<Dialog v-model:visible="visible" modal header="Nouvel Entrepôt" :style="{ width: '25rem' }">
<div class="register form-container">
<h2>Créer un entrepôt</h2>
<form @submit.prevent="create_warehouse">
<div class="form">
<InputGroup>
<InputGroupAddon>Nom :</InputGroupAddon>
<InputText type="text" id="register-warehouse" v-model="warehouseName" required />
</InputGroup>
<IftaLabel>
<InputText name="register-name" type="text" id="register-name" v-model="warehouseName" required fluid/>
<label for="register-name">Nom de l'entrepôt :</label>
</IftaLabel>
<p-message v-if="registerErrors.name" severity="error">{{ registerErrors.name }}</p-message>
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Location :</InputGroupAddon>
<InputText type="text" id="register-location" v-model="warehouseLocation" required />
</InputGroup>
<IftaLabel>
<InputText name="register-location" type="text" id="register-location" v-model="warehouseLocation" required fluid/>
<label for="register-location">Location :</label>
</IftaLabel>
<p-message v-if="registerErrors.location" severity="error">{{ registerErrors.location }}</p-message>
</div>
<div class="form">
<InputGroup>
<InputGroupAddon>Capacité maximale :</InputGroupAddon>
<InputNumber id="register-max-capacity" v-model="warehouseMaxCapacity" required />
</InputGroup>
<IftaLabel>
<InputNumber name="register-max-capacity" id="register-max-capacity" v-model="warehouseMaxCapacity" required fluid />
<label for="register-max-capacity">Capacité totale :</label>
</IftaLabel>
<p-message v-if="registerErrors.max_capacity" severity="error">{{ registerErrors.max_capacity }}</p-message>
</div>
<Button label="Créer" type="submit" class="p-button-primary" />
<Button type="button" label="Cancel" severity="secondary" class="p-button-text" @click="visible = false"></Button>
<Button type="submit" label="Créer" class="p-button-primary" @click="visible = false" />
</form>
</div>
</Dialog>
<DataTable v-model:editingRows="editingRows" editMode="row" dataKey="id" @row-edit-save="onRowEditSave" :value="warehouses" tableStyle="min-width: 50rem" removableSort>