update selected and load data
This commit is contained in:
parent
263e122b60
commit
bebf684069
2 changed files with 157 additions and 53 deletions
|
|
@ -125,7 +125,7 @@ export const useChangeRoundDataStore = defineStore(
|
||||||
|
|
||||||
async function fetchDataForCardId(dataDetail: any, type?: string) {
|
async function fetchDataForCardId(dataDetail: any, type?: string) {
|
||||||
if (dataDetail) {
|
if (dataDetail) {
|
||||||
showLoader();
|
// showLoader();
|
||||||
const url =
|
const url =
|
||||||
type && type == "emp"
|
type && type == "emp"
|
||||||
? config.API.leaveSearchEMP()
|
? config.API.leaveSearchEMP()
|
||||||
|
|
@ -170,7 +170,7 @@ export const useChangeRoundDataStore = defineStore(
|
||||||
console.log(e);
|
console.log(e);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
hideLoader();
|
// hideLoader();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, reactive, onMounted } from "vue";
|
import { ref, watch, reactive, onMounted, nextTick } from "vue";
|
||||||
import { useQuasar } from "quasar";
|
import { useQuasar } from "quasar";
|
||||||
|
|
||||||
import http from "@/plugins/http";
|
import http from "@/plugins/http";
|
||||||
|
|
@ -18,13 +18,7 @@ import Dialogform from "@/modules/09_leave/components/03_ChangeRound/DialogForm.
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const mixin = useCounterMixin();
|
const mixin = useCounterMixin();
|
||||||
|
|
||||||
const {
|
const { showLoader, hideLoader, success, messageError, dialogConfirm } = mixin;
|
||||||
showLoader,
|
|
||||||
hideLoader,
|
|
||||||
success,
|
|
||||||
messageError,
|
|
||||||
dialogConfirm,
|
|
||||||
} = mixin;
|
|
||||||
const dataStore = useChangeRoundDataStore();
|
const dataStore = useChangeRoundDataStore();
|
||||||
const { fetchStructureTree } = useStructureTree();
|
const { fetchStructureTree } = useStructureTree();
|
||||||
|
|
||||||
|
|
@ -48,7 +42,7 @@ const formData = reactive<DataPost>({
|
||||||
|
|
||||||
const pagination = ref({
|
const pagination = ref({
|
||||||
page: 1,
|
page: 1,
|
||||||
rowsPerPage: formData.pageSize,
|
rowsPerPage: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** โครงสร้างข้อมูลต้นไม้ขององค์กร **/
|
/** โครงสร้างข้อมูลต้นไม้ขององค์กร **/
|
||||||
|
|
@ -59,6 +53,19 @@ const filter = ref<string>("");
|
||||||
const selected = ref<any[]>([]);
|
const selected = ref<any[]>([]);
|
||||||
const isMultiple = ref<boolean>(false);
|
const isMultiple = ref<boolean>(false);
|
||||||
|
|
||||||
|
/** client-side data & batch loading **/
|
||||||
|
const allRows = ref<any[]>([]);
|
||||||
|
const isLoadingAll = ref<boolean>(false);
|
||||||
|
const loadAllProgress = ref<number>(0);
|
||||||
|
const totalToLoad = ref<number | null>(null);
|
||||||
|
const BATCH_SIZE = 250;
|
||||||
|
|
||||||
|
function waitForUi() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** function fetch ข้อมูลของ Tree*/
|
/** function fetch ข้อมูลของ Tree*/
|
||||||
async function fetchDataTree() {
|
async function fetchDataTree() {
|
||||||
nodeTree.value = await fetchStructureTree(route.meta.Key as string, true);
|
nodeTree.value = await fetchStructureTree(route.meta.Key as string, true);
|
||||||
|
|
@ -135,27 +142,75 @@ function save() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Function โหลดข้อมูลทั้งหมดแบบ batch แล้วให้ QTable ทำ pagination เอง */
|
||||||
* function updatePagination
|
async function fetchAllData() {
|
||||||
* @param newPagination ข้อมูล Pagination ใหม่
|
isLoadingAll.value = true;
|
||||||
*/
|
allRows.value = [];
|
||||||
function updatePagination(newPagination: any) {
|
loadAllProgress.value = 0;
|
||||||
formData.pageSize =
|
totalToLoad.value = null;
|
||||||
newPagination.rowsPerPage === 0 ? 3000 : newPagination.rowsPerPage;
|
selected.value = [];
|
||||||
|
|
||||||
|
// ให้ UI แสดงสถานะกำลังโหลดทันที ก่อนรอผล API แรก
|
||||||
|
await nextTick();
|
||||||
|
await waitForUi();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await dataStore.fetchDataForCardId({
|
||||||
|
...formData,
|
||||||
|
page: 1,
|
||||||
|
pageSize: BATCH_SIZE,
|
||||||
|
});
|
||||||
|
allRows.value = dataStore.rows.slice();
|
||||||
|
|
||||||
|
const total = dataStore.totalListMain;
|
||||||
|
totalToLoad.value = total;
|
||||||
|
const totalPages = Math.ceil(total / BATCH_SIZE);
|
||||||
|
loadAllProgress.value =
|
||||||
|
totalPages <= 1 ? 100 : Math.round(100 / totalPages);
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
for (let page = 2; page <= totalPages; page++) {
|
||||||
|
await dataStore.fetchDataForCardId({
|
||||||
|
...formData,
|
||||||
|
page,
|
||||||
|
pageSize: BATCH_SIZE,
|
||||||
|
});
|
||||||
|
allRows.value.push(...dataStore.rows);
|
||||||
|
loadAllProgress.value = Math.round((page / totalPages) * 100);
|
||||||
|
await nextTick();
|
||||||
|
await waitForUi();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isLoadingAll.value = false;
|
||||||
|
totalToLoad.value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Function ค้นหาข้อมูล */
|
/** Function ค้นหาข้อมูล */
|
||||||
async function searchData() {
|
async function searchData() {
|
||||||
await dataStore.fetchDataForCardId(formData);
|
await fetchAllData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitSearchByEnter() {
|
||||||
|
if (isLoadingAll.value) return;
|
||||||
|
if (!checkPermission(route)?.attrIsGet) return;
|
||||||
|
formData.page = 1;
|
||||||
|
searchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function เลือกทั้งหมด */
|
||||||
|
function selectAllRows() {
|
||||||
|
selected.value = [...allRows.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelectedOrgTree(data: any) {
|
function onSelectedOrgTree(data: any) {
|
||||||
|
if (isLoadingAll.value) return;
|
||||||
selected.value = [];
|
selected.value = [];
|
||||||
|
allRows.value = [];
|
||||||
orgTreeId.value = data.orgTreeId;
|
orgTreeId.value = data.orgTreeId;
|
||||||
formData.selectedNodeId = data.orgTreeDnaId;
|
formData.selectedNodeId = data.orgTreeDnaId;
|
||||||
formData.selectedNode = data.orgLevel;
|
formData.selectedNode = data.orgLevel;
|
||||||
formData.page = 1;
|
formData.page = 1;
|
||||||
searchData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSelectMultiple() {
|
function handleSelectMultiple() {
|
||||||
|
|
@ -171,14 +226,14 @@ function resetSelected() {
|
||||||
watch(
|
watch(
|
||||||
() => formData.pageSize,
|
() => formData.pageSize,
|
||||||
() => {
|
() => {
|
||||||
formData.page = 1;
|
// pageSize ถูกควบคุมโดย QTable (client-side) ไม่ต้อง fetch API ใหม่
|
||||||
searchData();
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchDataTree();
|
fetchDataTree();
|
||||||
dataStore.rows = [];
|
dataStore.rows = [];
|
||||||
|
allRows.value = [];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -238,7 +293,6 @@ onMounted(() => {
|
||||||
<q-card-section
|
<q-card-section
|
||||||
class="col-lg-9 col-md-8 col-xs-12 q-gutter-sm scroll"
|
class="col-lg-9 col-md-8 col-xs-12 q-gutter-sm scroll"
|
||||||
style="height: 80vh"
|
style="height: 80vh"
|
||||||
v-if="orgTreeId"
|
|
||||||
>
|
>
|
||||||
<div class="row col-xs-12 col-sm-9">
|
<div class="row col-xs-12 col-sm-9">
|
||||||
<q-card flat bordered class="bg-grey-2 col-12 bg-white q-pa-lg">
|
<q-card flat bordered class="bg-grey-2 col-12 bg-white q-pa-lg">
|
||||||
|
|
@ -247,7 +301,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-between q-gutter-y-sm">
|
<div class="row justify-between q-gutter-y-sm">
|
||||||
<q-input
|
<q-input
|
||||||
:readonly="!checkPermission($route)?.attrIsGet"
|
:readonly="!checkPermission($route)?.attrIsGet || isLoadingAll"
|
||||||
v-model="formData.cardId"
|
v-model="formData.cardId"
|
||||||
outlined
|
outlined
|
||||||
label="เลขประจำตัวประชาชน"
|
label="เลขประจำตัวประชาชน"
|
||||||
|
|
@ -255,28 +309,32 @@ onMounted(() => {
|
||||||
dense
|
dense
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
maxlength="13"
|
maxlength="13"
|
||||||
|
@keyup.enter="submitSearchByEnter"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<q-input
|
||||||
:readonly="!checkPermission($route)?.attrIsGet"
|
:readonly="!checkPermission($route)?.attrIsGet || isLoadingAll"
|
||||||
v-model="formData.firstName"
|
v-model="formData.firstName"
|
||||||
outlined
|
outlined
|
||||||
label="ชื่อ"
|
label="ชื่อ"
|
||||||
class="col-5 col-md-3 bg-white inputgreen"
|
class="col-5 col-md-3 bg-white inputgreen"
|
||||||
dense
|
dense
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
|
@keyup.enter="submitSearchByEnter"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<q-input
|
||||||
:readonly="!checkPermission($route)?.attrIsGet"
|
:readonly="!checkPermission($route)?.attrIsGet || isLoadingAll"
|
||||||
v-model="formData.lastName"
|
v-model="formData.lastName"
|
||||||
outlined
|
outlined
|
||||||
label="นามสกุล"
|
label="นามสกุล"
|
||||||
class="col-6 col-md-3 bg-white inputgreen"
|
class="col-6 col-md-3 bg-white inputgreen"
|
||||||
dense
|
dense
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
|
@keyup.enter="submitSearchByEnter"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="checkPermission($route)?.attrIsGet"
|
v-if="checkPermission($route)?.attrIsGet"
|
||||||
@click="(formData.page = 1), searchData()"
|
@click="(formData.page = 1), searchData()"
|
||||||
|
:disable="isLoadingAll"
|
||||||
for="#search"
|
for="#search"
|
||||||
dense
|
dense
|
||||||
unelevated
|
unelevated
|
||||||
|
|
@ -289,7 +347,11 @@ onMounted(() => {
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="dataStore.rows.length === 0 && dataStore.checkCilck === true"
|
v-if="
|
||||||
|
allRows.length === 0 &&
|
||||||
|
dataStore.checkCilck === true &&
|
||||||
|
!isLoadingAll
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<q-card
|
<q-card
|
||||||
flat
|
flat
|
||||||
|
|
@ -298,30 +360,81 @@ onMounted(() => {
|
||||||
>ไม่พบข้อมูล</q-card
|
>ไม่พบข้อมูล</q-card
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="dataStore.rows.length !== 0" class="col-12">
|
<div v-if="allRows.length !== 0 || isLoadingAll" class="col-12">
|
||||||
|
<q-banner
|
||||||
|
v-if="isLoadingAll"
|
||||||
|
rounded
|
||||||
|
class="bg-blue-1 text-primary q-mb-sm"
|
||||||
|
>
|
||||||
|
<div class="row items-center q-gutter-sm">
|
||||||
|
<q-spinner color="primary" size="22px" />
|
||||||
|
<div v-if="totalToLoad === null || totalToLoad <= 500">
|
||||||
|
กำลังค้นหาข้อมูล กรุณารอสักครู่
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
กำลังโหลดข้อมูลจำนวนมาก กรุณารอสักครู่
|
||||||
|
<div class="text-caption text-grey-7">
|
||||||
|
ระบบกำลังดึงข้อมูลทั้งหมด
|
||||||
|
{{ totalToLoad.toLocaleString() }} รายการ
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-banner>
|
||||||
|
<q-linear-progress
|
||||||
|
v-if="isLoadingAll && totalToLoad === null"
|
||||||
|
indeterminate
|
||||||
|
color="primary"
|
||||||
|
class="q-mb-xs"
|
||||||
|
/>
|
||||||
|
<q-linear-progress
|
||||||
|
v-if="isLoadingAll && totalToLoad !== null"
|
||||||
|
:value="loadAllProgress / 100"
|
||||||
|
color="primary"
|
||||||
|
class="q-mb-xs"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="isLoadingAll && totalToLoad !== null"
|
||||||
|
class="text-caption text-grey-6 q-mb-xs"
|
||||||
|
>
|
||||||
|
กำลังโหลด... {{ allRows.length.toLocaleString() }} /
|
||||||
|
{{ totalToLoad.toLocaleString() }} รายการ
|
||||||
|
</div>
|
||||||
<div class="row justify-between items-center q-mb-sm">
|
<div class="row justify-between items-center q-mb-sm">
|
||||||
<q-btn
|
<div class="row q-gutter-sm">
|
||||||
:disable="selected.length === 0"
|
<!-- <q-btn
|
||||||
:color="selected.length === 0 ? 'grey' : 'info'"
|
color="secondary"
|
||||||
dense
|
dense
|
||||||
icon="mdi-shuffle-variant"
|
icon="mdi-checkbox-multiple-marked-outline"
|
||||||
label="เปลี่ยนรอบการลงเวลา"
|
label="เลือกทั้งหมด"
|
||||||
@click="handleSelectMultiple()"
|
:disable="isLoadingAll || allRows.length === 0"
|
||||||
/>
|
@click="selectAllRows()"
|
||||||
|
/> -->
|
||||||
|
<q-btn
|
||||||
|
:disable="selected.length === 0 || isLoadingAll"
|
||||||
|
:color="selected.length === 0 ? 'grey' : 'info'"
|
||||||
|
dense
|
||||||
|
icon="mdi-shuffle-variant"
|
||||||
|
:label="`เปลี่ยนรอบการลงเวลา${
|
||||||
|
selected.length > 0 ? ` (${selected.length})` : ''
|
||||||
|
}`"
|
||||||
|
@click="handleSelectMultiple()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<d-table
|
<d-table
|
||||||
ref="table"
|
ref="table"
|
||||||
:columns="dataStore.columns"
|
:columns="dataStore.columns"
|
||||||
:rows="dataStore.rows"
|
:rows="allRows"
|
||||||
row-key="profileId"
|
row-key="profileId"
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
dense
|
dense
|
||||||
|
virtual-scroll
|
||||||
|
table-style="max-height: 58vh"
|
||||||
class="custom-header-table"
|
class="custom-header-table"
|
||||||
:visible-columns="dataStore.visibleColumns"
|
:visible-columns="dataStore.visibleColumns"
|
||||||
:rows-per-page-options="[10, 25, 50, 100]"
|
hide-pagination
|
||||||
@update:pagination="updatePagination"
|
|
||||||
v-model:pagination="pagination"
|
v-model:pagination="pagination"
|
||||||
selection="multiple"
|
selection="multiple"
|
||||||
v-model:selected="selected"
|
v-model:selected="selected"
|
||||||
|
|
@ -333,6 +446,7 @@ onMounted(() => {
|
||||||
keep-color
|
keep-color
|
||||||
color="primary"
|
color="primary"
|
||||||
dense
|
dense
|
||||||
|
:disable="isLoadingAll"
|
||||||
v-model="props.selected"
|
v-model="props.selected"
|
||||||
/>
|
/>
|
||||||
</q-th>
|
</q-th>
|
||||||
|
|
@ -354,6 +468,7 @@ onMounted(() => {
|
||||||
keep-color
|
keep-color
|
||||||
color="primary"
|
color="primary"
|
||||||
dense
|
dense
|
||||||
|
:disable="isLoadingAll"
|
||||||
v-model="props.selected"
|
v-model="props.selected"
|
||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
@ -429,21 +544,10 @@ onMounted(() => {
|
||||||
</q-td>
|
</q-td>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:pagination="scope">
|
|
||||||
ทั้งหมด {{ dataStore.totalListMain }} รายการ
|
|
||||||
<q-pagination
|
|
||||||
v-model="formData.page"
|
|
||||||
active-color="primary"
|
|
||||||
color="dark"
|
|
||||||
:max="Number(dataStore.maxPageMain)"
|
|
||||||
size="sm"
|
|
||||||
boundary-links
|
|
||||||
direction-links
|
|
||||||
:max-pages="5"
|
|
||||||
@update:model-value="dataStore.fetchDataForCardId(formData)"
|
|
||||||
></q-pagination>
|
|
||||||
</template>
|
|
||||||
</d-table>
|
</d-table>
|
||||||
|
<div class="text-caption text-grey-7 q-mt-sm">
|
||||||
|
ทั้งหมด {{ allRows.length }} รายการ
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue