676 lines
21 KiB
Vue
676 lines
21 KiB
Vue
<template>
|
|
<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>
|
|
|
|
<q-dialog v-model="showQr">
|
|
<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-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>
|
|
|
|
<q-dialog v-model="showHistoryForm">
|
|
<q-card style="min-width:420px">
|
|
<q-card-section>
|
|
<div class="text-h6">Ajouter une entrée</div>
|
|
</q-card-section>
|
|
<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>
|
|
<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-card-actions align="right">
|
|
<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 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 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>
|
|
<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="primary" icon="o_check" label="Marquer comme terminé"
|
|
@click="setTaskDone(selectedHistory)" />
|
|
</q-card-section>
|
|
<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 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>
|
|
|
|
</q-page>
|
|
</template>
|
|
|
|
<script>
|
|
import { date } from 'quasar'
|
|
import imageCompression from 'browser-image-compression'
|
|
import QRCode from 'qrcode'
|
|
|
|
export default {
|
|
name: 'StockItem',
|
|
props: ['itemRef', 'shortId'],
|
|
data () {
|
|
return {
|
|
showHistoryForm: false,
|
|
pendingHistory: null,
|
|
pendingHistoryType: 'comment',
|
|
changed: false,
|
|
hasFile: false,
|
|
username: null,
|
|
qrCodeDataUrl: null,
|
|
showQr: false,
|
|
item: {},
|
|
showHistory: false,
|
|
selectedHistory: null
|
|
}
|
|
},
|
|
computed: {
|
|
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 || []
|
|
},
|
|
originalItem () {
|
|
return this.stock.find(item => {
|
|
return (item) ? item.ref === this.itemRef : false
|
|
}) || []
|
|
},
|
|
itemId () {
|
|
return this.$store.state.core.firebase.stock.findIndex(item => {
|
|
return (item) ? item.ref === this.itemRef : false
|
|
})
|
|
},
|
|
history () {
|
|
return this.$store.state.core.firebase.history.filter(item => {
|
|
return item.ref === this.itemRef
|
|
}).sort((a, b) => {
|
|
return (a.timestamp > b.timestamp) ? 1 : -1
|
|
}) || []
|
|
}
|
|
},
|
|
created: function () {
|
|
if (this.shortId) {
|
|
let itemRef = this.stock.find(item => {
|
|
return item.short_id === parseInt(this.shortId)
|
|
})?.ref
|
|
if (itemRef) this.$router.push(`/item/${itemRef}`)
|
|
}
|
|
this.loadItem()
|
|
this.$watch(
|
|
() => this.itemRef,
|
|
() => { this.loadItem() }
|
|
)
|
|
},
|
|
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')
|
|
},
|
|
openHistoryForm () {
|
|
this.showHistoryForm = true
|
|
},
|
|
async addHistory () {
|
|
this.$q.loading.show()
|
|
let historyDate = new Date()
|
|
let file = null
|
|
if (this.hasFile) {
|
|
file = await this.uploadFile(this.$refs.uploader.files[0])
|
|
}
|
|
this.$store.dispatch('core/addToCollection', {
|
|
collection: 'history',
|
|
data: {
|
|
ref: this.itemRef,
|
|
text: this.pendingHistory,
|
|
type: this.pendingHistoryType,
|
|
user: this.$store.state.core.username,
|
|
image_file: file,
|
|
date: historyDate.toISOString()
|
|
}
|
|
}).then(_ => {
|
|
this.$store.dispatch('core/loadAppData').then(_ => {
|
|
this.loadItem()
|
|
this.showHistoryForm = false
|
|
this.pendingHistory = null
|
|
this.hasFile = false
|
|
this.$refs.uploader.reset()
|
|
this.$q.loading.hide()
|
|
})
|
|
})
|
|
},
|
|
removeHistory (data) {
|
|
this.$q.dialog({
|
|
title: 'Supprimer ?',
|
|
message: 'Es-tu certain de vouloir supprimer cette entrée ?',
|
|
ok: 'Supprimer',
|
|
cancel: 'Annuler'
|
|
}).onOk(() => {
|
|
this.$store.dispatch('core/removeFromCollection', {
|
|
collection: 'history',
|
|
data
|
|
}).then(_ => {
|
|
this.$store.dispatch('core/loadAppData').then(_ => {
|
|
this.loadItem()
|
|
this.showHistory = false
|
|
this.selectedHistory = null
|
|
this.$q.notify('Supprimé !')
|
|
})
|
|
})
|
|
})
|
|
},
|
|
updateItem () {
|
|
this.$q.loading.show()
|
|
this.$store.dispatch('core/updateItem', {
|
|
collection: 'stock',
|
|
itemId: this.itemId,
|
|
data: this.item
|
|
}).then(_ => {
|
|
this.$q.notify({
|
|
message: 'Enregistré !',
|
|
color: 'primary',
|
|
avatar: '/gyoza.svg',
|
|
timeout: 2000
|
|
})
|
|
this.changed = false
|
|
this.$store.dispatch('core/loadAppData').then(_ => {
|
|
this.loadItem()
|
|
this.$q.loading.hide()
|
|
})
|
|
})
|
|
},
|
|
setTaskDone (history) {
|
|
this.$store.dispatch('core/updateItem', {
|
|
collection: 'history',
|
|
itemId: history.id,
|
|
data: {
|
|
id: history.id,
|
|
solved_at: new Date().toISOString(),
|
|
solved_by: this.username
|
|
}
|
|
}).then(_ => {
|
|
this.$store.dispatch('core/loadAppData').then(_ => {
|
|
this.loadItem()
|
|
this.showHistory = false
|
|
this.selectedHistory = null
|
|
})
|
|
})
|
|
},
|
|
async uploadFile (file) {
|
|
const options = {
|
|
maxSizeMB: 1,
|
|
maxWidthOrHeight: 2000,
|
|
useWebWorker: true
|
|
}
|
|
try {
|
|
return await imageCompression(file, options)
|
|
} catch (error) {
|
|
console.error('Error compressing image:', error)
|
|
}
|
|
},
|
|
getImageUrl (history, image, thumb = false) {
|
|
return this.$pb.files.getURL(history, image, { thumb: thumb ? '300x300f' : null })
|
|
},
|
|
loadItem () {
|
|
let item = this.stock.find(item => {
|
|
return (item) ? item.ref === this.itemRef : false
|
|
}) || []
|
|
this.item = { ...item }
|
|
},
|
|
async generateQRCode () {
|
|
this.showQr = true
|
|
try {
|
|
const url = await QRCode.toDataURL(window.location.href, {
|
|
errorCorrectionLevel: 'H',
|
|
width: 800,
|
|
margin: 1
|
|
})
|
|
this.qrCodeDataUrl = url
|
|
} catch (error) {
|
|
console.error('Error generating QR code:', error)
|
|
}
|
|
},
|
|
openQr () {
|
|
const win = window.open()
|
|
win.document.write(`<img src="${this.qrCodeDataUrl}" alt="QR Code" style="max-height:500px;max-width:500px" />`)
|
|
win.document.close()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.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>
|