more bug fix in support tickets
This commit is contained in:
parent
aa75b9c743
commit
6a07d3ede5
|
|
@ -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 = []
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,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,
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue