refactor: add grid / table view to product service

This commit is contained in:
Methapon2001 2024-07-09 11:19:10 +07:00
parent dbb366ead3
commit face6973cd

View file

@ -1,8 +1,9 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { ref, watch, reactive } from 'vue';
import { useI18n } from 'vue-i18n';
import { onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import type { QTableProps } from 'quasar';
import ItemCard from 'components/ItemCard.vue';
import AppBox from 'components/app/AppBox.vue';
import AddButton from 'components/AddButton.vue';
@ -120,6 +121,8 @@ const currentStatusProduct = ref(false);
const drawerInfo = ref(false);
const isEdit = ref(false);
const modeView = ref(false);
const dialogInputForm = ref(false);
const dialogProduct = ref(false);
const dialogService = ref(false);
@ -149,7 +152,7 @@ const service = ref<(Service & { type: 'service' })[]>();
const resultSearchProduct = ref<ProductList[]>();
const productAndService = ref<ServiceAndProduct[]>([]);
const productAndServiceTab = ref<'all' | 'product' | 'service'>('all');
const productAndServiceTab = ref<'product' | 'service'>('service');
const manageWorkNameDialog = ref(false);
const previousValue = ref();
@ -200,6 +203,69 @@ const serviceTab = [
];
const hideStat = ref(false);
const tbColumn = {
product: [
{ name: 'productName', align: 'left', label: 'productName', field: 'name' },
{
name: 'productDetail',
align: 'left',
label: 'productDetail',
field: 'detail',
},
{
name: 'productProcessingTime',
align: 'left',
label: 'productProcessingTime',
field: 'process',
},
{
name: 'priceInformation',
align: 'left',
label: 'priceInformation',
field: 'name',
},
],
service: [
{ name: 'serviceName', align: 'left', label: 'serviceName', field: 'name' },
{
name: 'serviceDetail',
align: 'left',
label: 'serviceDetail',
field: 'detail',
},
{
name: 'serviceWorkTotal',
align: 'left',
label: 'serviceWorkTotal',
field: (v) => v.work.length,
},
],
} satisfies {
product: QTableProps['columns'];
service: QTableProps['columns'];
};
const tbControl = reactive({
product: {
fieldDisplay: [
'productName',
'productDetail',
'productProcessingTime',
'priceInformation',
],
fieldSelected: [
'productName',
'productDetail',
'productProcessingTime',
'priceInformation',
],
},
service: {
fieldDisplay: ['serviceName', 'serviceDetail', 'serviceWorkTotal'],
fieldSelected: ['serviceName', 'serviceDetail', 'serviceWorkTotal'],
},
});
const workItems = ref<WorkItems[]>([]);
const workNameRef = ref();
const selectProduct = ref<ProductList[]>([]);
@ -541,10 +607,7 @@ async function deleteServiceById(serviceId?: string) {
const res = await deleteService(serviceId ?? currentIdService.value);
if (productAndServiceTab.value === 'service') {
await await fetchListOfService();
}
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
await fetchListOfService();
}
dialogServiceEdit.value = false;
@ -573,9 +636,6 @@ async function deleteTypeOfProduct(id?: string) {
if (productAndServiceTab.value === 'product') {
await fetchListOfProduct();
}
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
}
dialogProductEdit.value = false;
@ -722,7 +782,6 @@ const prevProduct = ref<ProductCreate>({
function assignFormDataProduct(data: ProductList) {
statusToggle.value = data.status === 'INACTIVE' ? false : true;
console.log(data);
profileUrl.value = `${baseUrl.value}/product/${data?.id}/image`;
profileSubmit.value = true;
@ -835,9 +894,6 @@ async function submitService() {
});
}
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
}
if (productAndServiceTab.value === 'service') {
await fetchListOfService();
}
@ -868,9 +924,6 @@ async function submitProduct() {
totalProduct.value = totalProduct.value + 1;
clearFormProduct();
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
}
if (productAndServiceTab.value === 'product') {
await fetchListOfProduct();
}
@ -957,10 +1010,6 @@ async function calculateStats() {
}
async function fetchStatus() {
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
flowStore.rotate();
}
if (productAndServiceTab.value === 'product') {
await fetchListOfProduct();
flowStore.rotate();
@ -973,15 +1022,6 @@ async function fetchStatus() {
}
async function alternativeFetch() {
console.log('asdasds');
if (productAndServiceTab.value === 'all') {
await fetchListOfProductAndService();
flowStore.rotate();
}
if (productAndServiceTab.value === 'product') {
await fetchListOfProduct();
@ -1163,10 +1203,7 @@ watch(inputSearchProductAndService, async () => {
</div>
<div v-if="stat[0].count !== 0" class="column full-height no-wrap">
<div
v-if="productMode === 'group' || productMode === 'type'"
class="text-body-2 q-mb-xs flex items-center"
>
<div class="text-body-2 q-mb-xs flex items-center">
{{ $t('dataSum') }}
<q-btn
class="q-ml-xs"
@ -1182,17 +1219,8 @@ watch(inputSearchProductAndService, async () => {
/>
</div>
<transition
v-if="productMode === 'group' || productMode === 'type'"
name="slide"
>
<div
v-if="
(productMode === 'group' && !hideStat) ||
(productMode === 'type' && !hideStat)
"
class="scroll q-mb-md"
>
<transition name="slide">
<div v-if="!hideStat" class="scroll q-mb-md">
<div style="display: inline-block">
<StatCard
label-i18n
@ -1342,7 +1370,7 @@ watch(inputSearchProductAndService, async () => {
pathTypeName = v.name;
currentIdType = v.id;
productMode = 'service';
productAndServiceTab = 'all';
productAndServiceTab = 'service';
// await featchStatsService();
// await featchStatsProduct();
await fetchListOfProduct();
@ -1542,7 +1570,7 @@ watch(inputSearchProductAndService, async () => {
class="surface-2 col bordered rounded column"
>
<div
class="row justify-between items-center surface-1 q-px-md q-py-sm rounded surface-3 bordered"
class="row justify-between items-center q-px-md q-py-sm rounded surface-2"
style="z-index: 1"
>
<div>
@ -1562,7 +1590,7 @@ watch(inputSearchProductAndService, async () => {
</template>
</q-input>
</div>
<div class="row">
<div class="row" style="gap: var(--size-2)">
<q-btn
icon="mdi-tune-vertical-variant"
size="sm"
@ -1612,13 +1640,56 @@ watch(inputSearchProductAndService, async () => {
</q-list>
</q-menu>
</q-btn>
<q-btn-toggle
v-model="modeView"
id="btn-mode"
dense
class="no-shadow bordered rounded surface-1"
:toggle-color="$q.dark.isActive ? 'grey-9' : 'grey-2'"
size="xs"
:options="[
{ value: true, slot: 'folder' },
{ value: false, slot: 'list' },
]"
>
<template v-slot:folder>
<q-icon
name="mdi-view-grid-outline"
size="16px"
class="q-px-sm q-py-xs rounded"
:style="{
color: $q.dark.isActive
? modeView
? '#C9D3DB '
: '#787B7C'
: modeView
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
<template v-slot:list>
<q-icon
name="mdi-format-list-bulleted"
class="q-px-sm q-py-xs rounded"
size="16px"
:style="{
color: $q.dark.isActive
? modeView === false
? '#C9D3DB'
: '#787B7C'
: modeView === false
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
</div>
<div
v-if="
(productAndServiceTab === 'all' &&
productAndService?.length === 0) ||
(productAndServiceTab === 'product' && product?.length === 0) ||
(productAndServiceTab === 'service' && service?.length === 0)
"
@ -1632,63 +1703,14 @@ watch(inputSearchProductAndService, async () => {
<div
v-if="productAndService && productAndService.length > 0"
class="row flex col q-px-md"
class="row flex col"
>
<q-tabs
dense
v-model="productAndServiceTab"
class="col-12 q-mb-lg bordered-b"
class="col-12 bordered-b q-px-md"
align="left"
style="border-top-left-radius: var(--radius-2)"
>
<q-tab
name="all"
@click="
async () => {
currentPageServiceAndProduct = 1;
inputSearchProductAndService = '';
currentStatus = 'All';
pageSizeServiceAndProduct;
// await fetchListOfProductAndService();
flowStore.rotate();
}
"
>
<div
class="row"
:class="
productAndServiceTab === 'all'
? 'text-bold'
: 'app-text-muted'
"
>
{{ $t('all') }}
</div>
</q-tab>
<q-tab
name="product"
@click="
async () => {
currentPageServiceAndProduct = 1;
inputSearchProductAndService = '';
currentStatus = 'All';
// await fetchListOfProduct();
flowStore.rotate();
}
"
>
<div
class="row"
:class="
productAndServiceTab === 'product'
? 'text-bold'
: 'app-text-muted'
"
>
{{ $t('product') }}
</div>
</q-tab>
<q-tab
name="service"
@click="
@ -1712,67 +1734,394 @@ watch(inputSearchProductAndService, async () => {
{{ $t('service') }}
</div>
</q-tab>
</q-tabs>
<div class="col-12 row flex col q-col-gutter-sm scroll full-height">
<div
class="col-md-3 col-sm-6 col-12"
v-for="i in productAndServiceTab === 'all'
? productAndService
: productAndServiceTab === 'product'
? product
: service"
:key="i.id"
<q-tab
name="product"
@click="
async () => {
currentPageServiceAndProduct = 1;
inputSearchProductAndService = '';
currentStatus = 'All';
// await fetchListOfProduct();
flowStore.rotate();
}
"
>
<TotalProductCardComponent
:data="i"
:key="i.id"
:title="i.name"
:isDisabled="i.status === 'INACTIVE' ? true : false"
@toggleStatus="
() => {
if (i.type === 'product') {
toggleStatusProduct(i.id, i.status);
}
if (i.type === 'service') {
toggleStatusService(i.id, i.status);
}
}
<div
class="row"
:class="
productAndServiceTab === 'product'
? 'text-bold'
: 'app-text-muted'
"
@menuViewDetail="
async () => {
if (i.type === 'product') {
currentIdProduct = i.id;
assignFormDataProduct(i);
dialogProductEdit = true;
}
if (i.type === 'service') {
currentIdService = i.id;
infoServiceEdit = false;
assignFormDataProductService(i.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
>
{{ $t('product') }}
</div>
</q-tab>
</q-tabs>
<div class="col-12 flex col scroll full-height q-pa-md surface-1">
<div class="full-width">
<q-table
class="full-width"
flat
bordered
:rows-per-page-options="[0]"
:rows="{ product, service }[productAndServiceTab] || []"
:columns="
{
product: tbColumn.product,
service: tbColumn.service,
}[productAndServiceTab]
"
@menuEdit="
async () => {
if (i.type === 'product') {
currentIdProduct = i.id;
infoProductEdit = true;
assignFormDataProduct(i);
dialogProductEdit = true;
}
if (i.type === 'service') {
currentIdService = i.id;
infoServiceEdit = true;
assignFormDataProductService(i.id);
dialogServiceEdit = true;
}
:grid="modeView"
card-container-class="row q-col-gutter-md"
row-key="name"
hide-pagination
:visible-columns="
{
product: tbControl.product.fieldSelected,
service: tbControl.service.fieldSelected,
}[productAndServiceTab]
"
>
<template v-slot:header="props">
<q-tr class="surface-2" :props="props">
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
{{ $t(col.label) }}
</q-th>
<q-th auto-width />
</q-tr>
</template>
await fetchListOfOptionBranch();
}
"
/>
<template v-slot:body="props">
<q-tr
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
}"
:props="props"
>
<q-td
v-if="
{
product: tbControl.product.fieldSelected,
service: tbControl.service.fieldSelected,
}[productAndServiceTab].includes(
{ product: 'productName', service: 'serviceName' }[
productAndServiceTab
],
)
"
>
<div class="row items-center">
<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">
<q-icon
size="md"
style="scale: 0.8"
name="mdi-office-building-outline"
/>
</div>
</div>
<div class="col">
<div class="col">{{ props.row.name }}</div>
<div class="col app-text-muted">
{{ props.row.code }}
</div>
</div>
</div>
</q-td>
<q-td
v-if="
{
product: tbControl.product.fieldSelected,
service: tbControl.service.fieldSelected,
}[productAndServiceTab].includes(
{
product: 'productDetail',
service: 'serviceDetail',
}[productAndServiceTab],
)
"
>
{{ props.row.detail }}
</q-td>
<q-td
v-if="
{
product: tbControl.product.fieldSelected,
service: tbControl.service.fieldSelected,
}[productAndServiceTab].includes(
{
product: 'productProcessingTime',
service: 'serviceWorkTotal',
}[productAndServiceTab],
)
"
>
{{
{
product: props.row.remark,
service: props.row.work?.length,
}[productAndServiceTab]
}}
</q-td>
<q-td
v-if="
{
product: tbControl.product.fieldSelected,
service: tbControl.service.fieldSelected,
}[productAndServiceTab].includes(
{
product: 'productProcessingTime',
service: 'empty',
}[productAndServiceTab],
)
"
>
{{ props.row.process }}
</q-td>
<q-td>
<q-btn
icon="mdi-eye-outline"
size="sm"
dense
round
flat
@click.stop="
async () => {
if (props.row.type === 'product') {
currentIdProduct = props.row.id;
assignFormDataProduct(props.row);
dialogProductEdit = true;
}
if (props.row.type === 'service') {
currentIdService = props.row.id;
infoServiceEdit = false;
assignFormDataProductService(props.row.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
"
/>
<q-btn
icon="mdi-dots-vertical"
size="sm"
dense
round
flat
@click.stop
>
<q-menu class="bordered">
<q-list v-close-popup>
<q-item
:id="`view-detail-btn-${props.row.name}-view`"
@click.stop="
async () => {
if (props.row.type === 'product') {
currentIdProduct = props.row.id;
assignFormDataProduct(props.row);
dialogProductEdit = true;
}
if (props.row.type === 'service') {
currentIdService = props.row.id;
infoServiceEdit = false;
assignFormDataProductService(props.row.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
>
<q-icon
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-edit`"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
async () => {
if (props.row.type === 'product') {
currentIdProduct = props.row.id;
infoProductEdit = true;
assignFormDataProduct(props.row);
dialogProductEdit = true;
}
if (props.row.type === 'service') {
currentIdService = props.row.id;
infoServiceEdit = true;
assignFormDataProductService(props.row.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-delete`"
dense
:clickable="props.row.status === 'CREATED'"
class="row"
:class="{
'surface-3': props.row.status !== 'CREATED',
'app-text-muted':
props.row.status !== 'CREATED',
}"
style="white-space: nowrap"
@click=""
>
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
:class="{
'app-text-negative':
props.row.status === 'CREATED',
}"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${props.row.name}-status`"
dense
size="sm"
:label="
props.row.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
() => {
if (props.row.type === 'product') {
toggleStatusProduct(
props.row.id,
props.row.status,
);
}
if (props.row.type === 'service') {
toggleStatusService(
props.row.id,
props.row.status,
);
}
}
"
:model-value="
props.row.status === 'CREATED' ||
props.row.status === 'ACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:item="{ row }">
<div class="col-12 col-md-6">
<TotalProductCardComponent
:data="row"
:key="row.id"
:title="row.name"
:isDisabled="row.status === 'INACTIVE' ? true : false"
@toggleStatus="
() => {
if (row.type === 'product') {
toggleStatusProduct(row.id, row.status);
}
if (row.type === 'service') {
toggleStatusService(row.id, row.status);
}
}
"
@menuViewDetail="
async () => {
if (row.type === 'product') {
currentIdProduct = row.id;
assignFormDataProduct(row);
dialogProductEdit = true;
}
if (row.type === 'service') {
currentIdService = row.id;
infoServiceEdit = false;
assignFormDataProductService(row.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
"
@menuEdit="
async () => {
if (row.type === 'product') {
currentIdProduct = row.id;
infoProductEdit = true;
assignFormDataProduct(row);
dialogProductEdit = true;
}
if (row.type === 'service') {
currentIdService = row.id;
infoServiceEdit = true;
assignFormDataProductService(row.id);
dialogServiceEdit = true;
}
await fetchListOfOptionBranch();
}
"
/>
</div>
</template>
</q-table>
</div>
</div>
</div>
@ -1821,11 +2170,9 @@ watch(inputSearchProductAndService, async () => {
{{
$t('recordsPage', {
resultcurrentPage:
productAndServiceTab === 'all'
? productAndService.length
: productAndServiceTab === 'product'
? product?.length
: service?.length,
productAndServiceTab === 'product'
? product?.length
: service?.length,
total: total,
})
}}