jws-frontend/src/pages/08_request-list/TableRequestList.vue
2024-12-25 15:04:01 +07:00

273 lines
7.5 KiB
Vue

<script setup lang="ts">
import { QTable, QTableProps, QTableSlots } from 'quasar';
import QuotationCard from 'src/components/05_quotation/QuotationCard.vue';
import BadgeComponent from 'src/components/BadgeComponent.vue';
import AvatarGroup from 'src/components/shared/AvatarGroup.vue';
import { RequestData } from 'src/stores/request-list/types';
import { RequestDataStatus } from 'src/stores/request-list/types';
import useOptionStore from 'src/stores/options';
import KebabAction from 'src/components/shared/KebabAction.vue';
const props = withDefaults(
defineProps<{
rows: QTableProps['rows'];
columns: QTableProps['columns'];
grid?: boolean;
visibleColumns?: string[];
}>(),
{
row: () => [],
column: () => [],
grid: false,
visibleColumns: () => [],
},
);
defineEmits<{
(e: 'view', data: RequestData): void;
(e: 'delete', data: RequestData): void;
}>();
function getCustomerName(
record: RequestData,
opts?: {
locale?: string;
noCode?: boolean;
},
) {
const customer = record.quotation.customerBranch;
return (
{
['CORP']: {
['eng']: customer.registerNameEN,
['tha']: customer.registerName,
}[opts?.locale || 'eng'],
['PERS']:
{
['eng']: `${useOptionStore().mapOption(customer?.namePrefix || '')} ${customer?.firstNameEN} ${customer?.lastNameEN}`,
['tha']: `${useOptionStore().mapOption(customer?.namePrefix || '')} ${customer?.firstName} ${customer?.lastName}`,
}[opts?.locale || 'eng'] || '-',
}[customer.customer.customerType] +
(opts?.noCode ? '' : ' ' + `(${customer.code})`)
);
}
function getEmployeeName(
record: RequestData,
opts?: {
locale?: string;
},
) {
const employee = record.employee;
return (
{
['eng']: `${useOptionStore().mapOption(employee?.namePrefix || '')} ${employee?.firstNameEN} ${employee?.lastNameEN}`,
['tha']: `${useOptionStore().mapOption(employee?.namePrefix || '')} ${employee?.firstName} ${employee?.lastName}`,
}[opts?.locale || 'eng'] || '-'
);
}
</script>
<template>
<q-table
v-bind="props"
bordered
flat
hide-pagination
card-container-class="q-col-gutter-sm"
:rows-per-page-options="[0]"
class="full-width"
>
<template v-slot:header="props">
<q-tr
style="background-color: hsla(var(--info-bg) / 0.07)"
:props="props"
>
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label && $t(col.label) }}
</q-th>
<q-th></q-th>
</q-tr>
</template>
<template
v-slot:body="props: {
row: RequestData;
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
>
<q-tr
:class="{ urgent: props.row.quotation.urgent, dark: $q.dark.isActive }"
class="text-center"
>
<q-td v-if="visibleColumns.includes('order')">
{{ props.rowIndex + 1 }}
</q-td>
<q-td v-if="visibleColumns.includes('requestList')" class="text-left">
{{ props.row.quotation.workName || '-' }}
<div class="text-caption app-text-muted">
{{ props.row.code || '-' }}
</div>
</q-td>
<q-td v-if="visibleColumns.includes('employer')" class="text-left">
{{
getCustomerName(props.row, {
noCode: true,
locale: $i18n.locale,
}) || '-'
}}
</q-td>
<q-td v-if="visibleColumns.includes('employee')" class="text-left">
{{ getEmployeeName(props.row, { locale: $i18n.locale }) || '-' }}
</q-td>
<q-td v-if="visibleColumns.includes('quotationCode')">
{{ props.row.quotation.code || '-' }}
</q-td>
<q-td v-if="visibleColumns.includes('responsiblePerson')">
{{ '-' }}
</q-td>
<q-td v-if="visibleColumns.includes('status')">
<BadgeComponent
:hsla-color="
{
[RequestDataStatus.Pending]: '--orange-5-hsl',
[RequestDataStatus.InProgress]: '--blue-6-hsl',
[RequestDataStatus.Completed]: '--green-8-hsl',
[RequestDataStatus.Canceled]: '--red-5-hsl',
}[props.row.requestDataStatus]
"
:title="
$t(`requestList.status.${props.row.requestDataStatus}`) || '-'
"
/>
</q-td>
<q-td class="text-right">
<q-btn
:id="`btn-eye-${props.row.quotation.workName}`"
icon="mdi-eye-outline"
size="sm"
dense
round
flat
@click.stop="$emit('view', props.row)"
/>
<KebabAction
hide-edit
hide-toggle
hide-view
hide-delete
:disable-cancel="
props.row.requestDataStatus === RequestDataStatus.Canceled
"
@cancel="$emit('delete', props.row)"
/>
</q-td>
</q-tr>
</template>
<template
v-slot:item="props: {
row: RequestData;
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
>
<div class="col-md-4 col-sm-6 col-12">
<QuotationCard
hide-preview
hide-kebab-view
hide-kebab-edit
:badge-color="
props.row.requestDataStatus === RequestDataStatus.Pending
? '--orange-5-hsl'
: props.row.requestDataStatus === RequestDataStatus.InProgress
? '--blue-6-hsl'
: props.row.requestDataStatus === RequestDataStatus.Completed
? '--green-8-hsl'
: '--orange-5-hsl'
"
:urgent="props.row.quotation.urgent"
:code="props.row.code"
:title="props.row.quotation.workName"
:status="$t(`requestList.status.${props.row.requestDataStatus}`)"
:custom-data="[
{
label: $t('customer.employer'),
value:
getCustomerName(props.row, {
noCode: true,
locale: $i18n.locale,
}) || '-',
},
{
label: $t('customer.employee'),
value:
getEmployeeName(props.row, { locale: $i18n.locale }) || '-',
},
{
label: $t('requestList.quotationCode'),
value: props.row.quotation.code || '-',
},
{
label: $t('flow.responsiblePerson'),
value: '',
slotName: 'responsiblePerson',
},
]"
@view="$emit('view', props.row)"
>
<template v-slot:responsiblePerson="{ props }">
<div class="col-4 app-text-muted q-pr-sm self-center">
{{ props.label }}
</div>
<div class="col-8">
<AvatarGroup />
</div>
</template>
</QuotationCard>
</div>
</template>
</q-table>
</template>
<style scoped>
:deep(tr:nth-child(2n)) {
background: #f9fafc;
&.dark {
background: hsl(var(--gray-11-hsl) / 0.2);
}
}
.q-table tr.urgent {
background: hsla(var(--red-6-hsl) / 0.03);
}
.q-table tr.urgent td:first-child {
&::after {
content: ' ';
display: block;
position: absolute;
left: 0;
top: 15%;
bottom: 15%;
background: var(--red-8);
width: 4px;
border-radius: 99rem;
animation: blink 1s infinite;
}
}
@keyframes blink {
0% {
background: var(--red-8);
}
50% {
background: var(--red-3);
}
100% {
background: var(--red-8);
}
}
</style>