Add pagination to leads list
Store tracks page/pageSize (default 20), exposes totalPages getter and setPage/setPageSize actions. Filter actions reset to page 1. List view shows page-size select, range indicator, and prev/next controls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ddfaf56722
commit
2d2b8784ec
@ -12,6 +12,8 @@ interface State {
|
||||
total: number;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
filters: {
|
||||
status: LeadStatus | 'all';
|
||||
lead_type: LeadType | 'all';
|
||||
@ -25,8 +27,13 @@ export const useLeadsStore = defineStore('leads', {
|
||||
total: 0,
|
||||
loading: false,
|
||||
error: null,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
filters: { status: 'all', lead_type: 'all', deal_stage: 'all' },
|
||||
}),
|
||||
getters: {
|
||||
totalPages: (s): number => Math.max(1, Math.ceil(s.total / s.pageSize)),
|
||||
},
|
||||
actions: {
|
||||
async load() {
|
||||
this.loading = true;
|
||||
@ -37,26 +44,45 @@ export const useLeadsStore = defineStore('leads', {
|
||||
lead_type: this.filters.lead_type,
|
||||
deal_stage: this.filters.deal_stage,
|
||||
sort: 'score_desc',
|
||||
limit: 100,
|
||||
limit: this.pageSize,
|
||||
offset: (this.page - 1) * this.pageSize,
|
||||
});
|
||||
this.items = res.data;
|
||||
this.total = res.total;
|
||||
const max = Math.max(1, Math.ceil(this.total / this.pageSize));
|
||||
if (this.page > max) {
|
||||
this.page = max;
|
||||
await this.load();
|
||||
}
|
||||
} catch (e) {
|
||||
this.error = (e as Error).message;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
setPage(page: number) {
|
||||
const max = Math.max(1, Math.ceil(this.total / this.pageSize));
|
||||
this.page = Math.min(Math.max(1, page), max);
|
||||
return this.load();
|
||||
},
|
||||
setPageSize(size: number) {
|
||||
this.pageSize = size;
|
||||
this.page = 1;
|
||||
return this.load();
|
||||
},
|
||||
setStatus(status: LeadStatus | 'all') {
|
||||
this.filters.status = status;
|
||||
this.page = 1;
|
||||
return this.load();
|
||||
},
|
||||
setLeadType(lead_type: LeadType | 'all') {
|
||||
this.filters.lead_type = lead_type;
|
||||
this.page = 1;
|
||||
return this.load();
|
||||
},
|
||||
setDealStage(deal_stage: DealStage | 'all') {
|
||||
this.filters.deal_stage = deal_stage;
|
||||
this.page = 1;
|
||||
return this.load();
|
||||
},
|
||||
},
|
||||
|
||||
@ -126,5 +126,49 @@ async function removeLead(id: string, name: string) {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="store.items.length > 0"
|
||||
class="flex items-center justify-between text-sm text-gray-700"
|
||||
>
|
||||
<div>
|
||||
<label class="mr-2">На странице:</label>
|
||||
<select
|
||||
:value="store.pageSize"
|
||||
@change="store.setPageSize(Number(($event.target as HTMLSelectElement).value))"
|
||||
class="border border-gray-300 rounded-md px-2 py-1 bg-white"
|
||||
>
|
||||
<option :value="10">10</option>
|
||||
<option :value="20">20</option>
|
||||
<option :value="50">50</option>
|
||||
<option :value="100">100</option>
|
||||
</select>
|
||||
<span class="ml-4 text-gray-500">
|
||||
{{ (store.page - 1) * store.pageSize + 1 }}–{{
|
||||
Math.min(store.page * store.pageSize, store.total)
|
||||
}}
|
||||
из {{ store.total }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-1 rounded-md border border-gray-300 bg-white disabled:opacity-40"
|
||||
:disabled="store.page <= 1 || store.loading"
|
||||
@click="store.setPage(store.page - 1)"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
<span class="px-2">{{ store.page }} / {{ store.totalPages }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-1 rounded-md border border-gray-300 bg-white disabled:opacity-40"
|
||||
:disabled="store.page >= store.totalPages || store.loading"
|
||||
@click="store.setPage(store.page + 1)"
|
||||
>
|
||||
→
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user