fix: translations - excel export

refactor/issue-1/first-setup
Frédérik Benoist 2023-12-23 09:19:00 +01:00
parent 368d51e061
commit d7df6793b7
10 changed files with 412 additions and 11 deletions

View File

@ -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"
}
}
}

View File

@ -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'}

View File

@ -1 +1,4 @@
// Write your overrides
.dt-row-striped tr:nth-of-type(even) {
background-color: #f6f2f28d;
}

View File

@ -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' },
},
]

View File

@ -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' },
},
]

View File

@ -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>

View File

@ -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": "صلاحية التحكم صلاحية الدخول",

View File

@ -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",

View File

@ -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",

1
typed-router.d.ts vendored
View File

@ -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>>,