refactor: selected table product

This commit is contained in:
Thanaphon Frappet 2024-11-27 14:53:25 +07:00
parent 46b69deb59
commit 9083dab4af

View file

@ -0,0 +1,373 @@
<script setup lang="ts">
import { ref } from 'vue';
import { QTableProps } from 'quasar';
import { Product } from 'stores/product-service/types';
import KebabAction from 'src/components/shared/KebabAction.vue';
import useOptionStore from 'stores/options';
import { formatNumberDecimal } from 'stores/utils';
import { dateFormat } from 'src/utils/datetime';
const optionStore = useOptionStore();
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
const selectedItem = defineModel<Product[]>('selectedItem');
const props = withDefaults(
defineProps<{
row: QTableProps['rows'];
column: QTableProps['columns'];
grid?: boolean;
fieldSelected?: string[];
currentPage?: number;
pageSize?: number;
useKebabAction?: boolean;
}>(),
{
row: () => [],
column: () => [],
grid: false,
fieldSelected: () => [],
currentPage: 1,
pageSize: 1,
useKebabAction: false,
},
);
defineEmits<{
(e: 'view'): void;
(e: 'edit'): void;
(e: 'delete'): void;
(e: 'changeStatus'): void;
(e: 'select', data: any): void;
}>();
</script>
<template>
<q-table
bordered
:rows="row"
:columns="column"
:rows-per-page-options="[0]"
:grid="grid"
v-model:selected="selectedItem"
row-key="id"
@update:selected="(v) => $emit('select', v)"
card-container-class="row full-width q-col-gutter-md"
hide-pagination
selection="multiple"
>
<template v-slot:header="props">
<q-tr
style="background-color: hsla(var(--info-bg) / 0.07)"
:props="props"
>
<q-th auto-width></q-th>
<template v-for="col in props.cols" :key="col.name" :props="props">
<q-th>
{{ $t(col.label) }}
</q-th>
</template>
<q-th v-if="!!useKebabAction" auto-width />
</q-tr>
</template>
<template v-slot:body="props">
<q-tr
:style="
props.rowIndex % 2 !== 0
? $q.dark.isActive
? 'background: hsl(var(--gray-11-hsl)/0.2)'
: `background: #f9fafc`
: ''
"
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
}"
class="cursor-pointer"
:props="props"
@click.stop="$emit('select', props.row)"
>
<q-td>
<q-checkbox
:model-value="props.selected"
@click.stop="$emit('select', props.row)"
/>
</q-td>
<q-td
class="text-center"
v-if="fieldSelected.includes('branchLabelNo')"
>
{{ (currentPage - 1) * pageSize + props.rowIndex + 1 }}
</q-td>
<q-td v-if="fieldSelected.includes('productName')">
<div class="row items-center no-wrap">
<div
:class="{
'status-active': props.row.status !== 'INACTIVE',
'status-inactive': props.row.status === 'INACTIVE',
}"
style="width: 50px; display: flex; margin-bottom: var(--size-2)"
>
<div class="table__icon" :class="`icon-color-green`">
<q-avatar size="md">
<q-img
class="text-center"
:ratio="1"
:src="`${baseUrl}/product/${props.row.id}/image/${props.row.selectedImage}`"
>
<template #error>
<q-icon
size="sm"
name="mdi-shopping-outline"
style="top: 10%"
:style="`color: var(teal-10)`"
/>
</template>
</q-img>
</q-avatar>
</div>
</div>
<div class="column">
<div class="ellipsis" style="max-width: 20vw">
{{ props.row.name }}
<q-tooltip anchor="bottom left" self="center left" :delay="300">
{{ props.row.name }}
</q-tooltip>
</div>
<div class="app-text-muted">
{{ props.row.code }}
</div>
</div>
</div>
</q-td>
<q-td
class="ellipsis"
style="max-width: 150px"
v-if="fieldSelected.includes('productDetail')"
>
{{ props.row.detail || '-' }}
</q-td>
<q-td v-if="fieldSelected.includes('productExpenseType')">
{{ optionStore.mapOption(props.row.expenseType) }}
</q-td>
<q-td v-if="fieldSelected.includes('productProcessingTime')">
{{ props.row.process }}
</q-td>
<q-td v-if="fieldSelected.includes('productVat')">
{{ $t('productService.product.vatIncluded') }}
</q-td>
<q-td v-if="fieldSelected.includes('priceInformation')">
<div
class="row full-width q-gutter-x-md no-wrap items-center text-right"
>
<div
class="tags tags-color-orange col column ellipsis-2-lines"
:class="{
disable: props.row.status === 'INACTIVE',
}"
style="min-width: 50px"
>
<div class="col app-text-muted-2 text-caption">
{{ $t('productService.product.salePrice') }}
</div>
<div class="col text-weight-bold">
฿{{ formatNumberDecimal(props.row.price || 0, 2) }}
</div>
</div>
<div
class="tags tags-color-purple col column ellipsis-2-lines"
:class="{
disable: props.row.status === 'INACTIVE',
}"
style="min-width: 50px"
>
<div class="col app-text-muted-2 text-caption">
{{ $t('productService.product.agentPrice') }}
</div>
<div class="col text-weight-bold">
฿{{ formatNumberDecimal(props.row.agentPrice || 0, 2) }}
</div>
</div>
<div
class="tags tags-color-pink col column ellipsis-2-lines"
:class="{
disable: props.row.status === 'INACTIVE',
}"
style="min-width: 50px"
>
<div class="col app-text-muted-2 text-caption">
{{ $t('productService.product.processingPrice') }}
</div>
<div class="col">
฿{{ formatNumberDecimal(props.row.serviceCharge || 0, 2) }}
</div>
</div>
</div>
</q-td>
<q-td v-if="fieldSelected.includes('createdAt')">
{{ dateFormat(props.row.createdAt) }}
</q-td>
<q-td v-if="!!useKebabAction">
<q-btn
icon="mdi-eye-outline"
:id="`btn-eye-${props.row.name}`"
size="sm"
dense
round
flat
@click.stop="$emit('view')"
/>
<KebabAction
:status="props.row.status"
:id-name="props.row.name"
@view="$emit('view')"
@edit="$emit('edit')"
@delete="$emit('delete')"
@change-status="$emit('changeStatus')"
/>
</q-td>
</q-tr>
</template>
<template v-slot:item="{ row }">
<div class="col-3"><slot name="grid" :row="row" /></div>
</template>
</q-table>
</template>
<style scoped>
.status-active {
--_branch-status-color: var(--green-6-hsl);
}
.status-inactive {
--_branch-status-color: var(--stone-5-hsl);
--_branch-badge-bg: var(--stone-5-hsl);
filter: grayscale(0.5);
opacity: 0.5;
}
.icon-color-purple {
--_color: var(--violet-11-hsl);
}
.icon-color-pink {
--_color: var(--pink-6-hsl);
}
.icon-color-orange {
--_color: var(--orange-5-hsl);
}
.icon-color-green {
--_color: var(--teal-10-hsl);
}
.dark .icon-color-purple {
--_color: var(--violet-10-hsl);
}
.dark .icon-color-green {
--_color: var(--teal-8-hsl);
}
.dark .icon-color-orange {
--_color: var(--orange-6-hsl);
}
.tags-color-green {
--_color-tag: var(--teal-10-hsl);
}
.dark .tags-color-green {
--_color-tag: var(--teal-8-hsl);
}
.tags-color-orange {
--_color-tag: var(--orange-5-hsl);
}
.dark .tags-color-orange {
--_color-tag: var(--orange-6-hsl);
}
.tags-color-purple {
--_color-tag: var(--violet-11-hsl);
}
.dark .tags-color-purple {
--_color-tag: var(--violet-10-hsl);
}
.tags-color-pink {
--_color-tag: var(--pink-6-hsl);
}
.table__icon {
background-color: hsla(var(--_color) / 0.15);
color: hsla(var(--_color) / 1);
border-radius: 50%;
position: relative;
transform: rotate(45deg);
&::after {
content: ' ';
display: block;
block-size: 0.5rem;
aspect-ratio: 1;
position: absolute;
border-radius: 50%;
right: -0.1rem;
top: calc(50% - 0.25rem);
bottom: calc(50% - 0.25rem);
background-color: hsla(var(--_branch-status-color) / 1);
}
&:deep(.q-icon) {
transform: rotate(-45deg);
color: hsla(var(--_branch-card-bg) / 1);
}
&:deep(.q-img) {
transform: rotate(-45deg);
&:deep(.q-icon) {
transform: rotate(0deg);
}
}
}
.tags {
display: inline-block;
color: hsla(var(--_color-tag) / 1);
background: hsla(var(--_color-tag) / 0.075);
border-radius: var(--radius-2);
padding-inline: var(--size-2);
&.disable {
filter: grayscale(100%);
opacity: 80%;
}
}
* :deep(.q-icon.mdi-play) {
display: none;
}
.product-form-active {
background-color: hsla(var(--info-bg) / 0.2);
color: hsl(var(--info-bg));
font-weight: 600;
}
:deep(.split-pay .q-field__control) {
height: 23px;
}
</style>