more bug fix in support tickets

This commit is contained in:
Hesabix 2025-09-20 23:02:58 +03:30
parent aa75b9c743
commit 6a07d3ede5
4 changed files with 133 additions and 27 deletions

View file

@ -60,6 +60,34 @@ class TicketRepository(BaseRepository[Ticket]):
)\ )\
.filter(Ticket.user_id == user_id) .filter(Ticket.user_id == user_id)
# اعمال فیلترها
if query_info.filters:
for filter_item in query_info.filters:
if filter_item.property == "title" and hasattr(Ticket, "title"):
if filter_item.operator == "*":
query = query.filter(Ticket.title.ilike(f"%{filter_item.value}%"))
elif filter_item.operator == "*?":
query = query.filter(Ticket.title.ilike(f"{filter_item.value}%"))
elif filter_item.operator == "?*":
query = query.filter(Ticket.title.ilike(f"%{filter_item.value}"))
elif filter_item.operator == "=":
query = query.filter(Ticket.title == filter_item.value)
elif filter_item.property == "category.name":
query = query.join(Ticket.category).filter(Ticket.category.has(name=filter_item.value))
elif filter_item.property == "priority.name":
query = query.join(Ticket.priority).filter(Ticket.priority.has(name=filter_item.value))
elif filter_item.property == "status.name":
query = query.join(Ticket.status).filter(Ticket.status.has(name=filter_item.value))
elif filter_item.property == "description" and hasattr(Ticket, "description"):
if filter_item.operator == "*":
query = query.filter(Ticket.description.ilike(f"%{filter_item.value}%"))
elif filter_item.operator == "*?":
query = query.filter(Ticket.description.ilike(f"{filter_item.value}%"))
elif filter_item.operator == "?*":
query = query.filter(Ticket.description.ilike(f"%{filter_item.value}"))
elif filter_item.operator == "=":
query = query.filter(Ticket.description == filter_item.value)
# اعمال جستجو # اعمال جستجو
if query_info.search and query_info.search_fields: if query_info.search and query_info.search_fields:
search_conditions = [] search_conditions = []
@ -98,6 +126,43 @@ class TicketRepository(BaseRepository[Ticket]):
joinedload(Ticket.status) joinedload(Ticket.status)
) )
# اعمال فیلترها
if query_info.filters:
for filter_item in query_info.filters:
if filter_item.property == "title" and hasattr(Ticket, "title"):
if filter_item.operator == "*":
query = query.filter(Ticket.title.ilike(f"%{filter_item.value}%"))
elif filter_item.operator == "*?":
query = query.filter(Ticket.title.ilike(f"{filter_item.value}%"))
elif filter_item.operator == "?*":
query = query.filter(Ticket.title.ilike(f"%{filter_item.value}"))
elif filter_item.operator == "=":
query = query.filter(Ticket.title == filter_item.value)
elif filter_item.property == "category.name":
query = query.join(Ticket.category).filter(Ticket.category.has(name=filter_item.value))
elif filter_item.property == "priority.name":
query = query.join(Ticket.priority).filter(Ticket.priority.has(name=filter_item.value))
elif filter_item.property == "status.name":
query = query.join(Ticket.status).filter(Ticket.status.has(name=filter_item.value))
elif filter_item.property == "description" and hasattr(Ticket, "description"):
if filter_item.operator == "*":
query = query.filter(Ticket.description.ilike(f"%{filter_item.value}%"))
elif filter_item.operator == "*?":
query = query.filter(Ticket.description.ilike(f"{filter_item.value}%"))
elif filter_item.operator == "?*":
query = query.filter(Ticket.description.ilike(f"%{filter_item.value}"))
elif filter_item.operator == "=":
query = query.filter(Ticket.description == filter_item.value)
elif filter_item.property == "user_email":
query = query.join(Ticket.user).filter(Ticket.user.has(email=filter_item.value))
elif filter_item.property == "user_name":
query = query.join(Ticket.user).filter(
or_(
Ticket.user.has(first_name=filter_item.value),
Ticket.user.has(last_name=filter_item.value)
)
)
# اعمال جستجو # اعمال جستجو
if query_info.search and query_info.search_fields: if query_info.search and query_info.search_fields:
search_conditions = [] search_conditions = []

View file

