update invoice filter and paginator

This commit is contained in:
2026-06-01 16:22:20 +03:30
parent d44004d555
commit ae963a60ce
10 changed files with 83 additions and 57 deletions
@@ -7,9 +7,9 @@
header="فیلتر صورت‌حساب‌ها" header="فیلتر صورت‌حساب‌ها"
styleClass="w-full md:w-[28rem]" styleClass="w-full md:w-[28rem]"
(visibleChange)="visibleChange.emit($event)"> (visibleChange)="visibleChange.emit($event)">
<div class="flex h-full flex-col overflow-y-auto"> <div class="flex h-full flex-col">
<hr /> <hr />
<form class="grow py-4" [formGroup]="form" (ngSubmit)="submit()"> <form class="grow py-0" [formGroup]="form" (ngSubmit)="submit()">
<app-input label="شماره صورت‌حساب" [control]="form.controls.invoice_number" name="invoice_number" /> <app-input label="شماره صورت‌حساب" [control]="form.controls.invoice_number" name="invoice_number" />
<app-enum-select type="fiscalResponseStatus" [control]="form.controls.status" /> <app-enum-select type="fiscalResponseStatus" [control]="form.controls.status" />
@@ -23,12 +23,26 @@
type="nationalId" /> type="nationalId" />
<app-input label="شناسه اقتصادی" [control]="form.controls.customer_economic_code" name="customer_economic_code" /> <app-input label="شناسه اقتصادی" [control]="form.controls.customer_economic_code" name="customer_economic_code" />
<!-- <div class="grid grid-cols-2 gap-2"> <app-datepicker
<uikit-datepicker label="از تاریخ صورت‌حساب‌" [control]="form.controls.invoice_date_from" name="invoice_date_from" /> label="از تاریخ صورت‌حساب‌"
<uikit-datepicker label="تا تاریخ صورت‌حساب‌" [control]="form.controls.invoice_date_to" name="invoice_date_to" /> [control]="form.controls.invoice_date_from"
</div> [max]="form.controls.invoice_date_to.value || now"
name="invoice_date_from" />
<app-datepicker
label="تا تاریخ صورت‌حساب‌"
[control]="form.controls.invoice_date_to"
[min]="form.controls.invoice_date_from.value || undefined"
[max]="now"
name="invoice_date_to" />
<div class="grid grid-cols-2 gap-2"> <app-datepicker
label="از تاریخ ایجاد"
[control]="form.controls.created_at_from"
[max]="form.controls.invoice_date_to.value || now"
name="created_at_from" />
<app-datepicker label="تا تاریخ ایجاد" [control]="form.controls.created_at_to" [max]="now" name="created_at_to" />
<!-- <div class="grid grid-cols-2 gap-2">
<uikit-datepicker label="از تاریخ صدور" [control]="form.controls.created_at_from" name="created_at_from" /> <uikit-datepicker label="از تاریخ صدور" [control]="form.controls.created_at_from" name="created_at_from" />
<uikit-datepicker label="تا تاریخ صدور" [control]="form.controls.created_at_to" name="created_at_to" /> <uikit-datepicker label="تا تاریخ صدور" [control]="form.controls.created_at_to" name="created_at_to" />
</div> --> </div> -->
@@ -38,7 +52,7 @@
<app-input label="تا مبلغ" [control]="form.controls.total_amount_to" name="total_amount_to" type="price" /> <app-input label="تا مبلغ" [control]="form.controls.total_amount_to" name="total_amount_to" type="price" />
</div> </div>
</form> </form>
<div class="bg-surface-card sticky bottom-0 mt-auto shrink-0"> <div class="bg-surface-card mt-auto shrink-0 pb-4">
<hr /> <hr />
<div class="grid grid-cols-2 gap-2 pt-2"> <div class="grid grid-cols-2 gap-2 pt-2">
<button pButton type="button" outlined label="حذف" (click)="clear()"></button> <button pButton type="button" outlined label="حذف" (click)="clear()"></button>
@@ -2,6 +2,8 @@ import { Maybe } from '@/core';
import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
import { TspProviderResponseStatus } from '@/shared/catalog'; import { TspProviderResponseStatus } from '@/shared/catalog';
import { InputComponent } from '@/shared/components'; import { InputComponent } from '@/shared/components';
import { DatepickerComponent } from '@/uikit';
import { nowGregorian } from '@/utils';
import { import {
Component, Component,
EventEmitter, EventEmitter,
@@ -29,6 +31,7 @@ import { IPosSaleInvoicesFilterDto } from '../models';
ButtonDirective, ButtonDirective,
EnumSelectComponent, EnumSelectComponent,
InputComponent, InputComponent,
DatepickerComponent,
], ],
}) })
export class PosSaleInvoicesFilterDrawerComponent implements OnChanges { export class PosSaleInvoicesFilterDrawerComponent implements OnChanges {
@@ -40,6 +43,8 @@ export class PosSaleInvoicesFilterDrawerComponent implements OnChanges {
@Output() visibleChange = new EventEmitter<boolean>(); @Output() visibleChange = new EventEmitter<boolean>();
@Output() apply = new EventEmitter<IPosSaleInvoicesFilterDto>(); @Output() apply = new EventEmitter<IPosSaleInvoicesFilterDto>();
readonly now = nowGregorian();
readonly form = this.fb.group({ readonly form = this.fb.group({
page: this.fb.control<number | null>(null), page: this.fb.control<number | null>(null),
perPage: this.fb.control<number | null>(null), perPage: this.fb.control<number | null>(null),
@@ -160,6 +160,7 @@ export class PosSaleInvoiceListComponent {
} }
private syncFiltersToQueryParams() { private syncFiltersToQueryParams() {
this.filters.update((val) => ({ ...val, page: 1 }));
const queryParams = Object.entries(this.filters()).reduce<Record<string, string>>( const queryParams = Object.entries(this.filters()).reduce<Record<string, string>>(
(acc, [key, value]) => { (acc, [key, value]) => {
if (value !== undefined && value !== null && value !== '') { if (value !== undefined && value !== null && value !== '') {
@@ -6,16 +6,16 @@
<div class="absolute top-0 right-0 h-full w-1" [style.backgroundColor]="preparedInfo().borderColor"></div> <div class="absolute top-0 right-0 h-full w-1" [style.backgroundColor]="preparedInfo().borderColor"></div>
<div class="text-surface-700 flex items-center justify-between gap-2"> <div class="text-surface-700 flex items-center justify-between gap-2">
<div class="text-surface-700 flex items-center gap-2"> <div class="text-surface-700 flex items-center gap-2">
<span <!-- <span
class="text-surface-700 flex h-8 w-8 items-center justify-center rounded-full border" class="text-surface-700 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border"
[style.borderColor]="preparedInfo().borderColor" [style.borderColor]="preparedInfo().borderColor"
[style.backgroundColor]="preparedInfo().borderColor + '33'"> [style.backgroundColor]="preparedInfo().borderColor + '33'">
<i class="text-sm" [ngClass]="'pi pi-' + preparedInfo().icon" [style.color]="preparedInfo().borderColor"></i> <i class="text-sm" [ngClass]="'pi pi-' + preparedInfo().icon" [style.color]="preparedInfo().borderColor"></i>
</span> </span> -->
<span class="text-surface-700 text-sm font-semibold">{{ preparedInfo().title }}</span> <span class="text-surface-700 text-sm font-semibold">{{ preparedInfo().title }}</span>
</div> </div>
<span <span
class="text-surface-700 rounded-full border px-2 py-1 text-xs font-bold" class="text-surface-700 shrink-0 rounded-full border px-2 py-1 text-xs font-bold"
[style.borderColor]="preparedInfo().borderColor"> [style.borderColor]="preparedInfo().borderColor">
{{ count || 0 }} عدد {{ count || 0 }} عدد
</span> </span>
@@ -57,7 +57,7 @@ export class PosStatisticsInvoiceTypeCardComponent {
}; };
case 'pending': case 'pending':
return { return {
title: 'انتظار ارسال', title: taxProviderStatusTranslatorUtil('FISCAL_QUEUED'),
icon: 'clock', icon: 'clock',
bgColor: '#3B82F61A', bgColor: '#3B82F61A',
borderColor: '#3B82F6', borderColor: '#3B82F6',
@@ -62,11 +62,11 @@ export class PosStatisticsRootComponent {
case 'failure': case 'failure':
queryParams.status = 'FAILURE'; queryParams.status = 'FAILURE';
break; break;
case 'notSended': case 'not_send':
queryParams.status = 'NOT_SEND'; queryParams.status = 'NOT_SEND';
break; break;
case 'pending': case 'pending':
queryParams.status = 'QUEUED'; queryParams.status = 'FISCAL_QUEUED';
break; break;
} }
const queryString = new URLSearchParams(queryParams as Record<string, string>).toString(); const queryString = new URLSearchParams(queryParams as Record<string, string>).toString();
+1 -2
View File
@@ -8,6 +8,5 @@
[showClear]="showClear" [showClear]="showClear"
[name]="name || type" [name]="name || type"
[overlayOptions]="overlayOptions()" [overlayOptions]="overlayOptions()"
appendTo="body" appendTo="body" />
/>
</uikit-field> </uikit-field>
@@ -10,7 +10,7 @@
<i class="pi pi-chevron-right cursor-pointer" (click)="changeMonth(-1)"></i> <i class="pi pi-chevron-right cursor-pointer" (click)="changeMonth(-1)"></i>
</div> </div>
<div class="flex w-32 items-center justify-center px-3 text-lg font-bold select-none"> <div class="flex w-36 items-center justify-center px-3 text-lg font-bold select-none">
{{ monthInfo().monthTitle }} {{ monthInfo().monthTitle }}
</div> </div>
@@ -39,7 +39,7 @@
[class.bg-background-default]="closedDays.includes($index)"> [class.bg-background-default]="closedDays.includes($index)">
@if (!(day.isNextMonth || day.isPastMonth)) { @if (!(day.isNextMonth || day.isPastMonth)) {
<span <span
class="flex aspect-square w-full cursor-pointer items-center justify-center rounded px-2 py-1 text-lg transition-colors select-none" class="flex aspect-square w-full cursor-pointer items-center justify-center rounded-lg px-2 py-1 text-lg transition-colors select-none"
[ngClass]="{ [ngClass]="{
'bg-surface-ground font-bold': day.isCurrentDay, 'bg-surface-ground font-bold': day.isCurrentDay,
'bg-primary! text-primary-contrast!': isSelected(day), 'bg-primary! text-primary-contrast!': isSelected(day),
@@ -19,7 +19,7 @@ import { InputText } from 'primeng/inputtext';
import { Popover } from 'primeng/popover'; import { Popover } from 'primeng/popover';
import { Maybe } from '@/core'; import { Maybe } from '@/core';
import { formatJalali } from '@/utils'; import { GREGORIAN_DATE_FORMATS, formatDate, formatJalali } from '@/utils';
import { UikitFieldComponent } from '../uikit-field.component'; import { UikitFieldComponent } from '../uikit-field.component';
@@ -40,44 +40,33 @@ dayjs.extend(jalaliday);
imports: [CommonModule, Popover, InputText, UikitFieldComponent], imports: [CommonModule, Popover, InputText, UikitFieldComponent],
}) })
export class DatepickerComponent { export class DatepickerComponent {
@Input({ required: true }) @Input({ required: true }) control!: FormControl<Maybe<string>>;
control!: FormControl<Maybe<string>>;
@Input() @Input() alignment: 'vertical' | 'horizontal' = 'vertical';
alignment: 'vertical' | 'horizontal' = 'vertical';
@Input() @Input() name = 'date';
name = 'date';
@Input() @Input() label = 'تاریخ';
label = 'تاریخ';
@Input() @Input() closeOnSelect = true;
closeOnSelect = true;
/** /**
* Gregorian YYYY-MM-DD * Gregorian YYYY-MM-DD
*/ */
@Input() @Input() min?: string;
min?: string;
/** /**
* Gregorian YYYY-MM-DD * Gregorian YYYY-MM-DD
*/ */
@Input() @Input() max?: string;
max?: string;
@Input() @Input() closedDays: number[] = [];
closedDays: number[] = [];
@Output() @Output() valueChange = new EventEmitter<string>();
valueChange = new EventEmitter<string>();
@Output() @Output() clickOnDayEvent = new EventEmitter<MonthlyWeekDate>();
clickOnDayEvent = new EventEmitter<MonthlyWeekDate>();
@ViewChild('op') @ViewChild('op') op!: Popover;
op!: Popover;
readonly daysName = daysName; readonly daysName = daysName;
@@ -113,7 +102,9 @@ export class DatepickerComponent {
} }
get value(): Maybe<string> { get value(): Maybe<string> {
return this.control?.value ?? null; return this.control.value
? formatDate(this.control.value, 'gregory', 'en', GREGORIAN_DATE_FORMATS.NUMERIC)
: null;
} }
get valueToShow(): Maybe<string> { get valueToShow(): Maybe<string> {
+23 -7
View File
@@ -1,4 +1,4 @@
import { Component, computed, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output, signal, SimpleChanges } from '@angular/core';
import { ButtonModule } from 'primeng/button'; import { ButtonModule } from 'primeng/button';
@Component({ @Component({
@@ -13,13 +13,16 @@ export class PaginatorComponent {
@Input() loading: boolean = false; @Input() loading: boolean = false;
@Output() onChange = new EventEmitter<number>(); @Output() onChange = new EventEmitter<number>();
pagesToShow = computed(() => { pagesToShow = signal<number[]>([]);
init() {
const maxVisible = 5; const maxVisible = 5;
if (this.totalPages <= maxVisible) { let pagesToShow = [];
return Array.from({ length: this.totalPages }, (_, i) => i + 1);
}
if (this.totalPages <= maxVisible) {
pagesToShow = Array.from({ length: this.totalPages }, (_, i) => i + 1);
} else {
let start = Math.max(1, this.currentPage - Math.floor(maxVisible / 2)); let start = Math.max(1, this.currentPage - Math.floor(maxVisible / 2));
let end = start + maxVisible - 1; let end = start + maxVisible - 1;
@@ -29,8 +32,11 @@ export class PaginatorComponent {
start = end - maxVisible + 1; start = end - maxVisible + 1;
} }
return Array.from({ length: end - start + 1 }, (_, i) => start + i); pagesToShow = Array.from({ length: end - start + 1 }, (_, i) => start + i);
}); }
this.pagesToShow.set(pagesToShow);
}
onPageChange(newPage: number) { onPageChange(newPage: number) {
this.onChange.emit(newPage); this.onChange.emit(newPage);
@@ -46,4 +52,14 @@ export class PaginatorComponent {
this.onPageChange(this.currentPage + 1); this.onPageChange(this.currentPage + 1);
} }
} }
ngOnInit() {
this.init();
}
ngOnChanges(changes: SimpleChanges) {
if (changes['totalPages'] || changes['currentPage']) {
this.init();
}
}
} }