feat: add attachment tab and improve layout for product and customer management pages

This commit is contained in:
puriphatt 2025-01-07 12:42:19 +07:00
parent 9590467d0f
commit 4f5320cb36
4 changed files with 164 additions and 130 deletions

View file

@ -100,20 +100,22 @@ withDefaults(
</script> </script>
<template> <template>
<div class="row col-12"> <div class="row col-12 full-width">
<div class="col-12 q-pb-sm row items-center"> <div class="col-12 q-pb-sm row items-center">
<q-icon <div :class="{ 'col-12': $q.screen.lt.sm }">
flat <q-icon
size="xs" flat
class="q-pa-sm rounded q-mr-sm" size="xs"
color="info" class="q-pa-sm rounded q-mr-sm"
name="mdi-cash" color="info"
style="background-color: var(--surface-3)" name="mdi-cash"
/> style="background-color: var(--surface-3)"
<span class="text-body1 text-weight-bold"> />
{{ $t('productService.product.priceInformation') }} <span class="text-body1 q-pr-md text-weight-bold">
</span> {{ $t('productService.product.priceInformation') }}
<section class="q-px-md"> </span>
</div>
<section class="q-pr-md">
<input <input
id="input-calc-vat" id="input-calc-vat"
type="checkbox" type="checkbox"

View file

@ -269,7 +269,7 @@ const smallBanner = ref(false);
v-bind:key="tab.name" v-bind:key="tab.name"
class="content-tab text-capitalize" class="content-tab text-capitalize"
:name="tab.name" :name="tab.name"
:label="$t(tab.label)" :label="tab.label"
/> />
</q-tabs> </q-tabs>
</div> </div>
@ -283,12 +283,12 @@ const smallBanner = ref(false);
v-if="(!$q.screen.gt.sm && smallBanner) || smallBanner || $q.screen.lt.sm" v-if="(!$q.screen.gt.sm && smallBanner) || smallBanner || $q.screen.lt.sm"
fit="cover" fit="cover"
class="cover rounded bordered relative-position" class="cover rounded bordered relative-position"
:style="`height: 45px`" :style="`height: ${tabsList ? '100' : '45'}px`"
:src="coverUrl || fallbackCover || '/blank-cover.png'" :src="coverUrl || fallbackCover || '/blank-cover.png'"
@error="coverUrl = ''" @error="coverUrl = ''"
> >
<nav <nav
class="full-width full-height row no-wrap items-center" class="full-width full-height column"
:style="`background-image: linear-gradient( :style="`background-image: linear-gradient(
90deg, ${ 90deg, ${
$q.dark.isActive $q.dark.isActive
@ -298,124 +298,148 @@ const smallBanner = ref(false);
)`" )`"
> >
<!-- profile --> <!-- profile -->
<div class="flex items-center full-height q-pl-lg" style="z-index: 1"> <span class="row col items-center">
<div <div class="flex items-center full-height q-pl-lg" style="z-index: 1">
class="surface-1" <div
style="border-radius: 50%; border: 2px solid var(--surface-1)" class="surface-1"
> style="border-radius: 50%; border: 2px solid var(--surface-1)"
<q-avatar
size="35px"
font-size="20px"
class="relative-position"
style="z-index: 1; box-shadow: var(--shadow-2)"
:style="{
color: `${color || 'white'}`,
cursor: `${noImageAction ? 'default' : 'pointer'}`,
}"
@mouseover="showOverlay = true"
@mouseleave="showOverlay = false"
@click.stop="$emit('view')"
> >
<div <q-avatar
v-if="img" size="35px"
class="full-width full-height" font-size="20px"
class="relative-position"
style="z-index: 1; box-shadow: var(--shadow-2)"
:style="{ :style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`, color: `${color || 'white'}`,
cursor: `${noImageAction ? 'default' : 'pointer'}`,
}" }"
> @mouseover="showOverlay = true"
<q-img id="profile-view" :src="img" :ratio="1"> @mouseleave="showOverlay = false"
<template #error> @click.stop="$emit('view')"
<q-img
v-if="fallbackImg"
:src="fallbackImg"
:ratio="1"
style="background-color: transparent"
>
<template #error>
<div
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
</template>
</q-img>
<div
v-else
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
</template>
</q-img>
</div>
<div
v-else
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
<div
v-if="!hideActive"
class="absolute-bottom-right"
style="
border-radius: 50%;
width: 10px;
height: 10px;
z-index: 2;
background: var(--surface-1);
"
> >
<div <div
class="absolute-center" v-if="img"
style="border-radius: 50%; width: 8px; height: 8px" class="full-width full-height"
:style="`background: hsl(var(${active ? '--positive-bg' : '--text-mute'}))`" :style="{
/> background: `${bgColor || 'var(--brand-1)'}`,
</div> color: `${color || 'white'}`,
</q-avatar> }"
</div> >
</div> <q-img id="profile-view" :src="img" :ratio="1">
<template #error>
<q-img
v-if="fallbackImg"
:src="fallbackImg"
:ratio="1"
style="background-color: transparent"
>
<template #error>
<div
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
</template>
</q-img>
<div
v-else
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
</template>
</q-img>
</div>
<div
v-else
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<Icon
class="full-width full-height flex items-center justify-center"
:icon="icon || 'mdi-account'"
/>
</div>
<div class="col column full-height text-caption q-ml-md"> <div
<span class="text-bold ellipsis absolute" style="bottom: 16px"> v-if="!hideActive"
{{ title }} class="absolute-bottom-right"
<q-tooltip anchor="bottom left" self="center left" :delay="300"> style="
border-radius: 50%;
width: 10px;
height: 10px;
z-index: 2;
background: var(--surface-1);
"
>
<div
class="absolute-center"
style="border-radius: 50%; width: 8px; height: 8px"
:style="`background: hsl(var(${active ? '--positive-bg' : '--text-mute'}))`"
/>
</div>
</q-avatar>
</div>
</div>
<div class="col column full-height justify-center text-caption q-ml-md">
<span class="text-bold ellipsis" style="bottom: 16px">
{{ title }} {{ title }}
</q-tooltip> <q-tooltip anchor="bottom left" self="center left" :delay="300">
</span> {{ title }}
<span </q-tooltip>
v-if="title" </span>
class="absolute" <span
:class="$q.dark.isActive ? 'foreground' : 'app-text-muted'" v-if="title"
style="font-size: 10px; bottom: 4px" :class="$q.dark.isActive ? 'foreground' : 'app-text-muted'"
style="font-size: 10px; bottom: 4px"
>
{{ caption }}
</span>
</div>
</span>
<span class="row full-width" v-if="tabsList && currentTab">
<q-tabs
dense
inline-label
mobile-arrows
v-model="currentTab"
active-class="active-tab text-weight-bold"
class="app-text-muted full-width"
align="left"
v-if="typeof tabsList === 'object'"
> >
{{ caption }} <q-tab
</span> v-for="tab in tabsList"
</div> :id="`${prefix}-tab-${tab.label}`"
v-bind:key="tab.name"
class="content-tab text-capitalize"
:name="tab.name"
:label="tab.label"
/>
</q-tabs>
</span>
<q-btn <q-btn
v-if="$q.screen.gt.xs"
class="absolute-top-right q-ma-xs" class="absolute-top-right q-ma-xs"
color="primary" color="primary"
flat flat