@ -129,7 +129,7 @@ class _SupportPageState extends State<SupportPage> {
}, },
defaultPageSize: 20, defaultPageSize: 20,
pageSizeOptions: const [10, 20, 50, 100], pageSizeOptions: const [10, 20, 50, 100],
showRefreshButton: true, showFiltersButton: false,
showClearFiltersButton: true, showClearFiltersButton: true,
emptyStateMessage: t.noTickets, emptyStateMessage: t.noTickets,
loadingMessage: t.loadingTickets, loadingMessage: t.loadingTickets,

View file

@ -215,6 +215,9 @@ class DataTableConfig<T> {
// Custom header actions // Custom header actions
final List<Widget>? customHeaderActions; final List<Widget>? customHeaderActions;
// Show individual action buttons
final bool showFiltersButton;
const DataTableConfig({ const DataTableConfig({
required this.endpoint, required this.endpoint,
required this.columns, required this.columns,
@ -276,6 +279,7 @@ class DataTableConfig<T> {
this.initialColumnSettings, this.initialColumnSettings,
this.onColumnSettingsChanged, this.onColumnSettingsChanged,
this.customHeaderActions, this.customHeaderActions,
this.showFiltersButton = true,
}); });
/// Get column width as double /// Get column width as double

View file

@ -772,7 +772,7 @@ class _DataTableWidgetState<T> extends State<DataTableWidget<T>> {
const Spacer(), const Spacer(),
// Filter buttons // Filter buttons
if (widget.config.showFilters) ...[ if (widget.config.showFilters && widget.config.showFiltersButton) ...[
Tooltip( Tooltip(
message: _showFilters ? t.hideFilters : t.showFilters, message: _showFilters ? t.hideFilters : t.showFilters,
child: IconButton( child: IconButton(
@ -807,37 +807,74 @@ class _DataTableWidgetState<T> extends State<DataTableWidget<T>> {
const SizedBox(width: 8), const SizedBox(width: 8),
], ],
if (widget.config.showRefreshButton)
IconButton(
onPressed: _fetchData,
icon: const Icon(Icons.refresh),
tooltip: t.refresh,
),
// Custom header actions // Custom header actions
if (widget.config.customHeaderActions != null) ...[ if (widget.config.customHeaderActions != null) ...[
const SizedBox(width: 8), const SizedBox(width: 8),
...widget.config.customHeaderActions!, ...widget.config.customHeaderActions!,
], ],
// Column settings button (moved after refresh button) // Actions menu
if (widget.config.showColumnSettingsButton && widget.config.enableColumnSettings) ...[ PopupMenuButton<String>(
const SizedBox(width: 4), icon: const Icon(Icons.more_vert),
Tooltip( tooltip: 'عملیات',
message: t.columnSettings, onSelected: (value) {
child: IconButton( switch (value) {
onPressed: _isLoadingColumnSettings ? null : _openColumnSettingsDialog, case 'refresh':
icon: _isLoadingColumnSettings _fetchData();
? const SizedBox( break;
width: 16, case 'filters':
height: 16, setState(() {
child: CircularProgressIndicator(strokeWidth: 2), _showFilters = !_showFilters;
) });
: const Icon(Icons.view_column), break;
tooltip: t.columnSettings, case 'columnSettings':
), _openColumnSettingsDialog();
), break;
], }
},
itemBuilder: (context) => [
if (widget.config.showRefreshButton)
PopupMenuItem(
value: 'refresh',
child: Row(
children: [
const Icon(Icons.refresh, size: 20),
const SizedBox(width: 8),
Text(t.refresh),
],
),
),
if (widget.config.showFilters && widget.config.showFiltersButton)
PopupMenuItem(
value: 'filters',
child: Row(
children: [
Icon(_showFilters ? Icons.filter_list_off : Icons.filter_list, size: 20),
const SizedBox(width: 8),
Text(_showFilters ? t.hideFilters : t.showFilters),
],
),
),
if (widget.config.showColumnSettingsButton && widget.config.enableColumnSettings)
PopupMenuItem(
value: 'columnSettings',
enabled: !_isLoadingColumnSettings,
child: Row(
children: [
_isLoadingColumnSettings
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.view_column, size: 20),
const SizedBox(width: 8),
Text(t.columnSettings),
],
),
),
],
),
], ],
); );
} }