302 lines
8.8 KiB
Vue
302 lines
8.8 KiB
Vue
|
|
<script lang="ts" setup>
|
||
|
|
import { QTableProps, QTableSlots } from 'quasar';
|
||
|
|
|
||
|
|
import QuotationCard from 'src/components/05_quotation/QuotationCard.vue';
|
||
|
|
import BadgeComponent from 'src/components/BadgeComponent.vue';
|
||
|
|
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||
|
|
|
||
|
|
import useOptionStore from 'src/stores/options';
|
||
|
|
import { dateFormatJS, dateFormat } from 'src/utils/datetime';
|
||
|
|
import { TaskOrder, TaskOrderStatus } from 'src/stores/task-order/types';
|
||
|
|
import { column } from './constants';
|
||
|
|
import { ref } from 'vue';
|
||
|
|
|
||
|
|
const selectedTask = defineModel<TaskOrder[]>('selectedTask', { default: [] });
|
||
|
|
const props = withDefaults(
|
||
|
|
defineProps<{
|
||
|
|
rows: QTableProps['rows'];
|
||
|
|
grid?: boolean;
|
||
|
|
visibleColumns?: string[];
|
||
|
|
selection?: 'single' | 'multiple' | 'none';
|
||
|
|
receive?: boolean;
|
||
|
|
}>(),
|
||
|
|
{
|
||
|
|
rows: () => [],
|
||
|
|
grid: false,
|
||
|
|
receive: false,
|
||
|
|
selection: 'none',
|
||
|
|
visibleColumns: () => [
|
||
|
|
'createdAt',
|
||
|
|
'order',
|
||
|
|
'taskName',
|
||
|
|
'issueBranch',
|
||
|
|
'institution',
|
||
|
|
'createdBy',
|
||
|
|
'contactTel',
|
||
|
|
'contactName',
|
||
|
|
'taskStatus',
|
||
|
|
],
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
const currentBtnOpen = ref<boolean[]>([]);
|
||
|
|
|
||
|
|
function taskOrderStatus(value: TaskOrderStatus, type: 'status' | 'color') {
|
||
|
|
const mappings: Record<string, Record<'status' | 'color', string>> = {
|
||
|
|
Pending: {
|
||
|
|
status: props.receive ? 'taskOrder.taskInCart' : 'taskOrder.title',
|
||
|
|
color: '--blue-6-hsl',
|
||
|
|
},
|
||
|
|
InProgress: {
|
||
|
|
status: 'taskOrder.inProgress',
|
||
|
|
color: props.receive ? '--blue-6-hsl' : '--orange-5-hsl',
|
||
|
|
},
|
||
|
|
Validate: {
|
||
|
|
status: 'taskOrder.inProgress',
|
||
|
|
color: props.receive ? '--blue-6-hsl' : '--orange-5-hsl',
|
||
|
|
},
|
||
|
|
Complete: {
|
||
|
|
status: props.receive ? 'taskOrder.sentTask' : 'taskOrder.goodReceipt',
|
||
|
|
color: props.receive ? '--blue-6-hsl' : '--green-8-hsl',
|
||
|
|
},
|
||
|
|
Accept: {
|
||
|
|
status: 'taskOrder.receiveTask',
|
||
|
|
color: '--blue-6-hsl',
|
||
|
|
},
|
||
|
|
Submit: {
|
||
|
|
status: 'taskOrder.sentTask',
|
||
|
|
color: '--blue-6-hsl',
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
return mappings[value]?.[type] || '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function getCreatedByName(
|
||
|
|
record: TaskOrder,
|
||
|
|
opts?: {
|
||
|
|
locale?: string;
|
||
|
|
},
|
||
|
|
) {
|
||
|
|
const createdBy = record.createdBy;
|
||
|
|
|
||
|
|
return (
|
||
|
|
{
|
||
|
|
['eng']: `${useOptionStore().mapOption(createdBy?.namePrefix) || ''} ${createdBy?.firstNameEN} ${createdBy?.lastNameEN}`,
|
||
|
|
['tha']: `${useOptionStore().mapOption(createdBy?.namePrefix) || ''} ${createdBy?.firstName} ${createdBy?.lastName}`,
|
||
|
|
}[opts?.locale || 'eng'] || '-'
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function openList(index: number, data: TaskOrder) {
|
||
|
|
if (!currentBtnOpen.value[index]) {
|
||
|
|
// currentBtnOpen.value.map((v, i) => {
|
||
|
|
// if (i !== index) {
|
||
|
|
// currentBtnOpen.value[i] = false;
|
||
|
|
// }
|
||
|
|
// });
|
||
|
|
emit('clickSubRow', index, data);
|
||
|
|
}
|
||
|
|
currentBtnOpen.value[index] = !currentBtnOpen.value[index];
|
||
|
|
}
|
||
|
|
|
||
|
|
const emit = defineEmits<{
|
||
|
|
(e: 'view', data: TaskOrder): void;
|
||
|
|
(e: 'clickSubRow', index: number, data: TaskOrder): void;
|
||
|
|
}>();
|
||
|
|
</script>
|
||
|
|
<template>
|
||
|
|
<q-table
|
||
|
|
v-bind="props"
|
||
|
|
:columns="column"
|
||
|
|
bordered
|
||
|
|
flat
|
||
|
|
hide-pagination
|
||
|
|
card-container-class="q-col-gutter-sm"
|
||
|
|
:rows-per-page-options="[0]"
|
||
|
|
class="full-width"
|
||
|
|
:no-data-label="$t('general.noDataTable')"
|
||
|
|
row-key="id"
|
||
|
|
v-model:selected="selectedTask"
|
||
|
|
hide-selected-banner
|
||
|
|
>
|
||
|
|
<template v-slot:header="props">
|
||
|
|
<q-tr
|
||
|
|
style="background-color: hsla(var(--info-bg) / 0.07)"
|
||
|
|
:props="props"
|
||
|
|
>
|
||
|
|
<q-th v-if="selection !== 'none'">
|
||
|
|
<q-checkbox v-model="props.selected" size="sm" />
|
||
|
|
</q-th>
|
||
|
|
<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: TaskOrder;
|
||
|
|
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
|
||
|
|
>
|
||
|
|
<q-tr class="text-center">
|
||
|
|
<q-td v-if="selection !== 'none'">
|
||
|
|
<q-checkbox v-model="props.selected" size="sm" />
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('order')">
|
||
|
|
{{ props.rowIndex + 1 }}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('taskName')" class="text-left">
|
||
|
|
<div>
|
||
|
|
{{ props.row.taskName || '-' }}
|
||
|
|
<q-tooltip :delay="300">
|
||
|
|
{{ props.row.taskName || '-' }}
|
||
|
|
</q-tooltip>
|
||
|
|
</div>
|
||
|
|
<div class="text-caption app-text-muted">
|
||
|
|
{{ props.row.code || '-' }}
|
||
|
|
</div>
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('issueBranch')">-</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('institution')">
|
||
|
|
{{
|
||
|
|
$i18n.locale === 'eng'
|
||
|
|
? props.row.institution.nameEN || '-'
|
||
|
|
: props.row.institution.name || '-'
|
||
|
|
}}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('createdAt')">
|
||
|
|
{{
|
||
|
|
dateFormatJS({
|
||
|
|
date: props.row.createdAt,
|
||
|
|
dayStyle: '2-digit',
|
||
|
|
monthStyle: '2-digit',
|
||
|
|
}) || '-'
|
||
|
|
}}
|
||
|
|
{{ dateFormat(props.row.createdAt, false, true) }}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('createdBy')" class="text-left">
|
||
|
|
{{ getCreatedByName(props.row, $i18n) }}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('contactTel')">
|
||
|
|
{{ props.row.contactTel || '-' }}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('contactName')" class="text-left">
|
||
|
|
{{ props.row.contactName || '-' }}
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="visibleColumns.includes('taskStatus')">
|
||
|
|
<BadgeComponent
|
||
|
|
hide-icon
|
||
|
|
:hsla-color="taskOrderStatus(props.row.taskOrderStatus, 'color')"
|
||
|
|
:title="$t(taskOrderStatus(props.row.taskOrderStatus, 'status'))"
|
||
|
|
/>
|
||
|
|
</q-td>
|
||
|
|
<q-td v-if="selection === 'none'">
|
||
|
|
<q-btn
|
||
|
|
:id="`btn-eye-${props.row.taskName}`"
|
||
|
|
icon="mdi-eye-outline"
|
||
|
|
size="sm"
|
||
|
|
dense
|
||
|
|
round
|
||
|
|
flat
|
||
|
|
@click.stop="$emit('view', props.row)"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<KebabAction
|
||
|
|
v-if="false"
|
||
|
|
:idName="`btn-kebab-${props.row.taskName}`"
|
||
|
|
status="'ACTIVE'"
|
||
|
|
hide-toggle
|
||
|
|
:hide-edit="true"
|
||
|
|
@view="$emit('view', props.row)"
|
||
|
|
/>
|
||
|
|
</q-td>
|
||
|
|
<q-td v-else>
|
||
|
|
<q-btn
|
||
|
|
dense
|
||
|
|
flat
|
||
|
|
class="rounded"
|
||
|
|
@click.stop="
|
||
|
|
() => {
|
||
|
|
openList(props.rowIndex, props.row);
|
||
|
|
}
|
||
|
|
"
|
||
|
|
>
|
||
|
|
<div class="row items-center no-wrap">
|
||
|
|
<q-icon name="mdi-account-group-outline" />
|
||
|
|
<q-icon
|
||
|
|
class="btn-arrow-right"
|
||
|
|
:class="{
|
||
|
|
active: currentBtnOpen[props.rowIndex],
|
||
|
|
}"
|
||
|
|
size="xs"
|
||
|
|
:name="`mdi-chevron-${currentBtnOpen[props.rowIndex] ? 'down' : 'up'}`"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</q-btn>
|
||
|
|
</q-td>
|
||
|
|
</q-tr>
|
||
|
|
|
||
|
|
<q-tr v-show="currentBtnOpen[props.rowIndex]" :props="props">
|
||
|
|
<q-td colspan="100%" style="padding: 16px">
|
||
|
|
<slot name="subRow" :props="props"></slot>
|
||
|
|
</q-td>
|
||
|
|
</q-tr>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<template v-slot:item="props">
|
||
|
|
<div class="col-md-4 col-sm-6 col-12">
|
||
|
|
<!-- TODO: status -->
|
||
|
|
<QuotationCard
|
||
|
|
:status="$t(taskOrderStatus(props.row.taskOrderStatus, 'status'))"
|
||
|
|
:badge-color="taskOrderStatus(props.row.taskOrderStatus, 'color')"
|
||
|
|
hide-action
|
||
|
|
hidePreview
|
||
|
|
:code="props.row.code"
|
||
|
|
:title="props.row.taskName"
|
||
|
|
:custom-data="[
|
||
|
|
{
|
||
|
|
label: $t('taskOrder.issueBranch'),
|
||
|
|
value: props.row.issueBranch,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: $t('general.agencies'),
|
||
|
|
value:
|
||
|
|
$i18n.locale === 'eng'
|
||
|
|
? props.row.institution.nameEN
|
||
|
|
: props.row.institution.name,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: $t('taskOrder.issueDate'),
|
||
|
|
value: `${dateFormatJS({
|
||
|
|
date: props.row.createdAt,
|
||
|
|
dayStyle: '2-digit',
|
||
|
|
monthStyle: '2-digit',
|
||
|
|
})} ${dateFormat(props.row.createdAt, false, true)}`,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: $t('taskOrder.madeBy'),
|
||
|
|
value: getCreatedByName(props.row, $i18n),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: $t('general.telephone'),
|
||
|
|
value: props.row.contactTel,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: $t('taskOrder.contactName'),
|
||
|
|
value: props.row.contactName,
|
||
|
|
},
|
||
|
|
]"
|
||
|
|
@view="$emit('view', props.row)"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
</q-table>
|
||
|
|
</template>
|
||
|
|
<style scoped>
|
||
|
|
:deep(.q-table tbody td:after) {
|
||
|
|
background: transparent;
|
||
|
|
}
|
||
|
|
</style>
|