View file

@ -4322,25 +4322,25 @@ const emptyCreateDialog = ref(false);
:tabs-list="[ :tabs-list="[
{ {
name: 'personalInfo', name: 'personalInfo',
label: 'customerEmployee.form.group.personalInfo', label: $t('customerEmployee.form.group.personalInfo'),
}, },
{ {
name: 'passport', name: 'passport',
label: 'customerEmployee.fileType.passport', label: $t('customerEmployee.fileType.passport'),
}, },
{ {
name: 'visa', name: 'visa',
label: 'customerEmployee.form.group.visa', label: $t('customerEmployee.form.group.visa'),
}, },
{ {
name: 'healthCheck', name: 'healthCheck',
label: 'customerEmployee.form.group.healthCheck', label: $t('customerEmployee.form.group.healthCheck'),
}, },
{ {
name: 'workHistory', name: 'workHistory',
label: 'customerEmployee.form.group.workHistory', label: $t('customerEmployee.form.group.workHistory'),
}, },
{ name: 'other', label: 'customerEmployee.form.group.other' }, { name: 'other', label: $t('customerEmployee.form.group.other') },
]" ]"
:toggle-title="$t('status.title')" :toggle-title="$t('status.title')"
/> />

View file

@ -3709,6 +3709,10 @@ watch(
name: 2, name: 2,
label: $t('productService.product.priceInformation'), label: $t('productService.product.priceInformation'),
}, },
{
name: 3,
label: $t('general.attachment'),
},
] ]
" "
v-model:current-tab="productTab" v-model:current-tab="productTab"
@ -3871,6 +3875,10 @@ watch(
name: 2, name: 2,
label: $t('productService.product.priceInformation'), label: $t('productService.product.priceInformation'),
}, },
{
name: 3,
label: $t('general.attachment'),
},
] ]
" "
v-model:currentTab="productTab" v-model:currentTab="productTab"
@ -3878,7 +3886,7 @@ watch(
</div> </div>
<div <div
class="col surface-1 rounded bordered scroll row relative-position" class="col surface-1 rounded bordered scroll row relative-position full-width"
id="product-form" id="product-form"
:class="{ :class="{
'q-mb-lg q-mx-lg ': $q.screen.gt.sm, 'q-mb-lg q-mx-lg ': $q.screen.gt.sm,