refactor: show mode list

This commit is contained in:
Thanaphon Frappet 2025-01-27 15:20:02 +07:00
parent 18d0aca1de
commit a4bc6e4884
2 changed files with 118 additions and 169 deletions

View file

@ -23,6 +23,8 @@ import PersonCard from 'src/components/shared/PersonCard.vue';
import { QuotationFull } from 'src/stores/quotations/types'; import { QuotationFull } from 'src/stores/quotations/types';
import { Lang } from 'src/utils/ui'; import { Lang } from 'src/utils/ui';
import NoData from 'src/components/NoData.vue'; import NoData from 'src/components/NoData.vue';
import TableWorker from 'src/components/shared/table/TableWorker.vue';
import ToggleView from 'src/components/shared/ToggleView.vue';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
@ -104,6 +106,7 @@ const employeeStore = useEmployeeStore();
const quotationStore = useQuotationStore(); const quotationStore = useQuotationStore();
const open = defineModel<boolean>('open', { default: false }); const open = defineModel<boolean>('open', { default: false });
const viewMode = ref<boolean>(false);
const workerSelected = ref<Employee[]>([]); const workerSelected = ref<Employee[]>([]);
const workerList = ref<Employee[]>([]); const workerList = ref<Employee[]>([]);
const importWorkerCriteria = ref<{ const importWorkerCriteria = ref<{
@ -314,6 +317,8 @@ watch(() => state.search, getWorkerList);
<q-tab-panel class="q-pa-none" :name="1"> <q-tab-panel class="q-pa-none" :name="1">
<div class="column q-pa-md full-height"> <div class="column q-pa-md full-height">
<section class="row justify-end q-mb-md"> <section class="row justify-end q-mb-md">
<ToggleView v-model="viewMode" class="q-mr-sm" />
<q-input <q-input
for="input-search" for="input-search"
outlined outlined
@ -340,55 +345,59 @@ watch(() => state.search, getWorkerList);
> >
<NoData :not-found="!!state.search" /> <NoData :not-found="!!state.search" />
</div> </div>
<div
:key="emp.id" <TableWorker
v-for="(emp, index) in workerList.map((data) => ({ v-model:selected="workerSelected"
...data, :rows="workerList"
_selectedIndex: selectedIndex(data), :disabledWorkerId
}))" :grid="viewMode"
class="col-md-2 col-sm-6 col-12"
> >
<button <template #grid="{ item: emp, index }">
class="selectable-item full-width" <div :key="emp.id" class="col-md-2 col-sm-6 col-12">
:class="{ <button
['selectable-item__selected']: emp._selectedIndex !== -1, class="selectable-item full-width"
['selectable-item__disabled']: disabledWorkerId?.some( :class="{
(id) => id === emp.id, ['selectable-item__selected']:
), emp._selectedIndex !== -1,
}" ['selectable-item__disabled']: disabledWorkerId?.some(
@click="toggleSelect(emp)" (id) => id === emp.id,
> ),
<span class="selectable-item__pos"> }"
{{ emp._selectedIndex + 1 }} @click="toggleSelect(emp)"
</span> >
<PersonCard <span class="selectable-item__pos">
no-action {{ (emp._selectedIndex || 0) + 1 }}
class="full-width" </span>
:prefix-id="'employee-' + index" <PersonCard
:data="{ no-action
name: class="full-width"
locale === Lang.English :prefix-id="'employee-' + index"
? `${emp.firstNameEN} ${emp.lastNameEN}` :data="{
: `${emp.firstName} ${emp.lastName}`, name:
code: emp.employeePassport?.at(0)?.number || '-', locale === Lang.English
female: emp.gender === 'female', ? `${emp.firstNameEN} ${emp.lastNameEN}`
male: emp.gender === 'male', : `${emp.firstName} ${emp.lastName}`,
img: getEmployeeImageUrl(emp), code: emp.employeePassport?.at(0)?.number || '-',
fallbackImg: `/images/employee-avatar-${emp.gender}.png`, female: emp.gender === 'female',
detail: [ male: emp.gender === 'male',
{ img: getEmployeeImageUrl(emp),
icon: 'mdi-passport', fallbackImg: `/images/employee-avatar-${emp.gender}.png`,
value: optionStore.mapOption(emp.nationality), detail: [
}, {
{ icon: 'mdi-passport',
icon: 'mdi-clock-outline', value: optionStore.mapOption(emp.nationality),
value: calculateAge(emp.dateOfBirth), },
}, {
], icon: 'mdi-clock-outline',
}" value: calculateAge(emp.dateOfBirth),
/> },
</button> ],
</div> }"
/>
</button>
</div>
</template>
</TableWorker>
</section> </section>
</div> </div>
</div> </div>
@ -457,86 +466,15 @@ watch(() => state.search, getWorkerList);
</template> </template>
<div class="q-pa-md surface-1"> <div class="q-pa-md surface-1">
<q-table <TableWorker
v-model:selected="productWorkerMap[id]" v-model:selected="productWorkerMap[id]"
:rows-per-page-options="[0]"
:rows=" :rows="
workerSelected.map((data, i) => ({ workerSelected.map((data, i) => ({
...data, ...data,
_index: i, _index: i,
})) }))
" "
:columns />
hide-bottom
bordered
flat
hide-pagination
selection="multiple"
card-container-class="q-col-gutter-sm"
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 columns"
:key="col.name"
:props="props"
>
<template v-if="!col.name.startsWith('#')">
{{ $t(col.label) }}
</template>
<template v-if="col.name === '#check'">
<q-checkbox v-model="props.selected" size="sm" />
</template>
</q-th>
</q-tr>
</template>
<template
v-slot:body="props: {
row: Employee & { _index: number };
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
>
<q-tr
:class="{ dark: $q.dark.isActive }"
class="text-center"
>
<q-td
v-for="col in columns"
:align="col.align"
:key="col.name"
>
<!-- NOTE: custom column will starts with # -->
<template v-if="!col.name.startsWith('#')">
<q-avatar
v-if="col.name === 'employeeName'"
class="q-mr-sm"
size="md"
>
<q-img
:src="getEmployeeImageUrl(props.row)"
:ratio="1"
class="text-center"
/>
</q-avatar>
<span>
{{
typeof col.field === 'string'
? props.row[col.field as keyof Employee]
: col.field(props.row)
}}
</span>
</template>
<template v-if="col.name === '#check'">
<q-checkbox v-model="props.selected" size="sm" />
</template>
</q-td>
</q-tr>
</template>
</q-table>
</div> </div>
</q-expansion-item> </q-expansion-item>
</div> </div>

