fix: translations - excel export
parent
368d51e061
commit
d7df6793b7
|
|
@ -50,7 +50,8 @@
|
|||
"vue3-apexcharts": "^1.4.4",
|
||||
"vue3-perfect-scrollbar": "^1.6.1",
|
||||
"vuetify": "3.3.22",
|
||||
"webfontloader": "^1.6.28"
|
||||
"webfontloader": "^1.6.28",
|
||||
"export-from-json": "^1.7.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config-vue": "^0.43.1",
|
||||
|
|
@ -133,4 +134,4 @@
|
|||
"msw": {
|
||||
"workerDirectory": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ dependencies:
|
|||
cookie-es:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
export-from-json:
|
||||
specifier: ^1.7.3
|
||||
version: 1.7.3
|
||||
jwt-decode:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2
|
||||
|
|
@ -4109,6 +4112,10 @@ packages:
|
|||
strip-final-newline: 3.0.0
|
||||
dev: true
|
||||
|
||||
/export-from-json@1.7.3:
|
||||
resolution: {integrity: sha512-Xg0L0saYz+CBz2MnaZvSEAHr17hWtHAfFWXw/frllG9t6aijuQukiU40ElOeM9nDTrtQPhLJMLN0q8lo897FYg==}
|
||||
dev: false
|
||||
|
||||
/external-editor@3.1.0:
|
||||
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
|
|||
|
|
@ -1 +1,4 @@
|
|||
// Write your overrides
|
||||
.dt-row-striped tr:nth-of-type(even) {
|
||||
background-color: #f6f2f28d;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,25 @@ export default [
|
|||
{
|
||||
title: 'Store',
|
||||
to: { name: 'store-list' },
|
||||
icon: { icon: 'tabler-file' },
|
||||
icon: { icon: 'tabler-building-store' },
|
||||
},
|
||||
{
|
||||
title: 'Obi',
|
||||
icon: { icon: 'tabler-file' },
|
||||
title: 'Flow',
|
||||
icon: { icon: 'tabler-topology-bus' },
|
||||
children: [
|
||||
{
|
||||
title: 'BL not sent',
|
||||
to: { name: 'flux-bl-not-sent' },
|
||||
icon: { icon: 'tabler-unlink' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'OBI',
|
||||
icon: { icon: 'tabler-shopping-bag-check' },
|
||||
},
|
||||
{
|
||||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-file' },
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,14 +7,25 @@ export default [
|
|||
{
|
||||
title: 'Store',
|
||||
to: { name: 'store-list' },
|
||||
icon: { icon: 'tabler-file' },
|
||||
icon: { icon: 'tabler-building-store' },
|
||||
},
|
||||
{
|
||||
title: 'Obi',
|
||||
icon: { icon: 'tabler-file' },
|
||||
title: 'Flow',
|
||||
icon: { icon: 'tabler-topology-bus' },
|
||||
children: [
|
||||
{
|
||||
title: 'BL not sent',
|
||||
to: { name: 'flux-bl-not-sent' },
|
||||
icon: { icon: 'tabler-unlink' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'OBI',
|
||||
icon: { icon: 'tabler-shopping-bag-check' },
|
||||
},
|
||||
{
|
||||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-file' },
|
||||
icon: { icon: 'tabler-database-star' },
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,301 @@
|
|||
<script setup lang="ts">
|
||||
import exportFromJSON from 'export-from-json'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: t('Distributor'), key: 'libelleDis' },
|
||||
{ title: t('Name'), key: 'nomStructure' },
|
||||
{ title: t('Chain'), key: 'enseigne' },
|
||||
{ title: t('Brand'), key: 'marque' },
|
||||
{ title: t('Season'), key: 'codeSaison' },
|
||||
{ title: t('R-C-S'), key: 'refRct' },
|
||||
{ title: t('Item'), key: 'nomProduit' },
|
||||
{ title: t('Item ID'), key: 'idProduit' },
|
||||
{ title: t('External Code'), key: 'codeExterne' },
|
||||
{ title: t('BL ID'), key: 'idBonLivraison' },
|
||||
{ title: t('BL Date'), key: 'dateBl' },
|
||||
{ title: t('Expeditor'), key: 'expediteur' },
|
||||
{ title: t('Notes'), key: 'remarques' },
|
||||
])
|
||||
|
||||
const selectedDistributor = ref()
|
||||
const selectedStore = ref()
|
||||
const selectedRefr = ref()
|
||||
|
||||
const searchQuery = ref<any>('')
|
||||
|
||||
// Data table options
|
||||
const { data: dtListData } = await useApi<any>(createUrl('/flux/bl/notsent'))
|
||||
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
|
||||
const distributor = computed(() => {
|
||||
const allItems = dtListData.value.map(({ libelleDis }: { libelleDis: any }) => libelleDis)
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const uniqueItems = allItems.filter((distributor: any, index: any, self: string | any[]) => self.indexOf(distributor) === index)
|
||||
const sortedItems = uniqueItems.sort()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedItems.map((distributor: any) => ({ title: distributor, value: distributor }))
|
||||
})
|
||||
|
||||
const store = computed(() => {
|
||||
const allItems = dtListData.value.map(({ nomStructure, idStructure }: { nomStructure: any; idStructure: any }) => ({ nomStructure, idStructure }))
|
||||
|
||||
const uniqueItems = allItems.filter((item: any, index: any, self: any[]) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
index === self.findIndex(t => (
|
||||
t.nomStructure === item.nomStructure && t.idStructure === item.idStructure
|
||||
)),
|
||||
)
|
||||
|
||||
const sortedItems = uniqueItems.sort((a: { idStructure: number }, b: { idStructure: number }) => a.idStructure - b.idStructure)
|
||||
|
||||
return sortedItems.map(({ nomStructure }: { nomStructure: any }) => ({ title: nomStructure, value: nomStructure }))
|
||||
})
|
||||
|
||||
const filterRefr = computed(() => {
|
||||
const allItems = dtListData.value.map(({ refR }: { refR: any }) => refR)
|
||||
|
||||
const uniqueItems = allItems.filter((refR: any, index: any, self: string | any[]) => self.indexOf(refR) === index)
|
||||
const sortedItems = uniqueItems.sort()
|
||||
|
||||
return sortedItems.map((refR: any) => ({ title: refR, value: refR }))
|
||||
})
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let filtered = dtListData.value
|
||||
|
||||
// If a distributor is selected, filter the records for this distributor
|
||||
if (selectedDistributor.value)
|
||||
filtered = filtered.filter(({ libelleDis }: { libelleDis: any }) => libelleDis === selectedDistributor.value)
|
||||
|
||||
// If a store is selected, filter the records for this store
|
||||
if (selectedStore.value)
|
||||
filtered = filtered.filter(({ nomStructure }: { nomStructure: any }) => nomStructure === selectedStore.value)
|
||||
|
||||
// If a ref R is selected, filter the records for this ref R
|
||||
if (selectedRefr.value)
|
||||
filtered = filtered.filter(({ refR }: { refR: any }) => refR === selectedRefr.value)
|
||||
|
||||
// If a search query is provided, filter the records for this query
|
||||
if (searchQuery.value) {
|
||||
filtered = filtered.filter((dataFiltered: { [s: string]: unknown } | ArrayLike<unknown>) =>
|
||||
Object.values(dataFiltered).some(value =>
|
||||
String(value).toLowerCase().includes(searchQuery.value.toLowerCase()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const widgetData = computed(() => [
|
||||
{ title: t('Distributors'), value: distributor.value.length, icon: 'tabler-brand-campaignmonitor' },
|
||||
{ title: t('Stores'), value: store.value.length, icon: 'tabler-building-store' },
|
||||
{ title: t('Items'), value: filterRefr.value.length, icon: 'tabler-shirt-sport' },
|
||||
{ title: t('Errors'), value: dtListData.value.length, icon: 'tabler-exclamation-circle' },
|
||||
])
|
||||
|
||||
const ExcelField = [
|
||||
'idDistrib',
|
||||
'libelleDis',
|
||||
'idStructure',
|
||||
'nomStructure',
|
||||
'enseigne',
|
||||
'marque',
|
||||
'codeSaison',
|
||||
'refR',
|
||||
'refRc',
|
||||
'refRct',
|
||||
'nomProduit',
|
||||
'idProduit',
|
||||
'codeExterne',
|
||||
'idBonLivraison',
|
||||
'dateBl',
|
||||
'idExpediteur',
|
||||
'expediteur',
|
||||
'remarques',
|
||||
]
|
||||
|
||||
const ExcelData = dtListData.value.map((item: { [x: string]: string }) => {
|
||||
const orderedItem: { [key: string]: string } = {}
|
||||
|
||||
ExcelField.forEach(field => {
|
||||
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 = `BLBLOQUES_${year}${month}${day}`
|
||||
|
||||
exportFromJSON({
|
||||
data: ExcelData,
|
||||
fileName,
|
||||
exportType: exportFromJSON.types.xls,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 Invoice Widgets -->
|
||||
<VCard class="mb-6">
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<template
|
||||
v-for="(data, id) in widgetData"
|
||||
:key="id"
|
||||
>
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
md="3"
|
||||
class="px-6"
|
||||
>
|
||||
<div class="d-flex justify-space-between">
|
||||
<div class="d-flex flex-column gap-y-1">
|
||||
<h4
|
||||
class="text-h4 text-high-emphasis"
|
||||
:class="{ 'text-error': id === 3 }"
|
||||
>
|
||||
{{ data.value }}
|
||||
</h4>
|
||||
<div class="text-body-1 text-capitalize">
|
||||
{{ data.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VAvatar
|
||||
color="rgba(var(--v-theme-on-background), var(--v-hover-opacity))"
|
||||
rounded
|
||||
class="text-high-emphasis"
|
||||
size="38"
|
||||
>
|
||||
<VIcon
|
||||
:icon="data.icon"
|
||||
size="26"
|
||||
/>
|
||||
</VAvatar>
|
||||
</div>
|
||||
</VCol>
|
||||
<VDivider
|
||||
v-if="$vuetify.display.mdAndUp ? id !== widgetData.length - 1
|
||||
: $vuetify.display.smAndUp ? id % 2 === 0
|
||||
: false"
|
||||
vertical
|
||||
inset
|
||||
/>
|
||||
</template>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<VCard
|
||||
:title="$t('Filters')"
|
||||
class="mb-6"
|
||||
>
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<!-- 👉 Select distributor -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedDistributor"
|
||||
:placeholder="$t('Distributor')"
|
||||
:items="distributor"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select store -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedStore"
|
||||
:placeholder="$t('Store')"
|
||||
:items="store"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select Reference R -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedRefr"
|
||||
:placeholder="$t('Item')"
|
||||
:items="filterRefr"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<!-- 👉 BL not sent -->
|
||||
<VCard
|
||||
:title="$t('BL not sent 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-4 flex-wrap align-center">
|
||||
<!-- 👉 Export button -->
|
||||
<VBtn
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
prepend-icon="tabler-upload"
|
||||
@click="exportEXCEL"
|
||||
>
|
||||
Export
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VDivider class="mt-4" />
|
||||
|
||||
<VCol cols="12">
|
||||
<!-- 👉 Datatable -->
|
||||
<VDataTable
|
||||
class="dt-row-striped"
|
||||
:headers="headers"
|
||||
:items="filteredData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
/>
|
||||
</VCol>
|
||||
</Vcard>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,9 +1,28 @@
|
|||
{
|
||||
"Home": "الصفحة الرئيسية",
|
||||
"Store": "متجر",
|
||||
"Stores": "المتاجر",
|
||||
"Flow": "التدفق",
|
||||
"OBI": "OBI",
|
||||
"Dotsoft": "Dotsoft",
|
||||
"List of stores": "قائمة المتاجر",
|
||||
"BL not sent list": "قائمة البيانات الخارجية غير المرسلة",
|
||||
"BL not sent": "بيانات البيانات الخارجية غير المرسلة",
|
||||
"ST ID": "ST ID",
|
||||
"Exp ID": "Exp ID",
|
||||
"BL ID": "BL ID",
|
||||
"BL Date": "تاريخ BL",
|
||||
"External Code": "رمز خارجي",
|
||||
"Notes": "ملاحظات",
|
||||
"Expeditor": "المندوب",
|
||||
"Distributor": "البائع",
|
||||
"Distributors": "البائعين",
|
||||
"Season": "الموسم",
|
||||
"Country": "الدولة",
|
||||
"Brand": "العلامة التجارية",
|
||||
"R-C-S": "R-C-S",
|
||||
"Item ID": "معرف العنصر",
|
||||
"Chain": "المجموعة",
|
||||
"Multi POS": "Multi POS",
|
||||
"Search": "بحث",
|
||||
"Name": "الاسم",
|
||||
|
|
@ -11,6 +30,7 @@
|
|||
"Mode": "الوضع",
|
||||
"Value": "القيمة",
|
||||
"Item": "العنصر",
|
||||
"Items": "العناصر",
|
||||
"Remote": "متصل",
|
||||
"Option": "خيار",
|
||||
"Stock": "المخزون",
|
||||
|
|
@ -34,6 +54,7 @@
|
|||
"Submit": "Submit",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "عناصر واجهة المستخدم",
|
||||
"Forms & Tables": "النماذج والجداول",
|
||||
|
|
@ -116,6 +137,7 @@
|
|||
"Not Authorized": "غير مخول",
|
||||
"Under Maintenance": "تحت الصيانة",
|
||||
"Error": "خطأ",
|
||||
"Errors": "خطوات",
|
||||
"Statistics": "إحصائيات",
|
||||
"Analytics": "تحليلات",
|
||||
"Access Control": "صلاحية التحكم صلاحية الدخول",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,28 @@
|
|||
{
|
||||
"Home": "Home",
|
||||
"Store": "Store",
|
||||
"Stores": "Stores",
|
||||
"Flow": "Flow",
|
||||
"OBI": "OBI",
|
||||
"Dotsoft": "Dotsoft",
|
||||
"List of stores": "List of stores",
|
||||
"BL not sent list": "BL not sent list",
|
||||
"BL not sent": "BL not sent",
|
||||
"ST ID": "ST ID",
|
||||
"Exp ID": "Exp ID",
|
||||
"BL ID": "BL ID",
|
||||
"BL Date": "BL Date",
|
||||
"External Code": "External Code",
|
||||
"Notes": "Notes",
|
||||
"Expeditor": "Expeditor",
|
||||
"Distributor": "Distributor",
|
||||
"Distributors": "Distributors",
|
||||
"Season": "Season",
|
||||
"Country": "Country",
|
||||
"Brand": "Brand",
|
||||
"R-C-S": "R-C-S",
|
||||
"Item ID": "Item ID",
|
||||
"Chain": "Chain",
|
||||
"Multi POS": "Multi POS",
|
||||
"Search": "Search",
|
||||
"Name": "Name",
|
||||
|
|
@ -11,6 +30,7 @@
|
|||
"Mode": "Mode",
|
||||
"Value": "Value",
|
||||
"Item": "Item",
|
||||
"Items": "Items",
|
||||
"Remote": "Remote",
|
||||
"Option": "Option",
|
||||
"Stock": "Stock",
|
||||
|
|
@ -34,6 +54,7 @@
|
|||
"Submit": "Submit",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "UI Elements",
|
||||
"Forms & Tables": "Forms & Tables",
|
||||
|
|
@ -116,6 +137,7 @@
|
|||
"Not Authorized": "Not Authorized",
|
||||
"Under Maintenance": "Under Maintenance",
|
||||
"Error": "Error",
|
||||
"Errors": "Errors",
|
||||
"Statistics": "Statistics",
|
||||
"Actions": "Actions",
|
||||
"Access Control": "Access Control",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,28 @@
|
|||
{
|
||||
"Home": "Accueil",
|
||||
"Store": "Boutique",
|
||||
"Stores": "Boutiques",
|
||||
"Flow": "Flux",
|
||||
"OBI": "OBI",
|
||||
"Dotsoft": "Dotsoft",
|
||||
"List of stores": "Liste des boutiques",
|
||||
"BL not sent list": "Liste des BL non envoyés",
|
||||
"BL not sent": "BL non envoyé",
|
||||
"ST ID": "ID ST",
|
||||
"Exp ID": "ID Exp",
|
||||
"BL ID": "ID BL",
|
||||
"BL Date": "Date BL",
|
||||
"External Code": "Code externe",
|
||||
"Notes": "Notes",
|
||||
"Expeditor": "Expéditeur",
|
||||
"Distributor": "Distributeur",
|
||||
"Distributors": "Distributeurs",
|
||||
"Season": "Saison",
|
||||
"Country": "Pays",
|
||||
"Brand": "Enseigne",
|
||||
"Brand": "Marque",
|
||||
"R-C-S": "R-C-T",
|
||||
"Item ID": "ID produit",
|
||||
"Chain": "Enseigne",
|
||||
"Multi POS": "Multi POS",
|
||||
"Search": "Chercher",
|
||||
"Name": "Nom",
|
||||
|
|
@ -11,6 +30,7 @@
|
|||
"Mode": "Mode",
|
||||
"Value": "Valeur",
|
||||
"Item": "Article",
|
||||
"Items": "Articles",
|
||||
"Remote": "Accès distant",
|
||||
"Option": "Option",
|
||||
"Stock": "Stock",
|
||||
|
|
@ -34,6 +54,7 @@
|
|||
"Submit": "Valider",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "ÉLÉMENTS DE L'UI",
|
||||
"Forms & Tables": "Formulaires et tableaux",
|
||||
|
|
@ -117,6 +138,7 @@
|
|||
"Not Authorized": "Pas autorisé",
|
||||
"Under Maintenance": "En maintenance",
|
||||
"Error": "Erreur",
|
||||
"Errors": "Erreurs",
|
||||
"Statistics": "Statistiques",
|
||||
"Card Actions": "Actions de la carte",
|
||||
"Actions": "Actions",
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare module 'vue-router/auto/routes' {
|
|||
export interface RouteNamedMap {
|
||||
'root': RouteRecordInfo<'root', '/', Record<never, never>, Record<never, never>>,
|
||||
'$error': RouteRecordInfo<'$error', '/:error(.*)', { error: ParamValue<true> }, { error: ParamValue<false> }>,
|
||||
'flux-bl-not-sent': RouteRecordInfo<'flux-bl-not-sent', '/flux/bl/not_sent', Record<never, never>, Record<never, never>>,
|
||||
'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>>,
|
||||
|
|
|
|||
Loading…
Reference in New Issue