feat: store details log, i18n
parent
b06dc48e4a
commit
1416dee41e
|
|
@ -31,6 +31,8 @@
|
|||
"apexcharts-clevision": "^3.28.5",
|
||||
"chart.js": "^4.4.0",
|
||||
"cookie-es": "^1.0.0",
|
||||
"date-fns": "^3.0.6",
|
||||
"export-from-json": "^1.7.3",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"mapbox-gl": "2.15.0",
|
||||
"ofetch": "^1.3.3",
|
||||
|
|
@ -50,8 +52,7 @@
|
|||
"vue3-apexcharts": "^1.4.4",
|
||||
"vue3-perfect-scrollbar": "^1.6.1",
|
||||
"vuetify": "3.3.22",
|
||||
"webfontloader": "^1.6.28",
|
||||
"export-from-json": "^1.7.3"
|
||||
"webfontloader": "^1.6.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config-vue": "^0.43.1",
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ dependencies:
|
|||
cookie-es:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
date-fns:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
export-from-json:
|
||||
specifier: ^1.7.3
|
||||
version: 1.7.3
|
||||
|
|
@ -3201,6 +3204,10 @@ packages:
|
|||
/dash-get@1.0.2:
|
||||
resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==}
|
||||
|
||||
/date-fns@3.0.6:
|
||||
resolution: {integrity: sha512-W+G99rycpKMMF2/YD064b2lE7jJGUe+EjOES7Q8BIGY8sbNdbgcs9XFTZwvzc9Jx1f3k7LB7gZaZa7f8Agzljg==}
|
||||
dev: false
|
||||
|
||||
/de-indent@1.0.2:
|
||||
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
||||
dev: true
|
||||
|
|
|
|||
|
|
@ -28,4 +28,15 @@ export default [
|
|||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
},
|
||||
{
|
||||
title: 'XADMIN',
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
children: [
|
||||
{
|
||||
title: 'Application Log',
|
||||
to: { name: 'xadmin-application-log' },
|
||||
icon: { icon: 'tabler-bug' },
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -28,4 +28,15 @@ export default [
|
|||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
},
|
||||
{
|
||||
title: 'XADMIN',
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
children: [
|
||||
{
|
||||
title: 'Application Log',
|
||||
to: { name: 'xadmin-application-log' },
|
||||
icon: { icon: 'tabler-bug' },
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ const exportEXCEL = () => {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 Invoice Widgets -->
|
||||
<!-- 👉 Statistics Widgets -->
|
||||
<VCard class="mb-6">
|
||||
<VCardText>
|
||||
<VRow>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import StoreHeader from '@/views/pages/store/view/StoreHeader.vue'
|
|||
import StoreTabAdmin from '@/views/pages/store/view/StoreTabAdmin.vue'
|
||||
import StoreTabGeneral from '@/views/pages/store/view/StoreTabGeneral.vue'
|
||||
import StoreTabItem from '@/views/pages/store/view/StoreTabItem.vue'
|
||||
import StoreTabLog from '@/views/pages/store/view/StoreTabLog.vue'
|
||||
import StoreTabRemote from '@/views/pages/store/view/StoreTabRemote.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
|
@ -11,14 +12,13 @@ const route = useRoute('store-details')
|
|||
|
||||
const storeTab = ref(route.query.tab || 'general')
|
||||
|
||||
console.log(route.query.dbHost)
|
||||
|
||||
// tabs
|
||||
const tabs = [
|
||||
{ title: 'General', icon: 'tabler-settings', tab: 'general' },
|
||||
{ title: t('Item'), icon: 'tabler-shirt-sport', tab: 'item' },
|
||||
{ title: t('Remote'), icon: 'tabler-brand-openvpn', tab: 'remote' },
|
||||
{ title: 'Admin', icon: 'tabler-lock', tab: 'admin' },
|
||||
{ title: 'Log', icon: 'tabler-bug', tab: 'log' },
|
||||
]
|
||||
|
||||
const { data: storeData } = await useApi<any>(`/stores/${route.query.storeId}/details?dbHost=${route.query.dbHost}`)
|
||||
|
|
@ -72,6 +72,11 @@ const { data: storeData } = await useApi<any>(`/stores/${route.query.storeId}/de
|
|||
<VWindowItem>
|
||||
<StoreTabAdmin :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
|
||||
<!-- 👉 Log -->
|
||||
<VWindowItem>
|
||||
<StoreTabLog :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
</VWindow>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,243 @@
|
|||
<script setup lang="ts">
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: '', key: 'data-table-expand' },
|
||||
{ title: t('businessDate'), key: 'businessDate' },
|
||||
{ title: t('createDate'), key: 'createDate' },
|
||||
{ title: t('createUserId'), key: 'createUserId' },
|
||||
{ title: t('rtlLocId'), key: 'rtlLocId' },
|
||||
{ title: t('wkstnId'), key: 'wkstnId' },
|
||||
{ title: t('logLevel'), key: 'logLevel' },
|
||||
{ title: t('threadName'), key: 'threadName' },
|
||||
{ title: '', key: 'actions', sortable: false },
|
||||
])
|
||||
|
||||
const selectedCountry = ref()
|
||||
const selectedBrand = ref()
|
||||
const selectedNbPos = ref()
|
||||
|
||||
// for reload process
|
||||
const storesList = ref<any>('')
|
||||
const isLoading = ref(false)
|
||||
|
||||
const searchQuery = ref<any>('')
|
||||
|
||||
// Data table options
|
||||
const { data: dtListData } = await useApi<any>(createUrl('/xadmin/application/log/5108?AWkstnId=20&BeginDate=20231221&EndDate=20231221'))
|
||||
|
||||
storesList.value = dtListData.value
|
||||
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
|
||||
const country = computed(() => {
|
||||
const allItems = storesList.value.map((store: { pays: any }) => store.pays)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueItems = allItems.filter((country: any, index: any, self: string | any[]) => self.indexOf(country) === index)
|
||||
const sortedItems = uniqueItems.sort()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedItems.map((country: any) => ({ title: country, value: country }))
|
||||
})
|
||||
|
||||
const brand = computed(() => {
|
||||
const allItems = storesList.value.map((store: { enseigne: any }) => store.enseigne)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueItems = allItems.filter((brand: any, index: any, self: string | any[]) => self.indexOf(brand) === index)
|
||||
const sortedItems = uniqueItems.sort()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedItems.map((brand: any) => ({ title: brand, value: brand }))
|
||||
})
|
||||
|
||||
const nbPos = computed(() => {
|
||||
const allItems = storesList.value.map((store: { nbcaisses: number }) => store.nbcaisses)
|
||||
const uniqueItems = Array.from(new Set(allItems)) as number[] // Utilisez une assertion de type
|
||||
const sortedItems = uniqueItems.sort((a, b) => a - b) // Triez les nombres en ordre croissant
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedItems.map((nbPos: number) => ({ title: nbPos, value: nbPos }))
|
||||
})
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let filtered = storesList.value
|
||||
|
||||
// If a brand is selected, filter the records for this brand
|
||||
if (selectedBrand.value)
|
||||
filtered = filtered.filter((store: { enseigne: any }) => store.enseigne === selectedBrand.value)
|
||||
|
||||
if (selectedCountry.value)
|
||||
filtered = filtered.filter((store: { pays: any }) => store.pays === selectedCountry.value)
|
||||
|
||||
if (selectedNbPos.value)
|
||||
filtered = filtered.filter((store: { nbcaisses: any }) => store.nbcaisses === selectedNbPos.value)
|
||||
|
||||
// If a search query is provided, filter the records for this query
|
||||
if (searchQuery.value) {
|
||||
filtered = filtered.filter((store: { [s: string]: unknown } | ArrayLike<unknown>) =>
|
||||
Object.values(store).some(value =>
|
||||
String(value).toLowerCase().includes(searchQuery.value.toLowerCase()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const selectedStore = ref(null)
|
||||
const isDialogVisible = ref(false)
|
||||
|
||||
const openPosList = (store: any) => {
|
||||
selectedStore.value = store
|
||||
isDialogVisible.value = true
|
||||
}
|
||||
|
||||
interface Store {
|
||||
id_structure: number
|
||||
caisses: Caisse[]
|
||||
}
|
||||
interface Caisse {
|
||||
id_caisse: number
|
||||
ip: string
|
||||
}
|
||||
|
||||
const reloadStores = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { data, error } = await useApi<any>(createUrl('/stores/reload'))
|
||||
|
||||
if (!isEmpty(error.value))
|
||||
console.error('Error loading store data:', error.value)
|
||||
|
||||
// Reload the store data
|
||||
const { data: storeData, error: storeError } = await useApi<any>(createUrl('/stores'))
|
||||
if (!isEmpty(storeError.value))
|
||||
console.error('Error loading store data:', storeError.value)
|
||||
else
|
||||
storesList.value = storeData.value
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 stores -->
|
||||
<VCard
|
||||
:title="$t('List of stores')"
|
||||
class="mb-6"
|
||||
>
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<!-- 👉 Select country -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedCountry"
|
||||
:placeholder="$t('Country')"
|
||||
:items="country"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select Brand -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedBrand"
|
||||
:placeholder="$t('Brand')"
|
||||
:items="brand"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select Multi POS -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedNbPos"
|
||||
:placeholder="$t('Multi POS')"
|
||||
:items="nbPos"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
|
||||
<VDivider class="my-4" />
|
||||
|
||||
<div class="d-flex flex-wrap gap-4 mx-5">
|
||||
<div class="d-flex align-center">
|
||||
<!-- 👉 Search -->
|
||||
<AppTextField
|
||||
v-model="searchQuery"
|
||||
:placeholder="$t('Search')"
|
||||
density="compact"
|
||||
style="inline-size: 200px;"
|
||||
class="me-3"
|
||||
/>
|
||||
</div>
|
||||
<VSpacer />
|
||||
<div class="d-flex gap-4 flex-wrap align-center">
|
||||
<VBtn
|
||||
color="primary"
|
||||
prepend-icon="tabler-reload"
|
||||
@click="reloadStores"
|
||||
>
|
||||
{{ t("Reload") }}
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VDivider class="mt-4" />
|
||||
|
||||
<VCol cols="12">
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<!-- 👉 Datatable -->
|
||||
<VDataTable
|
||||
v-else
|
||||
class="dt-row-striped"
|
||||
:headers="headers"
|
||||
:items="filteredData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
expand-on-click
|
||||
>
|
||||
<!-- Expanded Row Data -->
|
||||
<template #expanded-row="slotProps">
|
||||
<tr class="v-data-table__tr">
|
||||
<td :colspan="headers.length">
|
||||
<p class="my-1">
|
||||
City: {{ slotProps.item.logMessage }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!-- Store details hyperlink -->
|
||||
<template #item.businessDate="{ item }">
|
||||
<span> {{ formatDate(item.businessDate) }}</span>
|
||||
</template>
|
||||
</VDataTable>
|
||||
</VCol>
|
||||
</vcard>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -55,6 +55,16 @@
|
|||
"You can search for a reference, reference-color or reference-color-size.": "You can search for a reference, reference-color or reference-color-size.",
|
||||
"Minimum 5 characters long": "Minimum 5 characters long",
|
||||
"Filters": "Filters",
|
||||
"XADMIN": "XADMIN",
|
||||
"Application Log": "Application Log",
|
||||
"Level": "level",
|
||||
"loggerCategory": "loggerCategory",
|
||||
"Thread": "Thread",
|
||||
"Date": "Date",
|
||||
"WSK": "WSK",
|
||||
"Select date": "Select date",
|
||||
"ExcelData is empty, cannot export": "ExcelData is empty, cannot export",
|
||||
"Logs list": "Logs list",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "عناصر واجهة المستخدم",
|
||||
"Forms & Tables": "النماذج والجداول",
|
||||
|
|
|
|||
|
|
@ -55,6 +55,16 @@
|
|||
"You can search for a reference, reference-color or reference-color-size.": "You can search for a reference, reference-color or reference-color-size.",
|
||||
"Minimum 5 characters long": "Minimum 5 characters long",
|
||||
"Filters": "Filters",
|
||||
"XADMIN": "XADMIN",
|
||||
"Application Log": "Application Log",
|
||||
"Level": "level",
|
||||
"loggerCategory": "loggerCategory",
|
||||
"Thread": "Thread",
|
||||
"Date": "Date",
|
||||
"WSK": "WSK",
|
||||
"Select date": "Select date",
|
||||
"ExcelData is empty, cannot export": "No data, cannot export",
|
||||
"Logs list": "Logs list",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "UI Elements",
|
||||
"Forms & Tables": "Forms & Tables",
|
||||
|
|
|
|||
|
|
@ -55,6 +55,16 @@
|
|||
"You can search for a reference, reference-color or reference-color-size.": "Vous pouvez chercher une reference, reference-couleur ou reference-couleur-taille.",
|
||||
"Minimum 5 characters long": "Minimum 5 caractères",
|
||||
"Filters": "Filtres",
|
||||
"XADMIN": "XADMIN",
|
||||
"Application Log": "Application Log",
|
||||
"Level": "Niveau",
|
||||
"loggerCategory": "Categorie log",
|
||||
"Thread": "Thread",
|
||||
"Date": "Date",
|
||||
"WSK": "Caisse",
|
||||
"Select date": "Selectionner une date",
|
||||
"ExcelData is empty, cannot export": "Aucune donnée, impossible d'exporter",
|
||||
"Logs list": "Liste des logs",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "ÉLÉMENTS DE L'UI",
|
||||
"Forms & Tables": "Formulaires et tableaux",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,326 @@
|
|||
<script setup lang="ts">
|
||||
import { endOfDay, format } from 'date-fns'
|
||||
import exportFromJSON from 'export-from-json'
|
||||
import { French } from 'flatpickr/dist/l10n/fr'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: '', key: 'data-table-expand' },
|
||||
{ title: t('WSK'), key: 'wkstnId' },
|
||||
{ title: t('Level'), key: 'logLevel' },
|
||||
{ title: t('Thread'), key: 'threadName' },
|
||||
{ title: t('Category'), key: 'loggerCategory' },
|
||||
{ title: t('Date'), key: 'createDate' },
|
||||
{ title: t('User'), key: 'createUserId' },
|
||||
])
|
||||
|
||||
const selectedWkStn = ref(null)
|
||||
const selectedLogLevel = ref(null)
|
||||
const selectedCategory = ref(null)
|
||||
const selectedDate = ref(null)
|
||||
const searchQuery = ref('')
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
const isSnackbarVisibility = ref(false)
|
||||
|
||||
// Data table options
|
||||
// TODO SortBy ne marche pas
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: ['createDate'], sortDesc: [true] })
|
||||
const isLoading = ref(false)
|
||||
|
||||
const dtListData = ref([]) // Initialisez data comme un tableau vide
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
isSnackbarVisibility.value = false
|
||||
|
||||
let logDate
|
||||
if (selectedDate.value)
|
||||
logDate = format(new Date(selectedDate.value), 'yyyyMMdd')
|
||||
else
|
||||
logDate = format(endOfDay(new Date()), 'yyyyMMdd')
|
||||
|
||||
const response = await useApi<any>(createUrl(`/stores/${props.storeData.store.id_structure}/log?dbHost=${route.query.dbHost}&logDate=${logDate}`))
|
||||
|
||||
if (response.data.value)
|
||||
dtListData.value = response.data.value
|
||||
else
|
||||
dtListData.value = []
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
const wkstn = computed(() => {
|
||||
const allWkstns = dtListData.value.map((list: { wkstnId: any }) => list.wkstnId)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueWkstns = allWkstns.filter((wkstn: any, index: any, self: string | any[]) => self.indexOf(wkstn) === index)
|
||||
const sortedWkstns = uniqueWkstns.sort()
|
||||
|
||||
return sortedWkstns.map((list: any) => ({ title: list, value: list }))
|
||||
})
|
||||
|
||||
const level = computed(() => {
|
||||
const allLogLevels = dtListData.value.map((list: { logLevel: any }) => list.logLevel)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueLogLevels = allLogLevels.filter((level: any, index: any, self: string | any[]) => self.indexOf(level) === index)
|
||||
const sortedLogLevels = uniqueLogLevels.sort()
|
||||
|
||||
return sortedLogLevels.map((list: any) => ({ title: list, value: list }))
|
||||
})
|
||||
|
||||
const category = computed(() => {
|
||||
const allCategories = dtListData.value.map((list: { loggerCategory: any }) => list.loggerCategory)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueCategories = allCategories.filter((category: any, index: any, self: string | any[]) => self.indexOf(category) === index)
|
||||
const sortedCategories = uniqueCategories.sort()
|
||||
|
||||
return sortedCategories.map((list: any) => ({ title: list, value: list }))
|
||||
})
|
||||
|
||||
const filteredLogList = computed(() => {
|
||||
let filtered = dtListData.value
|
||||
|
||||
// If a workstation is selected, filter the records for this number
|
||||
if (selectedWkStn.value !== undefined && selectedWkStn.value !== null)
|
||||
filtered = filtered.filter((list: { wkstnId: any }) => list.wkstnId === selectedWkStn.value)
|
||||
|
||||
// If a loglevel is selected, filter the records for this Loglevel
|
||||
if (selectedLogLevel.value !== undefined && selectedLogLevel.value !== null)
|
||||
filtered = filtered.filter((list: { logLevel: any }) => list.logLevel === selectedLogLevel.value)
|
||||
|
||||
// If a loggerCategory is selected, filter the records for this loggerCategory
|
||||
if (selectedCategory.value !== undefined && selectedCategory.value !== null)
|
||||
filtered = filtered.filter((list: { loggerCategory: any }) => list.loggerCategory === selectedCategory.value)
|
||||
|
||||
// If a search query is provided, filter the records for this query
|
||||
if (searchQuery.value) {
|
||||
filtered = filtered.filter((log: { [s: string]: unknown } | ArrayLike<unknown>) =>
|
||||
Object.values(log).some(value =>
|
||||
String(value).toLowerCase().includes(searchQuery.value.toLowerCase()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const ExcelField = [
|
||||
'wkstnId',
|
||||
'logLevel',
|
||||
'threadName',
|
||||
'logMessage',
|
||||
'loggerCategory',
|
||||
'createDate',
|
||||
'createUserId',
|
||||
]
|
||||
|
||||
const ExcelData = computed(() => {
|
||||
return dtListData.value.map((item: { [x: string]: string }) => {
|
||||
const orderedItem: { [key: string]: string } = {}
|
||||
|
||||
ExcelField.forEach(field => {
|
||||
if (field === 'createDate') {
|
||||
const date = new Date(item[field])
|
||||
|
||||
orderedItem[field] = format(date, 'dd/MM/yyyy HH:mm:ss')
|
||||
}
|
||||
else {
|
||||
orderedItem[field] = item[field]
|
||||
}
|
||||
})
|
||||
|
||||
return orderedItem
|
||||
})
|
||||
})
|
||||
|
||||
const exportEXCEL = () => {
|
||||
const date = new Date()
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
|
||||
const fileName = `LOGS_${props.storeData.store.id_structure}-${year}${month}${day}`
|
||||
|
||||
if (ExcelData.value.length > 0) {
|
||||
exportFromJSON({
|
||||
data: ExcelData.value,
|
||||
fileName,
|
||||
exportType: exportFromJSON.types.xls,
|
||||
})
|
||||
}
|
||||
else {
|
||||
isSnackbarVisibility.value = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 logs -->
|
||||
<VCard
|
||||
:title="$t('Filters')"
|
||||
class="mb-6"
|
||||
>
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<!-- 👉 Select workstation -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedWkStn"
|
||||
:placeholder="$t('WorkStation')"
|
||||
:items="wkstn"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select log level -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedLogLevel"
|
||||
:placeholder="$t('Level')"
|
||||
:items="level"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select logger category -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedCategory"
|
||||
:placeholder="$t('loggerCategory')"
|
||||
:items="category"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow>
|
||||
<!-- 👉 Date log -->
|
||||
<VCol sm="4">
|
||||
<AppDateTimePicker
|
||||
v-model="selectedDate"
|
||||
label=""
|
||||
:locale="French"
|
||||
:placeholder="$t('Select date')"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<VCard
|
||||
:title="$t('Logs list')"
|
||||
class="mb-6"
|
||||
>
|
||||
<div class="d-flex flex-wrap gap-4 mx-5">
|
||||
<div class="d-flex align-center">
|
||||
<!-- 👉 Search -->
|
||||
<AppTextField
|
||||
v-model="searchQuery"
|
||||
:placeholder="$t('Search')"
|
||||
density="compact"
|
||||
style="inline-size: 200px;"
|
||||
class="me-3"
|
||||
/>
|
||||
</div>
|
||||
<VSpacer />
|
||||
<div class="d-flex gap-1 flex-wrap aalign-center">
|
||||
<!-- 👉 Export button -->
|
||||
<VBtn
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
prepend-icon="tabler-upload"
|
||||
@click="exportEXCEL"
|
||||
>
|
||||
Export
|
||||
</VBtn>
|
||||
</div>
|
||||
<!-- 👉 Reload -->
|
||||
<div class="d-flex gap-4 flex-wrap align-center">
|
||||
<VBtn
|
||||
color="primary"
|
||||
prepend-icon="tabler-reload"
|
||||
@click="fetchData"
|
||||
>
|
||||
{{ $t('Reload') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VDivider class="mt-4" />
|
||||
|
||||
<VCol cols="12">
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<!-- 👉 Datatable -->
|
||||
<VDataTable
|
||||
v-else
|
||||
class="dt-row-striped"
|
||||
:headers="headers"
|
||||
:items="filteredLogList"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
expand-on-click
|
||||
>
|
||||
<!-- format date log -->
|
||||
<template #item.createDate="{ item }">
|
||||
{{ format(new Date(item.createDate), 'dd/MM/yyyy HH:mm:ss') }}
|
||||
</template>
|
||||
|
||||
<!-- Expanded Row Data -->
|
||||
<template #expanded-row="slotProps">
|
||||
<tr class="v-data-table__tr">
|
||||
<td :colspan="headers.length">
|
||||
<p class="my-1">
|
||||
{{ slotProps.item.logMessage }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</VDataTable>
|
||||
</VCol>
|
||||
</VCard>
|
||||
</div>
|
||||
<!-- Snackbar -->
|
||||
<VSnackbar
|
||||
v-model="isSnackbarVisibility"
|
||||
location="center"
|
||||
>
|
||||
{{ $t('ExcelData is empty, cannot export') }}
|
||||
|
||||
<template #actions>
|
||||
<VBtn
|
||||
color="error"
|
||||
@click="isSnackbarVisibility = false"
|
||||
>
|
||||
Close
|
||||
</VBtn>
|
||||
</template>
|
||||
</VSnackbar>
|
||||
</template>
|
||||
|
|
@ -45,6 +45,7 @@ declare module 'vue-router/auto/routes' {
|
|||
'login': RouteRecordInfo<'login', '/login', Record<never, never>, Record<never, never>>,
|
||||
'store-details': RouteRecordInfo<'store-details', '/store/details', Record<never, never>, Record<never, never>>,
|
||||
'store-list': RouteRecordInfo<'store-list', '/store/list', Record<never, never>, Record<never, never>>,
|
||||
'xadmin-application-log': RouteRecordInfo<'xadmin-application-log', '/xadmin/application/log', Record<never, never>, Record<never, never>>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue