refactor: selected table product
This commit is contained in:
parent
46b69deb59
commit
9083dab4af
1 changed files with 373 additions and 0 deletions
373
src/components/04_product-service/TableProduct.vue
Normal file
373
src/components/04_product-service/TableProduct.vue
Normal 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>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue