refactor: 04 => screen.xs fetch scroll

This commit is contained in:
puriphatt 2025-01-29 17:07:43 +07:00
parent a894bacb13
commit f559987e0c
2 changed files with 733 additions and 671 deletions

View file

@ -276,7 +276,10 @@ async function fetchWorkflowList() {
: 'INACTIVE', : 'INACTIVE',
}); });
if (res) { if (res) {
workflowData.value = res.result; $q.screen.xs
? workflowData.value.push(...res.result)
: (workflowData.value = res.result);
workflowPageMax.value = Math.ceil(res.total / workflowPageSize.value); workflowPageMax.value = Math.ceil(res.total / workflowPageSize.value);
if (pageState.inputSearch || statusFilter.value !== 'all') return; if (pageState.inputSearch || statusFilter.value !== 'all') return;
pageState.total = res.total; pageState.total = res.total;
@ -351,7 +354,7 @@ watch([() => pageState.inputSearch, workflowPageSize], fetchWorkflowList);
<!-- SEC: header content --> <!-- SEC: header content -->
<section class="col surface-1 rounded bordered overflow-hidden"> <section class="col surface-1 rounded bordered overflow-hidden">
<div class="column full-height"> <div class="column full-height no-wrap">
<header <header
class="row surface-3 justify-between full-width items-center bordered-b" class="row surface-3 justify-between full-width items-center bordered-b"
style="z-index: 1" style="z-index: 1"
@ -500,173 +503,113 @@ watch([() => pageState.inputSearch, workflowPageSize], fetchWorkflowList);
</article> </article>
<article v-else class="col q-pa-md surface-2 scroll full-width"> <article v-else class="col q-pa-md surface-2 scroll full-width">
<q-table <q-infinite-scroll
flat :offset="100"
bordered @load="
:grid="pageState.gridView" (_, done) => {
:rows="workflowData" if ($q.screen.gt.xs || workflowPage === workflowPageMax) return;
:columns="columns" workflowPage = workflowPage + 1;
class="full-width" fetchWorkflowList().then(() =>
card-container-class="q-col-gutter-md" done(workflowPage >= workflowPageMax),
row-key="name" );
:rows-per-page-options="[0]" }
hide-pagination "
:visible-columns="fieldSelected"
> >
<template #header="{ cols }"> <q-table
<q-tr style="background-color: hsla(var(--info-bg) / 0.07)"> flat
<q-th bordered
v-for="v in cols" :grid="pageState.gridView"
:key="v" :rows="workflowData"
:class="{ :columns="columns"
'text-left': v.name === 'name', class="full-width"
'text-right': v.name === 'step', card-container-class="q-col-gutter-md"
}" row-key="name"
> :rows-per-page-options="[0]"
{{ hide-pagination
v.label && :visible-columns="fieldSelected"
$t(v.label, { >
msg: <template #header="{ cols }">
v.name === 'step' <q-tr style="background-color: hsla(var(--info-bg) / 0.07)">
? $t('flow.step') <q-th
: v.name === 'name' v-for="v in cols"
? $t('flow.title') :key="v"
: '', :class="{
}) 'text-left': v.name === 'name',
}} 'text-right': v.name === 'step',
</q-th> }"
<q-th auto-width /> >
</q-tr> {{
</template> v.label &&
$t(v.label, {
<template #body="props"> msg:
<q-tr v.name === 'step'
:class="{ ? $t('flow.step')
'app-text-muted': props.row.status === 'INACTIVE', : v.name === 'name'
'status-active': props.row.status !== 'INACTIVE', ? $t('flow.title')
'status-inactive': props.row.status === 'INACTIVE', : '',
}" })
:style=" }}
props.rowIndex % 2 !== 0 </q-th>
? $q.dark.isActive <q-th auto-width />
? 'background: hsl(var(--gray-11-hsl)/0.2)' </q-tr>
: `background: #f9fafc` </template>
: ''
" <template #body="props">
> <q-tr
<q-td
v-if="fieldSelected.includes('order')"
class="text-center"
>
{{ props.rowIndex + 1 }}
<!-- {{ (currentPage - 1) * pageSize + props.rowIndex + 1 }} -->
</q-td>
<q-td v-if="fieldSelected.includes('name')">
<section class="row items-center no-wrap">
<q-avatar
class="q-mr-sm"
size="md"
style="
color: var(--gray-6);
background: hsla(var(--gray-6-hsl) / 0.1);
"
>
<q-icon name="mdi-cogs" />
<q-badge
class="absolute-bottom-right no-padding"
style="
border-radius: 50%;
min-width: 8px;
min-height: 8px;
"
:style="{
background: `var(--${props.row.status === 'INACTIVE' ? 'stone-5' : 'green-6'})`,
}"
></q-badge>
</q-avatar>
{{ props.row.name }}
</section>
</q-td>
<q-td v-if="fieldSelected.includes('step')" class="text-right">
{{ props.row.step.length }}
</q-td>
<q-td style="width: 20%" class="text-right">
<q-btn
icon="mdi-eye-outline"
size="sm"
dense
round
flat
@click.stop="
() => {
assignFormData(props.row);
triggerDialog('view');
}
"
/>
<KebabAction
:id-name="props.row.id"
:status="props.row.status"
@view="
() => {
assignFormData(props.row);
triggerDialog('view');
}
"
@edit="
() => {
assignFormData(props.row);
triggerDialog('edit');
}
"
@delete="() => deleteWorkflow(props.row.id)"
@change-status="() => triggerChangeStatus(props.row)"
/>
</q-td>
</q-tr>
</template>
<template v-slot:item="props">
<section class="col-12 col-md-4 column">
<div
:class="{ :class="{
'app-text-muted': props.row.status === 'INACTIVE',
'status-active': props.row.status !== 'INACTIVE',
'status-inactive': props.row.status === 'INACTIVE', 'status-inactive': props.row.status === 'INACTIVE',
}" }"
class="surface-1 rounded bordered row no-wrap col" :style="
style="overflow: hidden" props.rowIndex % 2 !== 0
? $q.dark.isActive
? 'background: hsl(var(--gray-11-hsl)/0.2)'
: `background: #f9fafc`
: ''
"
> >
<div <q-td
class="col-md-2 col-3 flex items-center justify-center" v-if="fieldSelected.includes('order')"
style=" class="text-center"
color: var(--gray-6);
background: hsla(var(--gray-6-hsl) / 0.1);
"
> >
<q-icon name="mdi-cogs" size="md" /> {{ props.rowIndex + 1 }}
</div> <!-- {{ (currentPage - 1) * pageSize + props.rowIndex + 1 }} -->
<article class="row q-pa-sm q-gutter-y-sm col"> </q-td>
<div <q-td v-if="fieldSelected.includes('name')">
v-if="fieldSelected.includes('name')" <section class="row items-center no-wrap">
class="text-weight-bold col-12 ellipsis-2-lines" <q-avatar
:class="{ class="q-mr-sm"
'app-text-muted': props.row.status === 'INACTIVE', size="md"
}" style="
> color: var(--gray-6);
{{ props.row.name }} background: hsla(var(--gray-6-hsl) / 0.1);
"
>
<q-icon name="mdi-cogs" />
<q-tooltip> <q-badge
{{ props.row.name }} class="absolute-bottom-right no-padding"
</q-tooltip> style="
</div> border-radius: 50%;
<div v-if="fieldSelected.includes('step')" class="self-end"> min-width: 8px;
<div class="bordered rounded q-px-sm"> min-height: 8px;
<q-icon name="mdi-note-edit-outline" class="q-pr-sm" /> "
{{ props.row.step.length }} :style="{
</div> background: `var(--${props.row.status === 'INACTIVE' ? 'stone-5' : 'green-6'})`,
</div> }"
</article> ></q-badge>
<nav class="q-pa-sm row items-center self-start"> </q-avatar>
{{ props.row.name }}
</section>
</q-td>
<q-td
v-if="fieldSelected.includes('step')"
class="text-right"
>
{{ props.row.step.length }}
</q-td>
<q-td style="width: 20%" class="text-right">
<q-btn <q-btn
icon="mdi-eye-outline" icon="mdi-eye-outline"
size="sm" size="sm"
@ -698,17 +641,108 @@ watch([() => pageState.inputSearch, workflowPageSize], fetchWorkflowList);
@delete="() => deleteWorkflow(props.row.id)" @delete="() => deleteWorkflow(props.row.id)"
@change-status="() => triggerChangeStatus(props.row)" @change-status="() => triggerChangeStatus(props.row)"
/> />
</nav> </q-td>
</div> </q-tr>
</section> </template>
<template v-slot:item="props">
<section class="col-12 col-md-4 column">
<div
:class="{
'status-inactive': props.row.status === 'INACTIVE',
}"
class="surface-1 rounded bordered row no-wrap col"
style="overflow: hidden"
>
<div
class="col-md-2 col-3 flex items-center justify-center"
style="
color: var(--gray-6);
background: hsla(var(--gray-6-hsl) / 0.1);
"
>
<q-icon name="mdi-cogs" size="md" />
</div>
<article class="row q-pa-sm q-gutter-y-sm col">
<div
v-if="fieldSelected.includes('name')"
class="text-weight-bold col-12 ellipsis-2-lines"
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
}"
>
{{ props.row.name }}
<q-tooltip>
{{ props.row.name }}
</q-tooltip>
</div>
<div
v-if="fieldSelected.includes('step')"
class="self-end"
>
<div class="bordered rounded q-px-sm">
<q-icon
name="mdi-note-edit-outline"
class="q-pr-sm"
/>
{{ props.row.step.length }}
</div>
</div>
</article>
<nav class="q-pa-sm row items-center self-start">
<q-btn
icon="mdi-eye-outline"
size="sm"
dense
round
flat
@click.stop="
() => {
assignFormData(props.row);
triggerDialog('view');
}
"
/>
<KebabAction
:id-name="props.row.id"
:status="props.row.status"
@view="
() => {
assignFormData(props.row);
triggerDialog('view');
}
"
@edit="
() => {
assignFormData(props.row);
triggerDialog('edit');
}
"
@delete="() => deleteWorkflow(props.row.id)"
@change-status="() => triggerChangeStatus(props.row)"
/>
</nav>
</div>
</section>
</template>
</q-table>
<template v-slot:loading>
<div
v-if="$q.screen.lt.sm && workflowPage !== workflowPageMax"
class="row justify-center"
>
<q-spinner-dots color="primary" size="40px" />
</div>
</template> </template>
</q-table> </q-infinite-scroll>
</article> </article>
<!-- SEC: footer content --> <!-- SEC: footer content -->
<footer <footer
class="row justify-between items-center q-px-md q-py-sm surface-2" class="row justify-between items-center q-px-md q-py-sm surface-2"
v-if="workflowPageMax > 0" v-if="workflowPageMax > 0 && $q.screen.gt.xs"
> >
<div class="col-4"> <div class="col-4">
<div class="row items-center no-wrap"> <div class="row items-center no-wrap">

File diff suppressed because it is too large Load diff