Nice UI
This commit is contained in:
@ -1,244 +1,310 @@
|
||||
<template>
|
||||
<q-page class="q-pa-md">
|
||||
<q-btn @click="generateQRCode" class="float-right" icon="qr_code"></q-btn>
|
||||
<div class="q-ma-none text-h3 text-weight-bolder row" :class="{'text-faded': !item.name}">
|
||||
<span class="q-mr-md">{{ item.name || '---- -- ----' }}</span>
|
||||
<q-chip square size="lg" class="text-white q-mr-md" color="secondary">{{item.ref}}</q-chip>
|
||||
<q-chip square outline size="lg" class="q-mr-md" color="secondary">{{item.short_id}}</q-chip>
|
||||
<q-chip square size="lg" v-if="item.deleted" color="red">Supprimé</q-chip>
|
||||
<q-page class="q-pa-lg item-page">
|
||||
<q-btn flat round icon="o_arrow_back" class="q-mb-md" @click="$router.back()" />
|
||||
|
||||
<div class="item-header row items-center q-mb-md">
|
||||
<div class="col">
|
||||
<div class="text-h4 text-weight-bold" :class="{'text-faded': !item.name}">
|
||||
{{ item.name || 'Sans nom' }}
|
||||
</div>
|
||||
<div class="row items-center q-mt-xs q-gutter-x-sm">
|
||||
<q-chip dense square color="primary" text-color="white" class="text-weight-medium">
|
||||
{{ item.ref }}
|
||||
</q-chip>
|
||||
<q-chip dense square outline color="grey-5">
|
||||
ID {{ item.short_id }}
|
||||
</q-chip>
|
||||
<span class="text-grey-5 text-body2">{{ item.type }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<q-btn flat round size="lg" icon="o_qr_code" @click="generateQRCode">
|
||||
<q-tooltip>QR Code</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
|
||||
<div class="status-bar row q-gutter-sm q-mb-lg">
|
||||
<q-chip :color="stateColor(item.state)" text-color="white" icon="o_palette" size="md" class="status-chip">
|
||||
{{ item.state || 'État inconnu' }}
|
||||
</q-chip>
|
||||
<q-chip :color="item.working === true ? 'green' : item.working === false ? 'red' : 'grey-6'"
|
||||
text-color="white"
|
||||
:icon="item.working === true ? 'o_check_circle' : item.working === false ? 'o_cancel' : 'o_help'"
|
||||
size="md"
|
||||
class="status-chip">
|
||||
{{ item.working === true ? 'Fonctionnel' : item.working === false ? 'H.S.' : 'Inconnu' }}
|
||||
</q-chip>
|
||||
<q-chip :color="item.available ? 'green' : 'red'"
|
||||
text-color="white"
|
||||
:icon="item.available ? 'o_inventory_2' : 'o_remove_shopping_cart'"
|
||||
size="md"
|
||||
class="status-chip">
|
||||
{{ item.available ? 'En stock' : 'Absent' }}
|
||||
</q-chip>
|
||||
<q-chip v-if="item.deleted" color="red" text-color="white" icon="o_delete" size="md" class="status-chip">
|
||||
Supprimé
|
||||
</q-chip>
|
||||
</div>
|
||||
|
||||
<div class="row q-col-gutter-lg">
|
||||
<div class="col-12 col-md-7 col-lg-8">
|
||||
<q-card flat class="info-card">
|
||||
<q-card-section class="q-pb-none">
|
||||
<div class="text-subtitle1 text-weight-medium text-primary">Informations générales</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-sm-6">
|
||||
<q-input v-model="item.name"
|
||||
:disable="item.deleted"
|
||||
filled
|
||||
label="Nom"
|
||||
color="primary"
|
||||
@update:model-value="changed = true" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<q-input v-model="item.owner"
|
||||
:disable="item.deleted"
|
||||
filled
|
||||
label="Propriétaire"
|
||||
color="primary"
|
||||
@update:model-value="changed = true" />
|
||||
</div>
|
||||
</div>
|
||||
<q-input v-model="item.comment"
|
||||
:disable="item.deleted"
|
||||
filled
|
||||
type="textarea"
|
||||
rows="3"
|
||||
label="Commentaire"
|
||||
color="primary"
|
||||
class="q-mt-md"
|
||||
@update:model-value="changed = true" />
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<q-card flat class="info-card q-mt-md">
|
||||
<q-card-section class="q-pb-none">
|
||||
<div class="text-subtitle1 text-weight-medium text-primary">État</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="row items-center q-mb-md">
|
||||
<span class="text-caption text-grey-5 q-mr-md" style="min-width:100px">Cosmétique</span>
|
||||
<q-btn-toggle
|
||||
no-caps
|
||||
spread
|
||||
:disable="item.deleted"
|
||||
v-model="item.state"
|
||||
@update:model-value="changed = true"
|
||||
toggle-color="primary"
|
||||
text-color="white"
|
||||
:options="stateOptions"
|
||||
class="state-toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="row items-center q-mb-md">
|
||||
<span class="text-caption text-grey-5 q-mr-md" style="min-width:100px">Fonctionnel</span>
|
||||
<q-btn-toggle
|
||||
no-caps
|
||||
:disable="item.deleted"
|
||||
v-model="item.working"
|
||||
@update:model-value="changed = true"
|
||||
toggle-color="primary"
|
||||
text-color="white"
|
||||
:options="[
|
||||
{label: 'Oui', value: true},
|
||||
{label: '?', value: null},
|
||||
{label: 'Non', value: false}
|
||||
]"
|
||||
class="status-toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="row items-center q-mb-md">
|
||||
<span class="text-caption text-grey-5 q-mr-md" style="min-width:100px">En stock</span>
|
||||
<q-btn-toggle
|
||||
no-caps
|
||||
:disable="item.deleted"
|
||||
v-model="item.available"
|
||||
@update:model-value="changed = true"
|
||||
toggle-color="primary"
|
||||
text-color="white"
|
||||
:options="[
|
||||
{label: 'Oui', value: true},
|
||||
{label: 'Non', value: false}
|
||||
]"
|
||||
class="status-toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="row items-center">
|
||||
<span class="text-caption text-grey-5 q-mr-md" style="min-width:100px">Supprimé</span>
|
||||
<q-btn-toggle
|
||||
no-caps
|
||||
v-model="item.deleted"
|
||||
@update:model-value="changed = true"
|
||||
toggle-color="primary"
|
||||
text-color="white"
|
||||
:options="[
|
||||
{label: 'Oui', value: true},
|
||||
{label: 'Non', value: false}
|
||||
]"
|
||||
class="status-toggle"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<div class="fixed-bottom-right q-pa-lg save-bar" v-if="changed">
|
||||
<q-btn color="primary"
|
||||
icon="o_save"
|
||||
label="Enregistrer"
|
||||
:disable="originalItem.deleted"
|
||||
@click="updateItem()"
|
||||
class="save-btn" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-5 col-lg-4">
|
||||
<div class="row items-center q-mb-sm">
|
||||
<div class="text-subtitle1 text-weight-medium text-primary">Historique</div>
|
||||
<q-space />
|
||||
<q-btn flat dense round icon="o_add_circle" color="primary" size="sm" @click="openHistoryForm()">
|
||||
<q-tooltip>Ajouter une entrée</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
|
||||
<div v-if="history.length === 0" class="text-grey-5 text-center q-py-xl">
|
||||
<q-icon name="o_history" size="3rem" class="q-mb-sm" />
|
||||
<div>Aucun historique pour cet item</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="timeline">
|
||||
<div v-for="event in history" :key="event.id"
|
||||
class="timeline-item"
|
||||
@click="showHistory = true; selectedHistory = event">
|
||||
<div class="timeline-dot" :class="event.type === 'issue' ? 'dot-issue' : 'dot-comment'">
|
||||
<q-icon :name="event.type === 'issue' ? (event.solved_at ? 'o_check_circle' : 'o_error') : 'o_chat'"
|
||||
size="14px" color="white" />
|
||||
</div>
|
||||
<div class="timeline-content">
|
||||
<div class="timeline-card">
|
||||
<div v-if="event.image_file" class="timeline-image">
|
||||
<img :src="getImageUrl(event, event.image_file, true)" alt="" />
|
||||
</div>
|
||||
<div class="timeline-body">
|
||||
<div class="timeline-text" v-html="event.text.split('\n').join('<br>')"></div>
|
||||
<div class="timeline-meta">
|
||||
<span class="text-capitalize text-weight-medium">{{ event.user }}</span>
|
||||
<span class="text-grey-5">· {{ getDate(event.date || event.created) }}</span>
|
||||
</div>
|
||||
<div v-if="event.solved_at" class="timeline-solved">
|
||||
<q-icon name="o_check" size="xs" color="green" />
|
||||
Résolu par <span class="text-capitalize">{{ event.solved_by }}</span>
|
||||
le {{ getDate(event.solved_at) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-btn outline color="primary"
|
||||
icon="o_add"
|
||||
label="Ajouter une entrée"
|
||||
class="full-width q-mt-md"
|
||||
@click="openHistoryForm()" />
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="q-ma-none q-pb-md text-grey">{{item.type}}</h5>
|
||||
|
||||
<q-dialog v-model="showQr">
|
||||
<q-card style="width: 500px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ item.name }}</div>
|
||||
<q-card style="width: 480px">
|
||||
<q-card-section class="text-center">
|
||||
<div class="text-h6 q-mb-sm">{{ item.name }}</div>
|
||||
<div class="text-caption text-grey-5 q-mb-md">{{ item.ref }}</div>
|
||||
<q-img :src="qrCodeDataUrl" v-if="qrCodeDataUrl" alt="QR Code" style="max-height:360px;max-width:360px" class="rounded-borders" />
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none">
|
||||
<q-img :src="qrCodeDataUrl" v-if="qrCodeDataUrl" alt="QR Code" class="" style="max-height:500px;max-width:500px" />
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="OK" v-close-popup />
|
||||
<q-btn flat label="Print" @click="openQr"/>
|
||||
<q-card-actions align="center">
|
||||
<q-btn flat label="Fermer" color="grey" v-close-popup />
|
||||
<q-btn flat label="Imprimer" color="primary" @click="openQr" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<div class="row q-col-gutter-xl">
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="q-ma-none q-pb-md text-light">Informations</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<q-input v-model="item.name"
|
||||
:disable="item.deleted"
|
||||
type="text"
|
||||
label="Nom"
|
||||
outlined color="secondary"
|
||||
class="q-mb-md"
|
||||
@update:model-value="changed = true">
|
||||
</q-input>
|
||||
<q-input v-model="item.owner"
|
||||
:disable="item.deleted"
|
||||
outlined color="secondary" stack-label label="Propriétaire" class="q-mb-md"
|
||||
@input="changed = true"/>
|
||||
<q-field borderless stack-label label="Etat cosmétique" class="q-mb-md">
|
||||
<q-btn-toggle
|
||||
class="q-mt-sm"
|
||||
no-caps
|
||||
:disable="item.deleted"
|
||||
v-model="item.state"
|
||||
@update:model-value="changed = true"
|
||||
toggle-color="secondary"
|
||||
text-color="black"
|
||||
:options="[
|
||||
{label: 'Neuf', value: 'Neuf'},
|
||||
{label: 'Excellent', value: 'Excellent'},
|
||||
{label: 'Bon', value: 'Bon'},
|
||||
{label: 'Moyen', value: 'Moyen'},
|
||||
{label: 'Abimé', value: 'Abimé'},
|
||||
{label: 'Inutilisable', value: 'Inutilisable'}
|
||||
]"
|
||||
/>
|
||||
</q-field>
|
||||
<q-field borderless stack-label label="Fonctionnel" class="q-mb-md">
|
||||
<q-btn-toggle
|
||||
class="q-mt-sm"
|
||||
no-caps
|
||||
:disable="item.deleted"
|
||||
v-model="item.working"
|
||||
:toggle-color="item.working ? 'green' : 'red'"
|
||||
text-color="black"
|
||||
:options="[
|
||||
{label: '✔', value: true},
|
||||
{label: '?', value: null},
|
||||
{label: '✘', value: false}
|
||||
]"
|
||||
@input="changed = true"
|
||||
/>
|
||||
</q-field>
|
||||
<q-field borderless stack-label label="En stock" class="q-mb-md">
|
||||
<q-btn-toggle
|
||||
class="q-mt-sm"
|
||||
no-caps
|
||||
:disable="item.deleted"
|
||||
v-model="item.available"
|
||||
:toggle-color="item.available ? 'green' : 'red'"
|
||||
text-color="black"
|
||||
:options="[
|
||||
{label: '✔', value: true},
|
||||
{label: '✘', value: false}
|
||||
]"
|
||||
@input="changed = true"
|
||||
/>
|
||||
</q-field>
|
||||
<q-field borderless stack-label label="Supprimé" class="q-mb-md">
|
||||
<q-btn-toggle
|
||||
no-caps
|
||||
v-model="item.deleted"
|
||||
:toggle-color="item.deleted ? 'green' : 'red'"
|
||||
text-color="black"
|
||||
:options="[
|
||||
{label: 'Oui', value: true},
|
||||
{label: 'Non', value: false}
|
||||
]"
|
||||
@input="changed = true"
|
||||
class="q-mt-sm"
|
||||
/>
|
||||
</q-field>
|
||||
<q-input
|
||||
:disable="item.deleted"
|
||||
v-model="item.comment"
|
||||
@update:model-value="changed = true"
|
||||
type="textarea"
|
||||
:max-height="100"
|
||||
rows="5"
|
||||
outlined color="secondary" stack-label label="Commentaire" class="q-mb-md"
|
||||
inverted
|
||||
/>
|
||||
<q-btn :disabled="!changed || originalItem.deleted"
|
||||
@click="updateItem()"
|
||||
color="primary"
|
||||
:flat="!changed"
|
||||
>Enregistrer</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="q-ma-none q-pb-md text-light">Historique</h4>
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<q-btn outline icon="add" label="ajouter une entrée" color="primary" @click="openHistoryForm()"></q-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-list bordered separator class="rounded-borders">
|
||||
<q-item clickable
|
||||
v-for="event in history"
|
||||
:key="event.id"
|
||||
@click="showHistory = true;selectedHistory = event"
|
||||
>
|
||||
<q-item-section top thumbnail class="q-ml-none" style="margin:-8px 0 -8px -16px">
|
||||
<img
|
||||
:src="getImageUrl(event, event.image_file, true)"
|
||||
alt="photo"
|
||||
style="object-fit: cover"
|
||||
v-if="event.image_file"
|
||||
class="full-height"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label lines="3" v-html="event.text.split('\n').join('</br>')"></q-item-label>
|
||||
<q-item-label caption>
|
||||
<q-icon name="task" class="q-mr-sm" size="xs"
|
||||
v-if="event.type === 'issue'"
|
||||
:color="event.solved_at ? 'green' : 'grey'"
|
||||
/>
|
||||
<span class="text-capitalize">{{ event.user }}</span>
|
||||
<template v-if="event.solved_at">
|
||||
<q-icon name="arrow_right" size="sm"/>
|
||||
fait par <span class="text-capitalize">{{ event.solved_by }}</span> le {{getDate(event.solved_at)}}
|
||||
</template>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side top>
|
||||
<q-item-label caption>{{ getDate(event.date || event.created) }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="showHistoryForm">
|
||||
<q-card>
|
||||
<q-card style="min-width:420px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">Ajouter une entrée</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
v-model="pendingHistory"
|
||||
autofocus
|
||||
type="textarea"
|
||||
label="Description"
|
||||
:max-height="100"
|
||||
rows="3"
|
||||
invertedd
|
||||
color="secondary"
|
||||
/>
|
||||
<br/>
|
||||
<q-btn-group outline spread>
|
||||
<q-btn :outline="pendingHistoryType !== 'comment'" color="secondary" label="Info" icon="info" @click="pendingHistoryType = 'comment'"/>
|
||||
<q-btn :outline="pendingHistoryType !== 'issue'" color="secondary" label="Tâche" icon="task" @click="pendingHistoryType = 'issue'"/>
|
||||
<q-card-section class="q-pt-none">
|
||||
<q-btn-group spread outline class="full-width q-mb-md">
|
||||
<q-btn :outline="pendingHistoryType !== 'comment'"
|
||||
:color="pendingHistoryType === 'comment' ? 'primary' : 'grey'"
|
||||
label="Commentaire"
|
||||
icon="o_chat"
|
||||
@click="pendingHistoryType = 'comment'" />
|
||||
<q-btn :outline="pendingHistoryType !== 'issue'"
|
||||
:color="pendingHistoryType === 'issue' ? 'primary' : 'grey'"
|
||||
label="Tâche"
|
||||
icon="o_task"
|
||||
@click="pendingHistoryType = 'issue'" />
|
||||
</q-btn-group>
|
||||
<br/>
|
||||
<q-uploader
|
||||
:accept="'.jpg,.png'"
|
||||
:factory="uploadFile"
|
||||
label="Uploader une photo"
|
||||
@added="hasFile = true"
|
||||
ref="uploader"
|
||||
no-thumbnails
|
||||
hide-upload-btn
|
||||
flat
|
||||
bordered
|
||||
color="secondary"
|
||||
/>
|
||||
<br/>
|
||||
<q-input v-model="pendingHistory"
|
||||
autofocus
|
||||
filled
|
||||
type="textarea"
|
||||
rows="3"
|
||||
label="Description"
|
||||
color="primary" />
|
||||
<q-uploader class="q-mt-md"
|
||||
:accept="'.jpg,.png'"
|
||||
:factory="uploadFile"
|
||||
label="Photo (optionnel)"
|
||||
@added="hasFile = true"
|
||||
ref="uploader"
|
||||
no-thumbnails
|
||||
hide-upload-btn
|
||||
flat
|
||||
bordered
|
||||
color="primary" />
|
||||
</q-card-section>
|
||||
<q-separator></q-separator>
|
||||
<q-separator />
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat color="grey" @click.stop="showHistoryForm = false">Annuler</q-btn>
|
||||
<q-btn flat color="primary" @click.stop="addHistory()">Ok</q-btn>
|
||||
<q-btn flat label="Annuler" color="grey" @click.stop="showHistoryForm = false" />
|
||||
<q-btn flat label="Ajouter" color="primary" @click.stop="addHistory()" :disable="!pendingHistory" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="showHistory">
|
||||
<q-card>
|
||||
<img :src="getImageUrl(selectedHistory, selectedHistory.image_file)"
|
||||
alt="photo"
|
||||
v-if="selectedHistory.image_file"
|
||||
/>
|
||||
<q-card style="min-width:420px; max-width:560px">
|
||||
<img v-if="selectedHistory.image_file"
|
||||
:src="getImageUrl(selectedHistory, selectedHistory.image_file)"
|
||||
alt="photo"
|
||||
class="history-detail-image" />
|
||||
<q-card-section>
|
||||
<div v-html="selectedHistory.text.split('\n').join('</br>')"></div>
|
||||
<div class="text-caption text-grey">
|
||||
<div class="text-body1" v-html="selectedHistory.text.split('\n').join('<br>')"></div>
|
||||
<div class="q-mt-sm text-caption text-grey-5">
|
||||
<q-chip dense :color="selectedHistory.type === 'issue' ? 'orange' : 'primary'"
|
||||
text-color="white"
|
||||
:label="selectedHistory.type === 'issue' ? 'Tâche' : 'Commentaire'"
|
||||
size="sm"
|
||||
class="q-mr-sm" />
|
||||
<span class="text-capitalize">{{ selectedHistory.user }}</span>
|
||||
<q-separator vertical />
|
||||
<span>{{ getDate(selectedHistory.date || selectedHistory.created) }}</span>
|
||||
<span>· {{ getDate(selectedHistory.date || selectedHistory.created) }}</span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="selectedHistory.type === 'issue' && !selectedHistory.solved_at">
|
||||
<q-btn outline color="secondary" label="Marquer comme terminé" @click="setTaskDone(selectedHistory)"></q-btn>
|
||||
<q-btn outline color="primary" icon="o_check" label="Marquer comme terminé"
|
||||
@click="setTaskDone(selectedHistory)" />
|
||||
</q-card-section>
|
||||
<q-separator/>
|
||||
<q-card-section v-if="selectedHistory.solved_at" class="q-pt-none">
|
||||
<div class="text-caption text-green">
|
||||
Résolu par <span class="text-capitalize">{{ selectedHistory.solved_by }}</span>
|
||||
le {{ getDate(selectedHistory.solved_at) }}
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-separator />
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat color="red" @click.stop="removeHistory(selectedHistory)">Supprimer</q-btn>
|
||||
<q-btn flat color="grey" @click.stop="showHistory = false;selectedHistory = null">Fermer</q-btn>
|
||||
<q-btn flat label="Supprimer" color="red" @click.stop="removeHistory(selectedHistory)" />
|
||||
<q-btn flat label="Fermer" color="grey" @click.stop="showHistory = false; selectedHistory = null" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
@ -270,8 +336,15 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
category () {
|
||||
return this.item.type || ''
|
||||
stateOptions () {
|
||||
return [
|
||||
{ label: 'Neuf', value: 'Neuf' },
|
||||
{ label: 'Excellent', value: 'Excellent' },
|
||||
{ label: 'Bon', value: 'Bon' },
|
||||
{ label: 'Moyen', value: 'Moyen' },
|
||||
{ label: 'Abimé', value: 'Abimé' },
|
||||
{ label: 'Inutilisable', value: 'Inutilisable' }
|
||||
]
|
||||
},
|
||||
stock () {
|
||||
return this.$store.state.core.firebase.stock || []
|
||||
@ -299,21 +372,29 @@ export default {
|
||||
let itemRef = this.stock.find(item => {
|
||||
return item.short_id === parseInt(this.shortId)
|
||||
})?.ref
|
||||
console.log('Redirecting to item with ref:', itemRef)
|
||||
if (itemRef) this.$router.push(`/item/${itemRef}`)
|
||||
}
|
||||
this.loadItem()
|
||||
this.$watch(
|
||||
() => this.itemRef,
|
||||
(newId, oldId) => {
|
||||
this.loadItem()
|
||||
}
|
||||
() => { this.loadItem() }
|
||||
)
|
||||
},
|
||||
mounted () {
|
||||
mounted () {
|
||||
this.username = this.$q.localStorage.getItem('username')
|
||||
},
|
||||
methods: {
|
||||
stateColor (state) {
|
||||
const colors = {
|
||||
Neuf: 'green-8',
|
||||
Excellent: 'green',
|
||||
Bon: 'lime-9',
|
||||
Moyen: 'orange',
|
||||
Abimé: 'red',
|
||||
Inutilisable: 'grey-7'
|
||||
}
|
||||
return colors[state] || 'grey'
|
||||
},
|
||||
getDate (timestamp) {
|
||||
return date.formatDate(timestamp, 'DD/MM/YY - HH:mm')
|
||||
},
|
||||
@ -322,7 +403,7 @@ export default {
|
||||
},
|
||||
async addHistory () {
|
||||
this.$q.loading.show()
|
||||
let date = new Date()
|
||||
let historyDate = new Date()
|
||||
let file = null
|
||||
if (this.hasFile) {
|
||||
file = await this.uploadFile(this.$refs.uploader.files[0])
|
||||
@ -335,14 +416,13 @@ export default {
|
||||
type: this.pendingHistoryType,
|
||||
user: this.$store.state.core.username,
|
||||
image_file: file,
|
||||
date: date.toISOString()
|
||||
date: historyDate.toISOString()
|
||||
}
|
||||
}).then(response => {
|
||||
}).then(_ => {
|
||||
this.$store.dispatch('core/loadAppData').then(_ => {
|
||||
this.loadItem()
|
||||
this.showHistoryForm = false
|
||||
this.pendingHistory = null
|
||||
this.pendingHistoryDate = null
|
||||
this.hasFile = false
|
||||
this.$refs.uploader.reset()
|
||||
this.$q.loading.hide()
|
||||
@ -352,7 +432,7 @@ export default {
|
||||
removeHistory (data) {
|
||||
this.$q.dialog({
|
||||
title: 'Supprimer ?',
|
||||
message: "Il est possible que tu sois Meth, nous sommes donc légalement obligés de te demander : es-tu absolument sur d'être certain de vouloir effectuer cette action irréversible ?",
|
||||
message: 'Es-tu certain de vouloir supprimer cette entrée ?',
|
||||
ok: 'Supprimer',
|
||||
cancel: 'Annuler'
|
||||
}).onOk(() => {
|
||||
@ -362,6 +442,8 @@ export default {
|
||||
}).then(_ => {
|
||||
this.$store.dispatch('core/loadAppData').then(_ => {
|
||||
this.loadItem()
|
||||
this.showHistory = false
|
||||
this.selectedHistory = null
|
||||
this.$q.notify('Supprimé !')
|
||||
})
|
||||
})
|
||||
@ -373,12 +455,11 @@ export default {
|
||||
collection: 'stock',
|
||||
itemId: this.itemId,
|
||||
data: this.item
|
||||
}).then(response => {
|
||||
// this.$speech(`sugoï, domo arigato senpai !`)
|
||||
}).then(_ => {
|
||||
this.$q.notify({
|
||||
message: 'Enregistré !',
|
||||
color: 'secondary',
|
||||
avatar: '/gyoza_logo_nobg.png',
|
||||
color: 'primary',
|
||||
avatar: '/gyoza.svg',
|
||||
timeout: 2000
|
||||
})
|
||||
this.changed = false
|
||||
@ -406,7 +487,6 @@ export default {
|
||||
})
|
||||
},
|
||||
async uploadFile (file) {
|
||||
// Resize and compress the image before uploading
|
||||
const options = {
|
||||
maxSizeMB: 1,
|
||||
maxWidthOrHeight: 2000,
|
||||
@ -441,7 +521,6 @@ export default {
|
||||
}
|
||||
},
|
||||
openQr () {
|
||||
// Take the data url qr code and display it in a new tab
|
||||
const win = window.open()
|
||||
win.document.write(`<img src="${this.qrCodeDataUrl}" alt="QR Code" style="max-height:500px;max-width:500px" />`)
|
||||
win.document.close()
|
||||
@ -451,7 +530,146 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.q-field__label{
|
||||
padding-bottom:16px !important;
|
||||
.item-page {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.item-header .text-h4 {
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-chip {
|
||||
font-weight: 500;
|
||||
border-radius: 10px;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.state-toggle,
|
||||
.status-toggle {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.state-toggle :deep(.q-btn) {
|
||||
min-width: 48px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-toggle :deep(.q-btn) {
|
||||
min-width: 64px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.save-bar {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
border-radius: 14px;
|
||||
padding: 8px 28px;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 20px rgba(6, 182, 212, 0.3);
|
||||
}
|
||||
|
||||
.timeline {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
padding: 4px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
margin-top: 6px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dot-comment {
|
||||
background: #06b6d4;
|
||||
}
|
||||
|
||||
.dot-issue {
|
||||
background: #f97316;
|
||||
}
|
||||
|
||||
.timeline-item:not(:last-child) .timeline-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-item:not(:last-child) .timeline-content::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -28px;
|
||||
top: 34px;
|
||||
bottom: -10px;
|
||||
width: 2px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.timeline-card {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
transition: border-color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.timeline-item:hover .timeline-card {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.timeline-image img {
|
||||
width: 100%;
|
||||
max-height: 160px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.timeline-body {
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.timeline-text {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.timeline-meta {
|
||||
font-size: 0.75rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.timeline-solved {
|
||||
font-size: 0.72rem;
|
||||
color: #4ade80;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.history-detail-image {
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user