filter transaction description keywords in statistics & analysis page

This commit is contained in:
MaysWind
2025-07-08 00:31:50 +08:00
parent 5c9eb5dc5a
commit 01aa2cf0a4
22 changed files with 167 additions and 6 deletions
+2 -2
View File
@@ -316,7 +316,7 @@ func (a *TransactionsApi) TransactionStatisticsHandler(c *core.WebContext) (any,
}
uid := c.GetCurrentUid()
totalAmounts, err := a.transactions.GetAccountsAndCategoriesTotalIncomeAndExpense(c, uid, statisticReq.StartTime, statisticReq.EndTime, allTagIds, noTags, statisticReq.TagFilterType, utcOffset, statisticReq.UseTransactionTimezone)
totalAmounts, err := a.transactions.GetAccountsAndCategoriesTotalIncomeAndExpense(c, uid, statisticReq.StartTime, statisticReq.EndTime, allTagIds, noTags, statisticReq.TagFilterType, statisticReq.Keyword, utcOffset, statisticReq.UseTransactionTimezone)
if err != nil {
log.Errorf(c, "[transactions.TransactionStatisticsHandler] failed to get accounts and categories total income and expense for user \"uid:%d\", because %s", uid, err.Error())
@@ -379,7 +379,7 @@ func (a *TransactionsApi) TransactionStatisticsTrendsHandler(c *core.WebContext)
}
uid := c.GetCurrentUid()
allMonthlyTotalAmounts, err := a.transactions.GetAccountsAndCategoriesMonthlyIncomeAndExpense(c, uid, startYear, startMonth, endYear, endMonth, allTagIds, noTags, statisticTrendsReq.TagFilterType, utcOffset, statisticTrendsReq.UseTransactionTimezone)
allMonthlyTotalAmounts, err := a.transactions.GetAccountsAndCategoriesMonthlyIncomeAndExpense(c, uid, startYear, startMonth, endYear, endMonth, allTagIds, noTags, statisticTrendsReq.TagFilterType, statisticTrendsReq.Keyword, utcOffset, statisticTrendsReq.UseTransactionTimezone)
if err != nil {
log.Errorf(c, "[transactions.TransactionStatisticsTrendsHandler] failed to get accounts and categories total income and expense for user \"uid:%d\", because %s", uid, err.Error())
+2
View File
@@ -228,6 +228,7 @@ type TransactionStatisticRequest struct {
EndTime int64 `form:"end_time" binding:"min=0"`
TagIds string `form:"tag_ids"`
TagFilterType TransactionTagFilterType `form:"tag_filter_type" binding:"min=0,max=3"`
Keyword string `form:"keyword"`
UseTransactionTimezone bool `form:"use_transaction_timezone"`
}
@@ -236,6 +237,7 @@ type TransactionStatisticTrendsRequest struct {
YearMonthRangeRequest
TagIds string `form:"tag_ids"`
TagFilterType TransactionTagFilterType `form:"tag_filter_type" binding:"min=0,max=3"`
Keyword string `form:"keyword"`
UseTransactionTimezone bool `form:"use_transaction_timezone"`
}
+12 -2
View File
@@ -1421,7 +1421,7 @@ func (s *TransactionService) GetAccountsTotalIncomeAndExpense(c core.Context, ui
}
// GetAccountsAndCategoriesTotalIncomeAndExpense returns the every accounts and categories total income and expense amount by specific date range
func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c core.Context, uid int64, startUnixTime int64, endUnixTime int64, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, utcOffset int16, useTransactionTimezone bool) ([]*models.Transaction, error) {
func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c core.Context, uid int64, startUnixTime int64, endUnixTime int64, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) ([]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -1469,6 +1469,11 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
finalConditionParams = append(finalConditionParams, maxTransactionTime)
}
if keyword != "" {
finalCondition = finalCondition + " AND comment LIKE ?"
finalConditionParams = append(finalConditionParams, "%%"+keyword+"%%")
}
sess := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagIds, noTags, tagFilterType)
@@ -1530,7 +1535,7 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
}
// GetAccountsAndCategoriesMonthlyIncomeAndExpense returns the every accounts monthly income and expense amount by specific date range
func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c core.Context, uid int64, startYear int32, startMonth int32, endYear int32, endMonth int32, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, utcOffset int16, useTransactionTimezone bool) (map[int32][]*models.Transaction, error) {
func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c core.Context, uid int64, startYear int32, startMonth int32, endYear int32, endMonth int32, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) (map[int32][]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -1583,6 +1588,11 @@ func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c c
finalConditionParams = append(finalConditionParams, maxTransactionTime)
}
if keyword != "" {
finalCondition = finalCondition + " AND comment LIKE ?"
finalConditionParams = append(finalConditionParams, "%%"+keyword+"%%")
}
sess := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagIds, noTags, tagFilterType)
+8
View File
@@ -432,6 +432,10 @@ export default {
queryParams.push(`tag_filter_type=${req.tagFilterType}`);
}
if (req.keyword) {
queryParams.push(`keyword=${encodeURIComponent(req.keyword)}`);
}
return axios.get<ApiResponse<TransactionStatisticResponse>>(`v1/transactions/statistics.json?use_transaction_timezone=${req.useTransactionTimezone}` + (queryParams.length ? '&' + queryParams.join('&') : ''));
},
getTransactionStatisticsTrends: (req: TransactionStatisticTrendsRequest): ApiResponsePromise<TransactionStatisticTrendsResponseItem[]> => {
@@ -453,6 +457,10 @@ export default {
queryParams.push(`tag_filter_type=${req.tagFilterType}`);
}
if (req.keyword) {
queryParams.push(`keyword=${encodeURIComponent(req.keyword)}`);
}
return axios.get<ApiResponse<TransactionStatisticTrendsResponseItem[]>>(`v1/transactions/statistics/trends.json?use_transaction_timezone=${req.useTransactionTimezone}` + (queryParams.length ? '&' + queryParams.join('&') : ''));
},
getTransactionAmounts: (params: TransactionAmountsRequestParams): ApiResponsePromise<TransactionAmountsResponse> => {
+32
View File
@@ -249,6 +249,37 @@ export function useI18nUIComponents() {
});
}
function showPrompt(message: string, currentValue?: string, confirmCallback?: (value: string, dialog: Dialog.Dialog, e: Event) => void, cancelCallback?: (value: string, dialog: Dialog.Dialog, e: Event) => void): void {
f7ready((f7) => {
f7.dialog.create({
title: tt('global.app.title'),
text: tt(message),
content: `<div class="dialog-input-field input"><input type="text" class="dialog-input" value="${currentValue || ''}"></div>`,
animate: isEnableAnimate(),
buttons: [
{
text: tt('Cancel'),
onClick: (dialog, event) => {
if (cancelCallback) {
const inputValue = dialog.$el.find('.dialog-input').val();
cancelCallback(inputValue, dialog, event);
}
}
},
{
text: tt('OK'),
onClick: (dialog, event) => {
if (confirmCallback) {
const inputValue = dialog.$el.find('.dialog-input').val();
confirmCallback(inputValue, dialog, event);
}
}
}
]
}).open();
});
}
function showToast(message: string, timeout?: number): void {
f7ready((f7) => {
f7.toast.create({
@@ -262,6 +293,7 @@ export function useI18nUIComponents() {
return {
showAlert: showAlert,
showConfirm: showConfirm,
showPrompt: showPrompt,
showToast: showToast,
routeBackOnError
}
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Konten filtern",
"Filter Transaction Categories": "Transaktionskategorien filtern",
"Filter Transaction Tags": "Transaktions-Tags filtern",
"Filter transaction description": "Filter transaction description",
"User Settings": "Benutzereinstellungen",
"User Profile": "Benutzerprofil",
"Language": "Sprache",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Filter Accounts",
"Filter Transaction Categories": "Filter Transaction Categories",
"Filter Transaction Tags": "Filter Transaction Tags",
"Filter transaction description": "Filter transaction description",
"User Settings": "User Settings",
"User Profile": "User Profile",
"Language": "Language",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Filtrar cuentas",
"Filter Transaction Categories": "Filtrar categorías de transacciones",
"Filter Transaction Tags": "Filtrar etiquetas de transacciones",
"Filter transaction description": "Filter transaction description",
"User Settings": "Configuración de usuario",
"User Profile": "Perfil de usuario",
"Language": "Idioma",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Filtra conti",
"Filter Transaction Categories": "Filtra categorie transazione",
"Filter Transaction Tags": "Filtra tag transazione",
"Filter transaction description": "Filter transaction description",
"User Settings": "Impostazioni utente",
"User Profile": "Profilo utente",
"Language": "Lingua",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "口座で絞り込み",
"Filter Transaction Categories": "取引カテゴリで絞り込み",
"Filter Transaction Tags": "取引タグで絞り込み",
"Filter transaction description": "Filter transaction description",
"User Settings": "ユーザー設定",
"User Profile": "ユーザープロフィール",
"Language": "言語",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Filtrar Contas",
"Filter Transaction Categories": "Filtrar Categorias de Transações",
"Filter Transaction Tags": "Filtrar Tags de Transações",
"Filter transaction description": "Filter transaction description",
"User Settings": "Configurações do Usuário",
"User Profile": "Perfil do Usuário",
"Language": "Idioma",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Фильтровать счета",
"Filter Transaction Categories": "Фильтровать категории транзакций",
"Filter Transaction Tags": "Фильтровать теги транзакций",
"Filter transaction description": "Filter transaction description",
"User Settings": "Настройки пользователя",
"User Profile": "Профиль пользователя",
"Language": "Язык",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Фільтрувати рахунки",
"Filter Transaction Categories": "Фільтрувати категорії транзакцій",
"Filter Transaction Tags": "Фільтрувати теги транзакцій",
"Filter transaction description": "Filter transaction description",
"User Settings": "Налаштування користувача",
"User Profile": "Профіль користувача",
"Language": "Мова",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "Lọc tài khoản",
"Filter Transaction Categories": "Lọc danh mục giao dịch",
"Filter Transaction Tags": "Lọc thẻ giao dịch",
"Filter transaction description": "Filter transaction description",
"User Settings": "Cài đặt người dùng",
"User Profile": "Hồ sơ người dùng",
"Language": "Ngôn ngữ",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "过滤账户",
"Filter Transaction Categories": "过滤交易类型",
"Filter Transaction Tags": "过滤交易标签",
"Filter transaction description": "过滤交易描述",
"User Settings": "用户设置",
"User Profile": "用户信息",
"Language": "语言",
+1
View File
@@ -1851,6 +1851,7 @@
"Filter Accounts": "篩選帳戶",
"Filter Transaction Categories": "篩選交易類型",
"Filter Transaction Tags": "篩選交易標籤",
"Filter transaction description": "篩選交易描述",
"User Settings": "使用者設定",
"User Profile": "使用者資料",
"Language": "語言",
+2
View File
@@ -548,6 +548,7 @@ export interface TransactionStatisticRequest {
readonly endTime: number;
readonly tagIds: string;
readonly tagFilterType: number;
readonly keyword: string;
readonly useTransactionTimezone: boolean;
}
@@ -559,6 +560,7 @@ export interface YearMonthRangeRequest {
export interface TransactionStatisticTrendsRequest extends YearMonthRangeRequest {
readonly tagIds: string;
readonly tagFilterType: number;
readonly keyword: string;
readonly useTransactionTimezone: boolean;
}
+1
View File
@@ -131,6 +131,7 @@ const router = createRouter({
initFilterCategoryIds: route.query['filterCategoryIds'],
initTagIds: route.query['tagIds'],
initTagFilterType: route.query['tagFilterType'],
initKeyword: route.query['keyword'],
initSortingType: route.query['sortingType'],
initTrendDateAggregationType: route.query['trendDateAggregationType']
})
+25
View File
@@ -124,6 +124,7 @@ export interface TransactionStatisticsPartialFilter {
filterCategoryIds?: Record<string, boolean>;
tagIds?: string;
tagFilterType?: number;
keyword?: string;
sortingType?: number;
}
@@ -141,6 +142,7 @@ export interface TransactionStatisticsFilter extends TransactionStatisticsPartia
filterCategoryIds: Record<string, boolean>;
tagIds: string;
tagFilterType: number;
keyword: string;
sortingType: number;
}
@@ -165,6 +167,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
filterCategoryIds: {},
tagIds: '',
tagFilterType: TransactionTagFilterType.Default.type,
keyword: '',
sortingType: ChartSortingType.Default.type
});
@@ -693,6 +696,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
transactionStatisticsFilter.value.filterCategoryIds = {};
transactionStatisticsFilter.value.tagIds = '';
transactionStatisticsFilter.value.tagFilterType = TransactionTagFilterType.Default.type;
transactionStatisticsFilter.value.keyword = '';
transactionCategoryStatisticsData.value = null;
transactionCategoryTrendsData.value = [];
transactionStatisticsStateInvalid.value = true;
@@ -825,6 +829,12 @@ export const useStatisticsStore = defineStore('statistics', () => {
transactionStatisticsFilter.value.tagFilterType = TransactionTagFilterType.Default.type;
}
if (filter && isString(filter.keyword)) {
transactionStatisticsFilter.value.keyword = filter.keyword;
} else {
transactionStatisticsFilter.value.keyword = '';
}
if (filter && isInteger(filter.sortingType)) {
transactionStatisticsFilter.value.sortingType = filter.sortingType;
} else {
@@ -904,6 +914,11 @@ export const useStatisticsStore = defineStore('statistics', () => {
changed = true;
}
if (filter && isString(filter.keyword) && transactionStatisticsFilter.value.keyword !== filter.keyword) {
transactionStatisticsFilter.value.keyword = filter.keyword;
changed = true;
}
if (filter && isInteger(filter.sortingType) && transactionStatisticsFilter.value.sortingType !== filter.sortingType) {
transactionStatisticsFilter.value.sortingType = filter.sortingType;
changed = true;
@@ -964,6 +979,10 @@ export const useStatisticsStore = defineStore('statistics', () => {
querys.push('tagFilterType=' + transactionStatisticsFilter.value.tagFilterType);
}
if (transactionStatisticsFilter.value.keyword) {
querys.push('keyword=' + encodeURIComponent(transactionStatisticsFilter.value.keyword));
}
querys.push('sortingType=' + transactionStatisticsFilter.value.sortingType);
return querys.join('&');
@@ -1020,6 +1039,10 @@ export const useStatisticsStore = defineStore('statistics', () => {
querys.push('tagFilterType=' + transactionStatisticsFilter.value.tagFilterType);
}
if (transactionStatisticsFilter.value.keyword) {
querys.push('keyword=' + encodeURIComponent(transactionStatisticsFilter.value.keyword));
}
if (analysisType === StatisticsAnalysisType.CategoricalAnalysis
&& transactionStatisticsFilter.value.chartDataType !== ChartDataType.AccountTotalAssets.type
&& transactionStatisticsFilter.value.chartDataType !== ChartDataType.AccountTotalLiabilities.type) {
@@ -1045,6 +1068,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
endTime: transactionStatisticsFilter.value.categoricalChartEndTime,
tagIds: transactionStatisticsFilter.value.tagIds,
tagFilterType: transactionStatisticsFilter.value.tagFilterType,
keyword: transactionStatisticsFilter.value.keyword,
useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType === TimezoneTypeForStatistics.TransactionTimezone.type
}).then(response => {
const data = response.data;
@@ -1087,6 +1111,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
endYearMonth: transactionStatisticsFilter.value.trendChartEndYearMonth,
tagIds: transactionStatisticsFilter.value.tagIds,
tagFilterType: transactionStatisticsFilter.value.tagFilterType,
keyword: transactionStatisticsFilter.value.keyword,
useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType === TimezoneTypeForStatistics.TransactionTimezone.type
}).then(response => {
const data = response.data;
@@ -113,6 +113,16 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<div class="transaction-keyword-filter ml-2">
<v-text-field density="compact" :disabled="loading"
:prepend-inner-icon="mdiMagnify"
:append-inner-icon="filterKeyword !== query.keyword ? mdiCheck : undefined"
:placeholder="tt('Filter transaction description')"
v-model="filterKeyword"
@click:append-inner="setKeywordFilter(filterKeyword)"
@keyup.enter="setKeywordFilter(filterKeyword)"
/>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
@@ -383,6 +393,7 @@ import {
mdiCalendarRangeOutline,
mdiRefresh,
mdiSquareRounded,
mdiMagnify,
mdiMenu,
mdiFilterOutline,
mdiFilterCogOutline,
@@ -405,6 +416,7 @@ interface TransactionStatisticsProps {
initFilterCategoryIds?: string,
initTagIds?: string,
initTagFilterType?: string,
initKeyword?: string;
initSortingType?: string,
initTrendDateAggregationType?: string
}
@@ -454,6 +466,7 @@ const exportDialog = useTemplateRef<ExportDialogType>('exportDialog');
const activeTab = ref<string>('statisticsPage');
const initing = ref<boolean>(true);
const filterKeyword = ref<string>('');
const alwaysShowNav = ref<boolean>(display.mdAndUp.value);
const showNav = ref<boolean>(display.mdAndUp.value);
const showCustomDateRangeDialog = ref<boolean>(false);
@@ -551,9 +564,12 @@ function init(initProps: TransactionStatisticsProps): void {
filterCategoryIds: initProps.initFilterCategoryIds ? arrayItemToObjectField(initProps.initFilterCategoryIds.split(','), true) : {},
tagIds: initProps.initTagIds,
tagFilterType: initProps.initTagFilterType && parseInt(initProps.initTagFilterType) >= 0 ? parseInt(initProps.initTagFilterType) : undefined,
keyword: initProps.initKeyword,
sortingType: initProps.initSortingType ? parseInt(initProps.initSortingType) : undefined
};
filterKeyword.value = filter.keyword || '';
if (initProps.initAnalysisType === StatisticsAnalysisType.CategoricalAnalysis.toString()) {
filter.categoricalChartType = initProps.initChartType ? parseInt(initProps.initChartType) : undefined;
filter.categoricalChartDateType = initProps.initChartDateType ? parseInt(initProps.initChartDateType) : undefined;
@@ -904,6 +920,30 @@ function setTagFilter(changed: boolean): void {
}
}
function setKeywordFilter(keyword: string): void {
if (query.value.keyword === keyword) {
return;
}
let changed = false;
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({
keyword: keyword
});
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({
keyword: keyword
});
}
if (changed) {
loading.value = true;
statisticsStore.updateTransactionStatisticsInvalidState(true);
router.push(getFilterLinkUrl());
}
}
function exportResults(): void {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis && categoricalAnalysisData.value && categoricalAnalysisData.value.items) {
exportDialog.value?.open({
@@ -954,6 +994,7 @@ onBeforeRouteUpdate((to) => {
initFilterCategoryIds: (to.query['filterCategoryIds'] as string | null) || undefined,
initTagIds: (to.query['tagIds'] as string | null) || undefined,
initTagFilterType: (to.query['tagFilterType'] as string | null) || undefined,
initKeyword: (to.query['keyword'] as string | null) || undefined,
initSortingType: (to.query['sortingType'] as string | null) || undefined,
initTrendDateAggregationType: (to.query['trendDateAggregationType'] as string | null) || undefined
});
@@ -313,6 +313,10 @@
<f7-actions-button @click="filterCategories">{{ tt('Filter Transaction Categories') }}</f7-actions-button>
<f7-actions-button @click="filterTags">{{ tt('Filter Transaction Tags') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-label v-if="query.keyword">{{ query.keyword }}</f7-actions-label>
<f7-actions-button @click="filterDescription">{{ tt('Filter transaction description') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-button @click="settings">{{ tt('Settings') }}</f7-actions-button>
</f7-actions-group>
@@ -360,7 +364,7 @@ const props = defineProps<{
}>();
const { tt, getAllCategoricalChartTypes, formatPercent } = useI18n();
const { showToast, routeBackOnError } = useI18nUIComponents();
const { showPrompt, showToast, routeBackOnError } = useI18nUIComponents();
const {
loading,
@@ -697,6 +701,30 @@ function filterTags(): void {
props.f7router.navigate('/settings/filter/tag?type=statisticsCurrent');
}
function filterDescription(): void {
showPrompt('Filter transaction description', query.value.keyword, value => {
if (query.value.keyword === value) {
return;
}
let changed = false;
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({
keyword: value
});
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({
keyword: value
});
}
if (changed) {
reload();
}
});
}
function settings(): void {
props.f7router.navigate('/statistic/settings');
}
+2 -1
View File
@@ -941,7 +941,8 @@ function init(): void {
categoryIds: initQuery['categoryIds'],
accountIds: initQuery['accountIds'],
tagIds: initQuery['tagIds'],
tagFilterType: initQuery['tagFilterType'] && parseInt(initQuery['tagFilterType']) >= 0 ? parseInt(initQuery['tagFilterType']) : undefined
tagFilterType: initQuery['tagFilterType'] && parseInt(initQuery['tagFilterType']) >= 0 ? parseInt(initQuery['tagFilterType']) : undefined,
keyword: initQuery['keyword']
});
reload();