feat: store details translation
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
|
@ -0,0 +1,51 @@
|
|||
interface Store {
|
||||
id_structure: number
|
||||
nom: string
|
||||
ip_master: string
|
||||
telephone: string
|
||||
photoLink: string
|
||||
enseigne: string
|
||||
nb_caisses: number
|
||||
adresse: string
|
||||
caisses: Caisse[]
|
||||
}
|
||||
|
||||
interface Caisse {
|
||||
id_caisse: number
|
||||
ip: string
|
||||
}
|
||||
|
||||
interface Replication {
|
||||
pendingReplications: number
|
||||
minPendingReplicationDate: string
|
||||
maxPendingReplicationDate: string
|
||||
}
|
||||
|
||||
interface Transaction {
|
||||
backOfficeTransactions: number
|
||||
minBackOfficeTransactionDate: string
|
||||
maxBackOfficeTransactionDate: string
|
||||
backOfficeBusinessDate: string
|
||||
}
|
||||
|
||||
interface XstoreTransaction {
|
||||
count: number
|
||||
minDate: string
|
||||
minDateT: string
|
||||
minDateH: string
|
||||
maxDate: string
|
||||
maxDateT: string
|
||||
maxDateH: string
|
||||
}
|
||||
|
||||
export interface StoreData {
|
||||
store: Store
|
||||
replication: Replication
|
||||
transaction: Transaction
|
||||
openingTransaction: XstoreTransaction
|
||||
closingTransaction: XstoreTransaction
|
||||
saleTransaction: XstoreTransaction
|
||||
xstoreVersion: string
|
||||
xstoreVersionDate: string
|
||||
xstoreVersionCustomer: string
|
||||
}
|
||||
|
|
@ -9,4 +9,12 @@ export default [
|
|||
to: { name: 'store-list' },
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
{
|
||||
title: 'Obi',
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
{
|
||||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,4 +9,12 @@ export default [
|
|||
to: { name: 'store-list' },
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
{
|
||||
title: 'Obi',
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
{
|
||||
title: 'Dotsoft',
|
||||
icon: { icon: 'tabler-file' },
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,24 +2,11 @@
|
|||
<div>
|
||||
<VCard
|
||||
class="mb-6"
|
||||
title="Kick start your project 🚀"
|
||||
title="XSTORE HELPDESK DASHBOARD 🚀"
|
||||
>
|
||||
<VCardText>All the best for your new project.</VCardText>
|
||||
<VCardText>
|
||||
Please make sure to read our <a
|
||||
href="https://demos.pixinvent.com/vuexy-vuejs-admin-template/documentation/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-decoration-none"
|
||||
>
|
||||
Template Documentation
|
||||
</a> to understand where to go from here and how to use our template.
|
||||
</VCardText>
|
||||
</VCard>
|
||||
<VCardText>A cet endroit bientôt des statistiques</VCardText>
|
||||
|
||||
<VCard title="Want to integrate JWT? 🔒">
|
||||
<VCardText>We carefully crafted JWT flow so you can implement JWT with ease and with minimum efforts.</VCardText>
|
||||
<VCardText>Please read our JWT Documentation to get more out of JWT authentication.</VCardText>
|
||||
<VCardText>👉 Cliquez maintenant sur Boutique :)</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ 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 StoreTabRemote from '@/views/pages/store/view/StoreTabRemote.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
|
||||
|
|
@ -12,9 +15,10 @@ console.log(route.query.dbHost)
|
|||
|
||||
// tabs
|
||||
const tabs = [
|
||||
{ title: 'General', icon: 'tabler-users', tab: 'general' },
|
||||
{ title: 'Item', icon: 'tabler-lock', tab: 'item' },
|
||||
{ title: 'Admin', icon: 'tabler-file-text', tab: 'admin' },
|
||||
{ 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' },
|
||||
]
|
||||
|
||||
const { data: storeData } = await useApi<any>(`/stores/${route.query.storeId}/details?dbHost=${route.query.dbHost}`)
|
||||
|
|
@ -49,19 +53,24 @@ const { data: storeData } = await useApi<any>(`/stores/${route.query.storeId}/de
|
|||
class="mt-6 disable-tab-transition"
|
||||
:touch="false"
|
||||
>
|
||||
<!-- General -->
|
||||
<!-- 👉 General -->
|
||||
<VWindowItem>
|
||||
<StoreTabGeneral :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
|
||||
<!-- item -->
|
||||
<!-- 👉 Item -->
|
||||
<VWindowItem>
|
||||
<StoreTabItem />
|
||||
</VWindowItem>
|
||||
|
||||
<!-- admin -->
|
||||
<!-- 👉 Remote Access -->
|
||||
<VWindowItem>
|
||||
<StoreTabAdmin />
|
||||
<StoreTabRemote :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
|
||||
<!-- 👉 Admin -->
|
||||
<VWindowItem>
|
||||
<StoreTabAdmin :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
</VWindow>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const headers = computed(() => [
|
|||
{ title: t('Phone'), key: 'telephone', sortable: false },
|
||||
{ title: t('Brand'), key: 'enseigne' },
|
||||
{ title: t('Country'), key: 'pays' },
|
||||
{ title: '', key: 'actions', sortable: false },
|
||||
])
|
||||
|
||||
const selectedCountry = ref()
|
||||
|
|
@ -75,6 +76,23 @@ const filteredStoresList = computed(() => {
|
|||
|
||||
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
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -166,18 +184,81 @@ const filteredStoresList = computed(() => {
|
|||
:page="options.page"
|
||||
:options="options"
|
||||
>
|
||||
<!-- Store details hyperlink -->
|
||||
<template #item.nom="{ item }">
|
||||
<RouterLink :to="`/store/details?dbHost=${item.ip_master}&storeId=${item.id_structure}`">
|
||||
{{ item.nom }}
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<!-- Pos count -->
|
||||
<template #item.nbcaisses="{ item }">
|
||||
<VIcon v-if="item.nbcaisses > 1 && item.nbcaisses <= 9">
|
||||
{{ `tabler-square-rounded-number-${item.nbcaisses}` }}
|
||||
</VIcon>
|
||||
<span v-else-if="item.nbcaisses > 9">{{ item.nbcaisses }}</span>
|
||||
</template>
|
||||
|
||||
<!-- Actions -->
|
||||
<template #item.actions="{ item }">
|
||||
<IconBtn>
|
||||
<VIcon icon="tabler-dots-vertical" />
|
||||
<VMenu activator="parent">
|
||||
<VList>
|
||||
<VListItem
|
||||
value="connect"
|
||||
prepend-icon="tabler-numbers"
|
||||
@click="openPosList(item)"
|
||||
>
|
||||
POS
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
</IconBtn>
|
||||
</template>
|
||||
</VDataTable>
|
||||
|
||||
<VDialog
|
||||
v-model="isDialogVisible"
|
||||
max-width="600"
|
||||
>
|
||||
<!-- Dialog close btn -->
|
||||
<DialogCloseBtn @click="isDialogVisible = !isDialogVisible" />
|
||||
|
||||
<!-- Dialog Content -->
|
||||
<VCard title="Connect to invidual POS">
|
||||
<VCardText>
|
||||
<div v-if="selectedStore && (selectedStore as Store).caisses">
|
||||
<div
|
||||
v-for="(caisse, index) in (selectedStore as Store).caisses"
|
||||
:key="index"
|
||||
class="d-flex align-items-center mb-5"
|
||||
>
|
||||
<VTextField
|
||||
v-model="caisse.ip"
|
||||
label="IP"
|
||||
class="me-3"
|
||||
/>
|
||||
<VBtn
|
||||
:to="`/store/details?dbHost=${caisse.ip}&storeId=${(selectedStore as Store).id_structure}&workstationId=${caisse.id_caisse}`"
|
||||
color="primary"
|
||||
>
|
||||
Pos {{ caisse.id_caisse }}
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
<VCardText class="d-flex justify-end flex-wrap gap-3">
|
||||
<VBtn
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
@click="isDialogVisible = false"
|
||||
>
|
||||
Close
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</VCol>
|
||||
</vcard>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,31 @@
|
|||
"Search": "بحث",
|
||||
"Name": "الاسم",
|
||||
"Phone": "هاتف",
|
||||
"Mode": "الوضع",
|
||||
"Value": "القيمة",
|
||||
"Item": "العنصر",
|
||||
"Remote": "متصل",
|
||||
"Option": "خيار",
|
||||
"Stock": "المخزون",
|
||||
"Price": "السعر",
|
||||
"ITEM_ID": "ID العنصر",
|
||||
"PRICE": "السعر",
|
||||
"TYPE": "TYPE",
|
||||
"PARENT": "PARENT",
|
||||
"LEVEL": "LEVEL",
|
||||
"EFFECTIVE DATE": "EFFECTIVE DATE",
|
||||
"EXPIRATION DATE": "EXPIRATION DATE",
|
||||
"DATE_CREATE": "CREATE DATE",
|
||||
"USER_CREATE": "CREATE USER",
|
||||
"DATE_UPDATE": "UPDATE DATE",
|
||||
"USER_UPDATE": "UPDATE USER",
|
||||
"Reload": "تحديث",
|
||||
"WorkStation": "القطعة العملية",
|
||||
"SignatureString": "Signature string",
|
||||
"SignatureSource": "Signature source",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "عناصر واجهة المستخدم",
|
||||
"Forms & Tables": "النماذج والجداول",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,31 @@
|
|||
"Search": "Search",
|
||||
"Name": "Name",
|
||||
"Phone": "Phone",
|
||||
"Mode": "Mode",
|
||||
"Value": "Value",
|
||||
"Item": "Item",
|
||||
"Remote": "Remote",
|
||||
"Option": "Option",
|
||||
"Stock": "Stock",
|
||||
"Price": "Price",
|
||||
"ITEM_ID": "ITEM ID",
|
||||
"PRICE": "PRICE",
|
||||
"TYPE": "TYPE",
|
||||
"PARENT": "PARENT",
|
||||
"LEVEL": "LEVEL",
|
||||
"EFFECTIVE DATE": "EFFECTIVE DATE",
|
||||
"EXPIRATION DATE": "EXPIRATION DATE",
|
||||
"DATE_CREATE": "CREATE DATE",
|
||||
"USER_CREATE": "CREATE USER",
|
||||
"DATE_UPDATE": "UPDATE DATE",
|
||||
"USER_UPDATE": "UPDATE USER",
|
||||
"Reload": "Reload",
|
||||
"WorkStation": "Workstation",
|
||||
"SignatureString": "Signature string",
|
||||
"SignatureSource": "Signature source",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "UI Elements",
|
||||
"Forms & Tables": "Forms & Tables",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"Home": "Acceuil",
|
||||
"Home": "Accueil",
|
||||
"Store": "Boutique",
|
||||
"List of stores": "Liste des boutiques",
|
||||
"Country": "Pays",
|
||||
|
|
@ -8,6 +8,31 @@
|
|||
"Search": "Chercher",
|
||||
"Name": "Nom",
|
||||
"Phone": "Téléphone",
|
||||
"Mode": "Mode",
|
||||
"Value": "Valeur",
|
||||
"Item": "Article",
|
||||
"Remote": "Accès distant",
|
||||
"Option": "Option",
|
||||
"Stock": "Stock",
|
||||
"Price": "Prix",
|
||||
"ITEM_ID": "ITEM ID",
|
||||
"PRICE": "PRIX",
|
||||
"TYPE": "TYPE",
|
||||
"PARENT": "PARENT",
|
||||
"LEVEL": "NIVEAU",
|
||||
"EFFECTIVE DATE": "DATE EFFECTIVE",
|
||||
"EXPIRATION DATE": "DATE EXPIRATION",
|
||||
"DATE_CREATE": "DATE CREATION",
|
||||
"USER_CREATE": "UTIL. CREATION",
|
||||
"DATE_UPDATE": "DATE MAJ",
|
||||
"USER_UPDATE": "UTIL. MAJ",
|
||||
"Reload": "Rafraichir",
|
||||
"WorkStation": "Caisse",
|
||||
"SignatureString": "Chaine de Signature",
|
||||
"SignatureSource": "Signature source",
|
||||
"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",
|
||||
"---------------------------": "---------------------------",
|
||||
"UI Elements": "ÉLÉMENTS DE L'UI",
|
||||
"Forms & Tables": "Formulaires et tableaux",
|
||||
|
|
|
|||
|
|
@ -1,22 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
import UserProfileHeaderBg from '@images/pages/user-profile-header-bg.png'
|
||||
|
||||
interface Store {
|
||||
id_structure: number
|
||||
nom: string
|
||||
ip: string
|
||||
telephone: string
|
||||
photoLink: string
|
||||
enseigne: string
|
||||
adresse: string
|
||||
}
|
||||
|
||||
interface StoreHeaderData {
|
||||
store: Store
|
||||
}
|
||||
|
||||
interface Props {
|
||||
storeData: StoreHeaderData
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
@ -42,7 +29,7 @@ const props = defineProps<Props>()
|
|||
|
||||
<div class="user-profile-info w-100 mt-16 pt-6 pt-sm-0 mt-sm-0">
|
||||
<h5 class="text-h5 text-center text-sm-start font-weight-medium mb-3">
|
||||
{{ props?.storeData.store.id_structure }} - {{ props?.storeData.store.nom }}
|
||||
{{ props.storeData.store.id_structure }} - {{ props.storeData.store.nom }}
|
||||
</h5>
|
||||
|
||||
<div class="d-flex align-center justify-center justify-sm-space-between flex-wrap gap-4">
|
||||
|
|
@ -54,7 +41,7 @@ const props = defineProps<Props>()
|
|||
class="me-1"
|
||||
/>
|
||||
<span class="text-body-1">
|
||||
{{ props?.storeData.store.enseigne }}
|
||||
{{ props.storeData.store.enseigne }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
|
|
@ -65,7 +52,7 @@ const props = defineProps<Props>()
|
|||
class="me-1"
|
||||
/>
|
||||
<span class="text-body-1">
|
||||
{{ props?.storeData.store.telephone }}
|
||||
{{ props.storeData.store.telephone }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
|
|
@ -76,17 +63,27 @@ const props = defineProps<Props>()
|
|||
class="me-1"
|
||||
/>
|
||||
<span class="text-body-1">
|
||||
{{ props?.storeData.store.adresse }}
|
||||
{{ props.storeData.store.adresse }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<VBtn
|
||||
prepend-icon="tabler-check"
|
||||
color="success"
|
||||
<div class="d-flex align-center gap-4">
|
||||
<VAvatar
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
size="42"
|
||||
>
|
||||
Connected
|
||||
</VBtn>
|
||||
<VIcon icon="tabler-git-merge" />
|
||||
</VAvatar>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-h5 font-weight-medium">{{ props.storeData.xstoreVersion }} ({{ props.storeData.xstoreVersionCustomer }})</span>
|
||||
<span class="text-sm">
|
||||
{{ props.storeData.xstoreVersionDate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
<script lang="ts" setup>
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
import StoreTabAdminH from '@/views/pages/store/view/StoreTabAdminH.vue'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const props = defineProps<Props>()
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCard title="STORE TAB ADMIN">
|
||||
<VCardText>We carefully crafted JWT flow so you can implement JWT with ease and with minimum efforts.</VCardText>
|
||||
<VCardText>Please read our JWT Documentation to get more out of JWT authentication.</VCardText>
|
||||
</VCard>
|
||||
<VRow>
|
||||
<VCol cols="12">
|
||||
<StoreTabAdminH :store-data="storeData" />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
import StoreTabAdminHsequence from '@/views/pages/store/view/StoreTabAdminHsequence.vue'
|
||||
import StoreTabAdminHsignature from '@/views/pages/store/view/StoreTabAdminHsignature.vue'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const props = defineProps<Props>()
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
const currentTab = ref('tab-1')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VTabs
|
||||
v-model="currentTab"
|
||||
grow
|
||||
stacked
|
||||
>
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-123"
|
||||
/>
|
||||
Sequence
|
||||
</VTab>
|
||||
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-certificate"
|
||||
/>
|
||||
Signature
|
||||
</VTab>
|
||||
</VTabs>
|
||||
|
||||
<VCardText style="padding: 5px !important;">
|
||||
<VWindow
|
||||
v-model="currentTab"
|
||||
class="ms-3"
|
||||
>
|
||||
<VWindowItem value="tab-1">
|
||||
<StoreTabAdminHsequence :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
<VWindowItem value="tab-2">
|
||||
<StoreTabAdminHsignature :store-data="storeData" />
|
||||
</VWindowItem>
|
||||
</VWindow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
<script setup lang="ts">
|
||||
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: 'WSK', key: 'wkstnId' },
|
||||
{ title: t('Name'), key: 'sequenceId' },
|
||||
{ title: t('Mode'), key: 'sequenceMode' },
|
||||
{ title: t('Value'), key: 'sequenceNbr' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
|
||||
const selectedWkStn = ref()
|
||||
const selectedSequenceMode = ref()
|
||||
const searchQuery = ref('')
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
const isLoading = ref(false)
|
||||
|
||||
const data = ref([]) // Initialisez data comme un tableau vide
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const response = await useApi<any>(createUrl(`/stores/${props.storeData.store.id_structure}/sequence?dbHost=${route.query.dbHost}`))
|
||||
|
||||
data.value = response.data.value
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
const wkstn = computed(() => {
|
||||
const allWkstns = data.value.map((store: { wkstnId: any }) => store.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()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedWkstns.map((wkstn: any) => ({ title: wkstn, value: wkstn }))
|
||||
})
|
||||
|
||||
const seqmode = computed(() => {
|
||||
const allSeqModes = data.value.map((store: { sequenceMode: any }) => store.sequenceMode)
|
||||
|
||||
const uniqueSeqModes = allSeqModes.filter((seqmod: any, index: any, self: string | any[]) => self.indexOf(seqmod) === index)
|
||||
const sortedSeqModes = uniqueSeqModes.sort()
|
||||
|
||||
return sortedSeqModes.map((seqmod: any) => ({ title: seqmod, value: seqmod }))
|
||||
})
|
||||
|
||||
const filteredSequenceList = computed(() => {
|
||||
let filtered = data.value
|
||||
|
||||
// If a workstation is selected, filter the records for this number
|
||||
if (selectedWkStn.value !== undefined && selectedWkStn.value !== null)
|
||||
filtered = filtered.filter((store: { wkstnId: any }) => store.wkstnId === selectedWkStn.value)
|
||||
|
||||
// If a sequence mode is selected, filter the records for this mode
|
||||
if (selectedSequenceMode.value !== undefined && selectedSequenceMode.value !== null)
|
||||
filtered = filtered.filter((store: { sequenceMode: any }) => store.sequenceMode === selectedSequenceMode.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
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 stores -->
|
||||
<VCard class="mb-6">
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<!-- 👉 Select country -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedWkStn"
|
||||
:placeholder="$t('WorkStation')"
|
||||
:items="wkstn"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select Brand -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedSequenceMode"
|
||||
:placeholder="$t('Mode')"
|
||||
:items="seqmode"
|
||||
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="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
|
||||
:headers="headers"
|
||||
:items="filteredSequenceList"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
<script setup lang="ts">
|
||||
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: 'WSK', key: 'wkstnId' },
|
||||
{ title: t('Name'), key: 'signatureId' },
|
||||
{ title: t('Mode'), key: 'signatureMode' },
|
||||
{ title: t('SignatureString'), key: 'signatureString' },
|
||||
{ title: t('SignatureSource'), key: 'signatureSource' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
|
||||
const selectedWkStn = ref()
|
||||
const selectedSignatureMode = ref()
|
||||
const searchQuery = ref('')
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
const isLoading = ref(false)
|
||||
|
||||
const data = ref([]) // Initialisez data comme un tableau vide
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const response = await useApi<any>(createUrl(`/stores/${props.storeData.store.id_structure}/signature?dbHost=${route.query.dbHost}`))
|
||||
|
||||
data.value = response.data.value
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
const wkstn = computed(() => {
|
||||
const allWkstns = data.value.map((store: { wkstnId: any }) => store.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()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
return sortedWkstns.map((wkstn: any) => ({ title: wkstn, value: wkstn }))
|
||||
})
|
||||
|
||||
const signmode = computed(() => {
|
||||
const allSignModes = data.value.map((store: { signMode: any }) => store.signMode)
|
||||
|
||||
const uniqueSignMoeds = allSignModes.filter((signmod: any, index: any, self: string | any[]) => self.indexOf(signmod) === index)
|
||||
const sortedSignMoeds = uniqueSignMoeds.sort()
|
||||
|
||||
return sortedSignMoeds.map((signmod: any) => ({ title: signmod, value: signmod }))
|
||||
})
|
||||
|
||||
const filteredSigantureList = computed(() => {
|
||||
let filtered = data.value
|
||||
|
||||
// If a workstation is selected, filter the records for this number
|
||||
if (selectedWkStn.value !== undefined && selectedWkStn.value !== null)
|
||||
filtered = filtered.filter((store: { wkstnId: any }) => store.wkstnId === selectedWkStn.value)
|
||||
|
||||
// If a signature mode is selected, filter the records for this mode
|
||||
if (selectedSignatureMode.value !== undefined && selectedSignatureMode.value !== null)
|
||||
filtered = filtered.filter((store: { signMode: any }) => store.signMode === selectedSignatureMode.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
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 👉 stores -->
|
||||
<VCard class="mb-6">
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<!-- 👉 Select country -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedWkStn"
|
||||
:placeholder="$t('WorkStation')"
|
||||
:items="wkstn"
|
||||
clearable
|
||||
clear-icon="tabler-x"
|
||||
/>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Select Brand -->
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="4"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="selectedSignatureMode"
|
||||
:placeholder="$t('Mode')"
|
||||
:items="signmode"
|
||||
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="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
|
||||
:headers="headers"
|
||||
:items="filteredSigantureList"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,33 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
interface Store {
|
||||
id_structure: number
|
||||
nom: string
|
||||
ip: string
|
||||
telephone: string
|
||||
photoLink: string
|
||||
enseigne: string
|
||||
}
|
||||
|
||||
interface Replication {
|
||||
pendingReplicationOk: boolean
|
||||
pendingReplications: number
|
||||
minPendingReplicationDate: string
|
||||
maxPendingReplicationDate: string
|
||||
}
|
||||
|
||||
interface Transaction {
|
||||
backOfficeTransactionOk: boolean
|
||||
backOfficeTransactions: number
|
||||
minBackOfficeTransactionDate: string
|
||||
maxBackOfficeTransactionDate: string
|
||||
backOfficeBusinessDate: string
|
||||
}
|
||||
|
||||
interface StoreData {
|
||||
store: Store
|
||||
replication: Replication
|
||||
transaction: Transaction
|
||||
}
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
|
|
@ -37,14 +9,185 @@ const props = defineProps<Props>()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 👉 User fullName -->
|
||||
<h6 class="text-h4 mt-4">
|
||||
{{ props.storeData.store.id_structure }}
|
||||
</h6>
|
||||
<VRow class="py-6">
|
||||
<!-- 👉 Business date & opening hours -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="3"
|
||||
:class="$vuetify.display.mdAndUp ? 'border-e' : 'border-b'"
|
||||
>
|
||||
<div class="ape-3">
|
||||
<div class="d-flex justify-space-between flex-wrap gap-4 flex-column flex-xs-row">
|
||||
<div>
|
||||
<VCard title="STORE TAB GENERAL">
|
||||
<VCardText>We carefully crafted JWT flow so you can implement JWT with ease and with minimum efforts.</VCardText>
|
||||
<VCardText>Please read our JWT Documentation to get more out of JWT authentication.</VCardText>
|
||||
</VCard>
|
||||
<div class="d-flex mb-4">
|
||||
<VAvatar
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
rounded
|
||||
size="54"
|
||||
class="text-primary me-4"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-calendar-event"
|
||||
size="38"
|
||||
/>
|
||||
</VAvatar>
|
||||
<div>
|
||||
<span class="text-base">Business date</span>
|
||||
<h4 class="text-h4 font-weight-medium text-primary">
|
||||
{{ storeData.openingTransaction.maxDateT }}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
variant="tonal"
|
||||
color="info"
|
||||
rounded
|
||||
size="54"
|
||||
class="text-primary me-4"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-clock-hour-10"
|
||||
size="38"
|
||||
/>
|
||||
</VAvatar>
|
||||
<div>
|
||||
<span class="text-base">Opening hours</span>
|
||||
<h4 class="text-h4 font-weight-medium text-info">
|
||||
{{ storeData.openingTransaction.maxDateH }}{{ storeData.closingTransaction.maxDateH ? ` / ${storeData.closingTransaction.maxDateH}` : '' }}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 Pending Replication -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="3"
|
||||
:class="$vuetify.display.mdAndUp ? 'border-e' : 'border-b'"
|
||||
>
|
||||
<div class="d-flex justify-space-between align-center">
|
||||
<div class="d-flex flex-column ps-3">
|
||||
<h5 class="text-h5 text-high-emphasis mb-0 text-no-wrap">
|
||||
Pending replication
|
||||
</h5>
|
||||
<div class="text-h3 mb-2">
|
||||
{{ props.storeData.replication.pendingReplications }}
|
||||
</div>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Min
|
||||
</VChip>
|
||||
{{ props.storeData.replication.minPendingReplicationDate }}
|
||||
</div>
|
||||
</span>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Max
|
||||
</VChip>
|
||||
{{ props.storeData.replication.maxPendingReplicationDate }}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 XSTORE Ticket -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="3"
|
||||
:class="$vuetify.display.mdAndUp ? 'border-e' : 'border-b'"
|
||||
>
|
||||
<div class="d-flex justify-space-between align-center">
|
||||
<div class="d-flex flex-column ps-3">
|
||||
<h5 class="text-h5 text-high-emphasis mb-0 text-no-wrap">
|
||||
XSTORE Tickets
|
||||
</h5>
|
||||
<div class="text-h3 mb-2">
|
||||
{{ props.storeData.saleTransaction.count }}
|
||||
</div>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Min
|
||||
</VChip>
|
||||
{{ props.storeData.saleTransaction.minDate }}
|
||||
</div>
|
||||
</span>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Max
|
||||
</VChip>
|
||||
{{ props.storeData.saleTransaction.maxDate }}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
|
||||
<!-- 👉 DOTSOFT Tickets -->
|
||||
<VCol
|
||||
cols="12"
|
||||
md="3"
|
||||
>
|
||||
<div class="d-flex justify-space-between align-center">
|
||||
<div class="d-flex flex-column ps-3">
|
||||
<h5 class="text-h5 text-high-emphasis mb-0 text-no-wrap">
|
||||
DOTSOFT Tickets
|
||||
</h5>
|
||||
<div class="text-h3 mb-2">
|
||||
{{ props.storeData.transaction.backOfficeTransactions }}
|
||||
</div>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Min
|
||||
</VChip>
|
||||
{{ props.storeData.transaction.minBackOfficeTransactionDate }}
|
||||
</div>
|
||||
</span>
|
||||
<span class="mb-1">
|
||||
<div>
|
||||
<VChip
|
||||
variant="tonal"
|
||||
color="secondary"
|
||||
style="inline-size:45px"
|
||||
>
|
||||
Max
|
||||
</VChip>
|
||||
{{ props.storeData.transaction.maxBackOfficeTransactionDate }}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,84 @@
|
|||
<script lang="ts" setup>
|
||||
import { provide, ref } from 'vue'
|
||||
import { VForm } from 'vuetify/components/VForm'
|
||||
import StoreTabItemH from '@/views/pages/store/view/StoreTabItemH.vue'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { t } = useI18n()
|
||||
|
||||
const itemForm = ref('')
|
||||
const injItemForm = ref('')
|
||||
const refItemForm = ref<VForm>()
|
||||
|
||||
provide('item', injItemForm)
|
||||
|
||||
const validateItemForm = () => {
|
||||
refItemForm.value?.validate().then(valid => {
|
||||
if (valid.valid) {
|
||||
console.log(itemForm.value)
|
||||
injItemForm.value = itemForm.value
|
||||
}
|
||||
else { console.log(`KO:${itemForm.value}`) }
|
||||
})
|
||||
}
|
||||
|
||||
const lengthMinValidator = (value: unknown, length: number) => {
|
||||
if (isEmpty(value))
|
||||
return true
|
||||
|
||||
return String(value).length >= length || `The Min Character field must be at least ${length} characters`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCard title="STORE TAB ITEM">
|
||||
<VCardText>We carefully crafted JWT flow so you can implement JWT with ease and with minimum efforts.</VCardText>
|
||||
<VCardText>Please read our JWT Documentation to get more out of JWT authentication.</VCardText>
|
||||
<VRow>
|
||||
<VCol cols="12">
|
||||
<!-- 👉 Item search -->
|
||||
<VCard title="">
|
||||
<VCardText>
|
||||
<VAlert
|
||||
variant="tonal"
|
||||
color="warning"
|
||||
class="mb-4"
|
||||
>
|
||||
<VAlertTitle class="mb-2">
|
||||
{{ $t('You can search for a reference, reference-color or reference-color-size.') }}
|
||||
</VAlertTitle>
|
||||
<span>{{ $t('Minimum 5 characters long') }}</span>
|
||||
</VAlert>
|
||||
|
||||
<VForm
|
||||
ref="refItemForm"
|
||||
@submit.prevent="validateItemForm"
|
||||
>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<AppTextField
|
||||
v-model="itemForm"
|
||||
label="Reference"
|
||||
persistent-placeholder
|
||||
placeholder="QY10010"
|
||||
:rules="[requiredValidator, lengthMinValidator(itemForm, 5)]"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VBtn type="submit">
|
||||
{{ $t('Submit') }}
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
|
||||
<VCol cols="12">
|
||||
<StoreTabItemH />
|
||||
</VCol>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import StoreTabItemHitem from '@/views/pages/store/view/StoreTabItemHitem.vue'
|
||||
import StoreTabItemHoption from '@/views/pages/store/view/StoreTabItemHoption.vue'
|
||||
import StoreTabItemHprice from '@/views/pages/store/view/StoreTabItemHprice.vue'
|
||||
import StoreTabItemHstock from '@/views/pages/store/view/StoreTabItemHstock.vue'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { t } = useI18n()
|
||||
|
||||
const item = inject<string>('item')
|
||||
|
||||
const currentTab = ref('tab-1')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VTabs
|
||||
v-model="currentTab"
|
||||
grow
|
||||
stacked
|
||||
>
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-shirt-sport"
|
||||
/>
|
||||
{{ $t('Item') }}
|
||||
</VTab>
|
||||
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-report-money"
|
||||
/>
|
||||
{{ $t('Option') }}
|
||||
</VTab>
|
||||
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-currency-euro"
|
||||
/>
|
||||
{{ $t('Price') }}
|
||||
</VTab>
|
||||
|
||||
<VTab>
|
||||
<VIcon
|
||||
start
|
||||
icon="tabler-building-warehouse"
|
||||
/>
|
||||
{{ $t('Stock') }}
|
||||
</VTab>
|
||||
</VTabs>
|
||||
|
||||
<VCardText style="padding: 5px !important;">
|
||||
<VWindow
|
||||
v-model="currentTab"
|
||||
class="ms-3"
|
||||
>
|
||||
<VWindowItem value="tab-1">
|
||||
<StoreTabItemHitem :item="item" />
|
||||
</VWindowItem>
|
||||
<VWindowItem value="tab-2">
|
||||
<StoreTabItemHoption :item="item" />
|
||||
</VWindowItem>
|
||||
<VWindowItem value="tab-3">
|
||||
<StoreTabItemHprice :item="item" />
|
||||
</VWindowItem>
|
||||
<VWindowItem value="tab-4">
|
||||
<StoreTabItemHstock :item="item" />
|
||||
</VWindowItem>
|
||||
</VWindow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<script setup lang="ts">
|
||||
import { watchEffect } from 'vue'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const props = defineProps({
|
||||
item: String,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
|
||||
const fetchedData = ref<Array<Record<string, unknown>>>([])
|
||||
const isLoading = ref(false)
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const { data } = await useApi<any>(createUrl(`/items/${props.item}?dbHost=${route.query.dbHost}`))
|
||||
|
||||
fetchedData.value = data.value
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
// eslint-disable-next-line sonarjs/no-collapsible-if
|
||||
if (props.item)
|
||||
// eslint-disable-next-line curly
|
||||
if (!(props.item.trim() === ''))
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: t('ITEM_ID'), key: 'itemId' },
|
||||
{ title: t('LEVEL'), key: 'itemLevelCode' },
|
||||
{ title: t('PARENT'), key: 'parentItemId' },
|
||||
{ title: t('TYPE'), key: 'itemTypeCode' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCol>
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<VDataTable
|
||||
v-else
|
||||
:headers="headers"
|
||||
:items="fetchedData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<script setup lang="ts">
|
||||
import { watchEffect } from 'vue'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const props = defineProps({
|
||||
item: String,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
const isLoading = ref(false)
|
||||
|
||||
const fetchedData = ref<Array<Record<string, unknown>>>([])
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const { data } = await useApi<any>(createUrl(`/items/${props.item}/options?dbHost=${route.query.dbHost}`))
|
||||
|
||||
fetchedData.value = data.value.map((item: any) => ({
|
||||
...item,
|
||||
level: `${item.levelCode}:${item.levelValue}`,
|
||||
}))
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
// eslint-disable-next-line sonarjs/no-collapsible-if
|
||||
if (props.item)
|
||||
// eslint-disable-next-line curly
|
||||
if (!(props.item.trim() === ''))
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: t('ITEM_ID'), key: 'itemId' },
|
||||
{ title: 'LEVEL', key: 'level' },
|
||||
{ title: 'VENDABLE', key: 'itemAvailabilityCode' },
|
||||
{ title: 'TAXE', key: 'taxGroupId' },
|
||||
{ title: 'VENDOR', key: 'vendor' },
|
||||
{ title: 'SEASON', key: 'seasonCode' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCol>
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<!-- 👉 Datatable -->
|
||||
<VDataTable
|
||||
v-else
|
||||
:headers="headers"
|
||||
:items="fetchedData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<script setup lang="ts">
|
||||
import { watchEffect } from 'vue'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const props = defineProps({
|
||||
item: String,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
const isLoading = ref(false)
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
|
||||
const fetchedData = ref<Array<Record<string, unknown>>>([])
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const { data } = await useApi<any>(createUrl(`/items/${props.item}/price?dbHost=${route.query.dbHost}`))
|
||||
|
||||
fetchedData.value = data.value.map((item: any) => ({
|
||||
...item,
|
||||
level: `${item.levelCode}:${item.levelValue}`,
|
||||
}))
|
||||
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
// eslint-disable-next-line sonarjs/no-collapsible-if
|
||||
if (props.item)
|
||||
// eslint-disable-next-line curly
|
||||
if (!(props.item.trim() === ''))
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: t('ITEM_ID'), key: 'itemId' },
|
||||
{ title: t('LEVEL'), key: 'level' },
|
||||
{ title: t('TYPE'), key: 'itmPricePropertyCode' },
|
||||
{ title: t('EFFECTIVE DATE'), key: 'effectiveDate' },
|
||||
{ title: t('EXPIRATION DATE'), key: 'expirationDate' },
|
||||
{ title: t('PRICE'), key: 'price' },
|
||||
{ title: 'EXTERNAL ID', key: 'externalId' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCol>
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<VDataTable
|
||||
v-else
|
||||
:headers="headers"
|
||||
:items="fetchedData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<script setup lang="ts">
|
||||
import { watchEffect } from 'vue'
|
||||
import { VDataTable } from 'vuetify/labs/VDataTable'
|
||||
|
||||
const props = defineProps({
|
||||
item: String,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute('store-details')
|
||||
|
||||
// Data table options
|
||||
const options = ref({ page: 1, itemsPerPage: 10, sortBy: [''], sortDesc: [false] })
|
||||
|
||||
const fetchedData = ref<Array<Record<string, unknown>>>([])
|
||||
const isLoading = ref(false)
|
||||
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
const { data } = await useApi<any>(createUrl(`/items/${props.item}/stock?dbHost=${route.query.dbHost}`))
|
||||
|
||||
fetchedData.value = data.value
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
// eslint-disable-next-line sonarjs/no-collapsible-if
|
||||
if (props.item)
|
||||
// eslint-disable-next-line curly
|
||||
if (!(props.item.trim() === ''))
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// const { t } = useI18n()
|
||||
|
||||
const headers = computed(() => [
|
||||
{ title: t('ITEM_ID'), key: 'itemId' },
|
||||
{ title: 'LOCATION', key: 'invLocationId' },
|
||||
{ title: 'BUCKET', key: 'bucketId' },
|
||||
{ title: 'STOCK', key: 'unitCount' },
|
||||
{ title: t('DATE_CREATE'), key: 'createDate' },
|
||||
{ title: t('USER_CREATE'), key: 'createUserId' },
|
||||
{ title: t('DATE_UPDATE'), key: 'updateDate' },
|
||||
{ title: t('USER_UPDATE'), key: 'updateUserId' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VCol>
|
||||
<div v-if="isLoading">
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<VDataTable
|
||||
v-else
|
||||
:headers="headers"
|
||||
:items="fetchedData"
|
||||
:items-per-page="options.itemsPerPage"
|
||||
:page="options.page"
|
||||
:options="options"
|
||||
density="compact"
|
||||
/>
|
||||
</VCol>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { StoreData } from '@/models/storeData'
|
||||
import logoVNC from '@images/misc/remote_128.png'
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const drive = ['M:', 'N:', 'O:', 'P:', 'Q:', 'R:', 'S:', 'T:']
|
||||
|
||||
interface Props {
|
||||
storeData: StoreData
|
||||
}
|
||||
|
||||
const localStoreData = ref()
|
||||
|
||||
onMounted(() => {
|
||||
// use copy a store data to prevent changes of ip field
|
||||
localStoreData.value = JSON.parse(JSON.stringify(props.storeData))
|
||||
localStoreData.value.store.caisses = localStoreData.value.store.caisses.map((caisse: any) => ({
|
||||
...caisse,
|
||||
drive: null, // replace null with the initial value you want to use
|
||||
}))
|
||||
})
|
||||
|
||||
const openVnc = (ip: string) => {
|
||||
const url = `vnc://${ip}`
|
||||
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const mountDrive = (ip: string, drive: string) => {
|
||||
const url = `hdpos://monter?lettre=${drive}&ip=${ip}`
|
||||
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<VCard
|
||||
flat
|
||||
border
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<img
|
||||
:src="logoVNC"
|
||||
size="128"
|
||||
>
|
||||
<div v-if="localStoreData && localStoreData.store.caisses">
|
||||
<div
|
||||
v-for="(caisse, index) in localStoreData.store.caisses"
|
||||
:key="index"
|
||||
class="d-flex align-items-center mb-5"
|
||||
>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="6"
|
||||
md="6"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<VTextField
|
||||
v-model.lazy="caisse.ip"
|
||||
label="IP"
|
||||
class="me-3"
|
||||
/>
|
||||
<VBtn
|
||||
v-if="caisse.ip"
|
||||
color="primary"
|
||||
@click="openVnc(caisse.ip)"
|
||||
>
|
||||
Pos {{ caisse.id_caisse }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-else
|
||||
disabled
|
||||
color="primary"
|
||||
>
|
||||
Pos {{ caisse.id_caisse }}
|
||||
</VBtn>
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="6"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<AppSelect
|
||||
v-model="caisse.drive"
|
||||
:items="drive"
|
||||
label=""
|
||||
density="compact"
|
||||
placeholder="Select"
|
||||
class="me-3"
|
||||
/>
|
||||
<VBtn
|
||||
v-if="caisse.drive"
|
||||
color="primary"
|
||||
@click="mountDrive(caisse.ip, caisse.drive)"
|
||||
>
|
||||
Mount drive {{ caisse.drive }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-else
|
||||
disabled
|
||||
color="primary"
|
||||
>
|
||||
Mount drive
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
||||