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