View file

@ -46,6 +46,8 @@ import {
columnsAttachment, columnsAttachment,
} from 'src/pages/03_customer-management/constant'; } from 'src/pages/03_customer-management/constant';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import ToggleView from 'src/components/shared/ToggleView.vue';
import TableWorker from 'src/components/shared/table/TableWorker.vue';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
@ -55,6 +57,8 @@ const quotationForm = useQuotationForm();
const { locale } = useI18n(); const { locale } = useI18n();
const ocrStore = useOcrStore(); const ocrStore = useOcrStore();
const viewMode = ref<boolean>(false);
const { state: employeeFormState, currentFromDataEmployee } = const { state: employeeFormState, currentFromDataEmployee } =
storeToRefs(employeeFormStore); storeToRefs(employeeFormStore);
@ -329,14 +333,15 @@ watch(() => state.search, getWorkerList);
<div class="column full-height no-wrap surface-2"> <div class="column full-height no-wrap surface-2">
<section class="row q-mb-md"> <section class="row q-mb-md">
<header <header
class="row items-center q-py-sm q-px-md justify-between full-width surface-3 bordered-b no-wrap" class="row items-center q-py-sm q-px-md justify-end full-width surface-3 bordered-b no-wrap"
> >
<ToggleView v-model="viewMode" class="q-mr-sm full-height" />
<q-input <q-input
for="input-search" for="input-search"
outlined outlined
dense dense
:label="$t('general.search')" :label="$t('general.search')"
class="q-mr-md col-md-4"
:bg-color="$q.dark.isActive ? 'dark' : 'white'" :bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="state.search" v-model="state.search"
debounce="500" debounce="500"
@ -447,7 +452,7 @@ watch(() => state.search, getWorkerList);
<div class="full-width q-pt-md"> <div class="full-width q-pt-md">
<section <section
:class="{ ['items-center']: workerList.length === 0 }" :class="{ ['items-center']: workerList.length === 0 }"
class="row q-col-gutter-md scroll" class="row scroll"
> >
<div <div
style="display: inline-block; margin-inline: auto" style="display: inline-block; margin-inline: auto"
@ -455,52 +460,58 @@ watch(() => state.search, getWorkerList);
> >
<NoData :not-found="!!state.search" /> <NoData :not-found="!!state.search" />
</div> </div>
<div <TableWorker
:key="emp.id" v-model:selected="workerSelected"
v-for="(emp, index) in workerList.map((data) => ({ :rows="workerList"
...data, :disabledWorkerId
_selectedIndex: selectedIndex(data), :grid="viewMode"
}))"
class="col-md-2 col-sm-6 col-12"
> >
<button <template #grid="{ item: emp, index }">
class="selectable-item full-width" <div :key="emp.id" class="col-md-2 col-sm-6 col-12">
:class="{ <button
['selectable-item__selected']: emp._selectedIndex !== -1, class="selectable-item full-width"
['selectable-item__disabled']: disabledWorkerId?.some( :class="{
(id) => id === emp.id, ['selectable-item__selected']:
), emp._selectedIndex !== -1,
}" ['selectable-item__disabled']: disabledWorkerId?.some(
@click="toggleSelect(emp)" (id) => id === emp.id,
> ),
<PersonCard }"
no-action @click="toggleSelect(emp)"
class="full-width" >
:prefix-id="'employee-' + index" <span class="selectable-item__pos">
:data="{ {{ (emp._selectedIndex || 0) + 1 }}
name: </span>
locale === Lang.English <PersonCard
? `${emp.firstNameEN} ${emp.lastNameEN}` no-action
: `${emp.firstName} ${emp.lastName}`, class="full-width"
code: emp.employeePassport?.at(0)?.number || '-', :prefix-id="'employee-' + index"
female: emp.gender === 'female', :data="{
male: emp.gender === 'male', name:
img: getEmployeeImageUrl(emp), locale === Lang.English
fallbackImg: `/images/employee-avatar-${emp.gender}.png`, ? `${emp.firstNameEN} ${emp.lastNameEN}`
detail: [ : `${emp.firstName} ${emp.lastName}`,
{ code: emp.employeePassport?.at(0)?.number || '-',
icon: 'mdi-passport', female: emp.gender === 'female',
value: optionStore.mapOption(emp.nationality), male: emp.gender === 'male',
}, img: getEmployeeImageUrl(emp),
{ fallbackImg: `/images/employee-avatar-${emp.gender}.png`,
icon: 'mdi-clock-outline', detail: [
value: calculateAge(emp.dateOfBirth), {
}, icon: 'mdi-passport',
], value: optionStore.mapOption(emp.nationality),
}" },
/> {
</button> icon: 'mdi-clock-outline',
</div> value: calculateAge(emp.dateOfBirth),
},
],
}"
/>
</button>
</div>
</template>
</TableWorker>
</section> </section>
</div> </div>
</q-expansion-item> </q-expansion-item>