From 563bef69cf63ca34414bd008045d04373e7ffdd4 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Mon, 11 May 2026 00:25:55 +0800 Subject: [PATCH] add transaction gallery mode in transaction list page --- pkg/api/data_managements.go | 2 +- pkg/api/transactions.go | 10 +- pkg/mcp/query_transactions_tool_handler.go | 4 +- pkg/models/transaction.go | 98 ++++++------ pkg/services/transactions.go | 34 ++-- src/components/mobile/ImageBox.vue | 97 +++++++++++ src/lib/services.ts | 4 +- src/lib/transaction.ts | 12 +- src/locales/de.json | 1 + src/locales/en.json | 1 + src/locales/es.json | 1 + src/locales/fr.json | 1 + src/locales/it.json | 1 + src/locales/ja.json | 1 + src/locales/kn.json | 1 + src/locales/ko.json | 1 + src/locales/nl.json | 1 + src/locales/pt_BR.json | 1 + src/locales/ru.json | 1 + src/locales/sl.json | 1 + src/locales/ta.json | 1 + src/locales/th.json | 1 + src/locales/tr.json | 1 + src/locales/uk.json | 1 + src/locales/vi.json | 1 + src/locales/zh_Hans.json | 1 + src/locales/zh_Hant.json | 1 + src/mobile-main.ts | 2 + src/models/transaction.ts | 4 + src/stores/transaction.ts | 10 +- .../transactions/TransactionListPageBase.ts | 7 + src/views/desktop/transactions/ListPage.vue | 87 +++++++++- src/views/mobile/transactions/ListPage.vue | 150 ++++++++++++++++-- 33 files changed, 453 insertions(+), 87 deletions(-) create mode 100644 src/components/mobile/ImageBox.vue diff --git a/pkg/api/data_managements.go b/pkg/api/data_managements.go index 254af6f8..a98113dc 100644 --- a/pkg/api/data_managements.go +++ b/pkg/api/data_managements.go @@ -419,7 +419,7 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType minTransactionTime = utils.GetMinTransactionTimeFromUnixTime(exportTransactionDataReq.MinTime) } - allTransactions, err := a.transactions.GetAllSpecifiedTransactions(c, uid, maxTransactionTime, minTransactionTime, exportTransactionDataReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, exportTransactionDataReq.AmountFilter, exportTransactionDataReq.Keyword, pageCountForDataExport, true) + allTransactions, err := a.transactions.GetAllSpecifiedTransactions(c, uid, maxTransactionTime, minTransactionTime, exportTransactionDataReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, exportTransactionDataReq.AmountFilter, exportTransactionDataReq.Keyword, false, pageCountForDataExport, true) if err != nil { log.Errorf(c, "[data_managements.getExportedFileContent] failed to all transactions user \"uid:%d\", because %s", uid, err.Error()) diff --git a/pkg/api/transactions.go b/pkg/api/transactions.go index b0cb6697..5ac6fbdb 100644 --- a/pkg/api/transactions.go +++ b/pkg/api/transactions.go @@ -97,7 +97,7 @@ func (a *TransactionsApi) TransactionCountHandler(c *core.WebContext) (any, *err } } - totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionCountReq.AmountFilter, transactionCountReq.Keyword) + totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionCountReq.AmountFilter, transactionCountReq.Keyword, transactionCountReq.MustHavePictures) if err != nil { log.Errorf(c, "[transactions.TransactionCountHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error()) @@ -168,7 +168,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.WebContext) (any, *errs var totalCount int64 if transactionListReq.WithCount { - totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword) + totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.MustHavePictures) if err != nil { log.Errorf(c, "[transactions.TransactionListHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error()) @@ -176,7 +176,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.WebContext) (any, *errs } } - transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.Page, transactionListReq.Count, true, true) + transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.MustHavePictures, transactionListReq.Page, transactionListReq.Count, true, true) if err != nil { log.Errorf(c, "[transactions.TransactionListHandler] failed to get transactions earlier than \"%d\" for user \"uid:%d\", because %s", transactionListReq.MaxTime, uid, err.Error()) @@ -276,7 +276,7 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.WebContext) (any, } } - transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword) + transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.MustHavePictures) if err != nil { log.Errorf(c, "[transactions.TransactionMonthListHandler] failed to get transactions in month \"%d-%d\" for user \"uid:%d\", because %s", transactionListReq.Year, transactionListReq.Month, uid, err.Error()) @@ -371,7 +371,7 @@ func (a *TransactionsApi) TransactionListAllHandler(c *core.WebContext) (any, *e minTransactionTime = utils.GetMinTransactionTimeFromUnixTime(transactionAllListReq.StartTime) } - allTransactions, err := a.transactions.GetAllSpecifiedTransactions(c, uid, maxTransactionTime, minTransactionTime, transactionAllListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionAllListReq.AmountFilter, transactionAllListReq.Keyword, pageCountForDataExport, true) + allTransactions, err := a.transactions.GetAllSpecifiedTransactions(c, uid, maxTransactionTime, minTransactionTime, transactionAllListReq.Type, allCategoryIds, allAccountIds, tagFilters, noTags, transactionAllListReq.AmountFilter, transactionAllListReq.Keyword, transactionAllListReq.MustHavePictures, pageCountForDataExport, true) if err != nil { log.Errorf(c, "[transactions.TransactionListAllHandler] failed to get all transactions for user \"uid:%d\", because %s", uid, err.Error()) diff --git a/pkg/mcp/query_transactions_tool_handler.go b/pkg/mcp/query_transactions_tool_handler.go index ed9bdc40..25094694 100644 --- a/pkg/mcp/query_transactions_tool_handler.go +++ b/pkg/mcp/query_transactions_tool_handler.go @@ -153,14 +153,14 @@ func (h *mcpQueryTransactionsToolHandler) Handle(c *core.WebContext, callToolReq } } - totalCount, err := services.GetTransactionService().GetTransactionCount(c, uid, maxTransactionTime, minTransactionTime, transactionType, filterCategoryIds, filterAccountIds, nil, false, "", queryTransactionsRequest.Keyword) + totalCount, err := services.GetTransactionService().GetTransactionCount(c, uid, maxTransactionTime, minTransactionTime, transactionType, filterCategoryIds, filterAccountIds, nil, false, "", queryTransactionsRequest.Keyword, false) if err != nil { log.Errorf(c, "[transactions.TransactionListHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error()) return nil, nil, err } - transactions, err := services.GetTransactionService().GetTransactionsByMaxTime(c, uid, maxTransactionTime, minTransactionTime, transactionType, filterCategoryIds, filterAccountIds, nil, false, "", queryTransactionsRequest.Keyword, queryTransactionsRequest.Page, queryTransactionsRequest.Count, false, true) + transactions, err := services.GetTransactionService().GetTransactionsByMaxTime(c, uid, maxTransactionTime, minTransactionTime, transactionType, filterCategoryIds, filterAccountIds, nil, false, "", queryTransactionsRequest.Keyword, false, queryTransactionsRequest.Page, queryTransactionsRequest.Count, false, true) structuredResponse, response, err := h.createNewMCPQueryTransactionsResponse(c, &queryTransactionsRequest, transactions, totalCount, services.GetAccountService().GetAccountMapByList(allAccounts), services.GetTransactionCategoryService().GetCategoryMapByList(allCategories)) if err != nil { diff --git a/pkg/models/transaction.go b/pkg/models/transaction.go index fccfc826..8fe486a5 100644 --- a/pkg/models/transaction.go +++ b/pkg/models/transaction.go @@ -210,65 +210,69 @@ type TransactionTagFilter struct { // TransactionCountRequest represents transaction count request type TransactionCountRequest struct { - Type TransactionType `form:"type" binding:"min=0,max=4"` - CategoryIds string `form:"category_ids"` - AccountIds string `form:"account_ids"` - TagFilter string `form:"tag_filter" binding:"validTagFilter"` - AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` - Keyword string `form:"keyword"` - MaxTime int64 `form:"max_time" binding:"min=0"` // Transaction time sequence id - MinTime int64 `form:"min_time" binding:"min=0"` // Transaction time sequence id + Type TransactionType `form:"type" binding:"min=0,max=4"` + CategoryIds string `form:"category_ids"` + AccountIds string `form:"account_ids"` + TagFilter string `form:"tag_filter" binding:"validTagFilter"` + AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` + Keyword string `form:"keyword"` + MustHavePictures bool `form:"must_have_pictures"` + MaxTime int64 `form:"max_time" binding:"min=0"` // Transaction time sequence id + MinTime int64 `form:"min_time" binding:"min=0"` // Transaction time sequence id } // TransactionListByMaxTimeRequest represents all parameters of transaction listing by max time request type TransactionListByMaxTimeRequest struct { - Type TransactionType `form:"type" binding:"min=0,max=4"` - CategoryIds string `form:"category_ids"` - AccountIds string `form:"account_ids"` - TagFilter string `form:"tag_filter" binding:"validTagFilter"` - AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` - Keyword string `form:"keyword"` - MaxTime int64 `form:"max_time" binding:"min=0"` // Transaction time sequence id - MinTime int64 `form:"min_time" binding:"min=0"` // Transaction time sequence id - Page int32 `form:"page" binding:"min=0"` - Count int32 `form:"count" binding:"required,min=1,max=50"` - WithCount bool `form:"with_count"` - WithPictures bool `form:"with_pictures"` - TrimAccount bool `form:"trim_account"` - TrimCategory bool `form:"trim_category"` - TrimTag bool `form:"trim_tag"` + Type TransactionType `form:"type" binding:"min=0,max=4"` + CategoryIds string `form:"category_ids"` + AccountIds string `form:"account_ids"` + TagFilter string `form:"tag_filter" binding:"validTagFilter"` + AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` + Keyword string `form:"keyword"` + MustHavePictures bool `form:"must_have_pictures"` + MaxTime int64 `form:"max_time" binding:"min=0"` // Transaction time sequence id + MinTime int64 `form:"min_time" binding:"min=0"` // Transaction time sequence id + Page int32 `form:"page" binding:"min=0"` + Count int32 `form:"count" binding:"required,min=1,max=50"` + WithCount bool `form:"with_count"` + WithPictures bool `form:"with_pictures"` + TrimAccount bool `form:"trim_account"` + TrimCategory bool `form:"trim_category"` + TrimTag bool `form:"trim_tag"` } // TransactionListInMonthByPageRequest represents all parameters of transaction listing by month request type TransactionListInMonthByPageRequest struct { - Year int32 `form:"year" binding:"required,min=1"` - Month int32 `form:"month" binding:"required,min=1"` - Type TransactionType `form:"type" binding:"min=0,max=4"` - CategoryIds string `form:"category_ids"` - AccountIds string `form:"account_ids"` - TagFilter string `form:"tag_filter" binding:"validTagFilter"` - AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` - Keyword string `form:"keyword"` - WithPictures bool `form:"with_pictures"` - TrimAccount bool `form:"trim_account"` - TrimCategory bool `form:"trim_category"` - TrimTag bool `form:"trim_tag"` + Year int32 `form:"year" binding:"required,min=1"` + Month int32 `form:"month" binding:"required,min=1"` + Type TransactionType `form:"type" binding:"min=0,max=4"` + CategoryIds string `form:"category_ids"` + AccountIds string `form:"account_ids"` + TagFilter string `form:"tag_filter" binding:"validTagFilter"` + AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` + Keyword string `form:"keyword"` + MustHavePictures bool `form:"must_have_pictures"` + WithPictures bool `form:"with_pictures"` + TrimAccount bool `form:"trim_account"` + TrimCategory bool `form:"trim_category"` + TrimTag bool `form:"trim_tag"` } // TransactionAllListRequest represents all parameters of all transaction listing request type TransactionAllListRequest struct { - Type TransactionType `form:"type" binding:"min=0,max=4"` - CategoryIds string `form:"category_ids"` - AccountIds string `form:"account_ids"` - TagFilter string `form:"tag_filter" binding:"validTagFilter"` - AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` - Keyword string `form:"keyword"` - StartTime int64 `form:"start_time" binding:"min=0"` - EndTime int64 `form:"end_time" binding:"min=0"` - WithPictures bool `form:"with_pictures"` - TrimAccount bool `form:"trim_account"` - TrimCategory bool `form:"trim_category"` - TrimTag bool `form:"trim_tag"` + Type TransactionType `form:"type" binding:"min=0,max=4"` + CategoryIds string `form:"category_ids"` + AccountIds string `form:"account_ids"` + TagFilter string `form:"tag_filter" binding:"validTagFilter"` + AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` + Keyword string `form:"keyword"` + MustHavePictures bool `form:"must_have_pictures"` + StartTime int64 `form:"start_time" binding:"min=0"` + EndTime int64 `form:"end_time" binding:"min=0"` + WithPictures bool `form:"with_pictures"` + TrimAccount bool `form:"trim_account"` + TrimCategory bool `form:"trim_category"` + TrimTag bool `form:"trim_tag"` } // TransactionReconciliationStatementRequest represents all parameters of transaction reconciliation statement request diff --git a/pkg/services/transactions.go b/pkg/services/transactions.go index bf7e130a..413db0ab 100644 --- a/pkg/services/transactions.go +++ b/pkg/services/transactions.go @@ -76,11 +76,11 @@ func (s *TransactionService) GetAllTransactions(c core.Context, uid int64, pageC // GetAllTransactionsByMaxTime returns all transactions before given time func (s *TransactionService) GetAllTransactionsByMaxTime(c core.Context, uid int64, maxTransactionTime int64, count int32, noDuplicated bool) ([]*models.Transaction, error) { - return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, "", "", 1, count, false, noDuplicated) + return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, "", "", false, 1, count, false, noDuplicated) } // GetAllSpecifiedTransactions returns all transactions that match given conditions -func (s *TransactionService) GetAllSpecifiedTransactions(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, pageCount int32, noDuplicated bool) ([]*models.Transaction, error) { +func (s *TransactionService) GetAllSpecifiedTransactions(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, mustHavePictures bool, pageCount int32, noDuplicated bool) ([]*models.Transaction, error) { if maxTransactionTime <= 0 { maxTransactionTime = utils.GetMaxTransactionTimeFromUnixTime(time.Now().Unix()) } @@ -88,7 +88,7 @@ func (s *TransactionService) GetAllSpecifiedTransactions(c core.Context, uid int var allTransactions []*models.Transaction for maxTransactionTime > 0 { - transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, tagFilters, noTags, amountFilter, keyword, 1, pageCount, false, noDuplicated) + transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, tagFilters, noTags, amountFilter, keyword, mustHavePictures, 1, pageCount, false, noDuplicated) if err != nil { return nil, err @@ -116,7 +116,7 @@ func (s *TransactionService) GetAllTransactionsInOneAccountWithAccountBalanceByM var allTransactions []*models.Transaction for maxTransactionTime > 0 { - transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, []int64{accountId}, nil, false, "", "", 1, pageCount, false, true) + transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, []int64{accountId}, nil, false, "", "", false, 1, pageCount, false, true) if err != nil { return nil, 0, 0, 0, 0, err @@ -206,7 +206,7 @@ func (s *TransactionService) GetAllAccountsDailyOpeningAndClosingBalance(c core. var allTransactions []*models.Transaction for maxTransactionTime > 0 { - transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, "", "", 1, pageCountForLoadTransactionAmounts, false, false) + transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, "", "", false, 1, pageCountForLoadTransactionAmounts, false, false) if err != nil { return nil, err @@ -323,7 +323,7 @@ func (s *TransactionService) GetAllAccountsDailyOpeningAndClosingBalance(c core. } // GetTransactionsByMaxTime returns transactions before given time -func (s *TransactionService) GetTransactionsByMaxTime(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) { +func (s *TransactionService) GetTransactionsByMaxTime(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, mustHavePictures bool, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } @@ -360,6 +360,7 @@ func (s *TransactionService) GetTransactionsByMaxTime(c core.Context, uid int64, condition, conditionParams := s.buildTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionDbType, categoryIds, accountIds, tagFilters, amountFilter, keyword, noDuplicated) sess := s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...) sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagFilters, noTags) + sess = s.appendFilterPicturesConditionToQuery(sess, uid, mustHavePictures) err = sess.Limit(int(actualCount), int(count*(page-1))).OrderBy("transaction_time desc").Find(&transactions) @@ -367,7 +368,7 @@ func (s *TransactionService) GetTransactionsByMaxTime(c core.Context, uid int64, } // GetTransactionsInMonthByPage returns all transactions in given year and month -func (s *TransactionService) GetTransactionsInMonthByPage(c core.Context, uid int64, year int32, month int32, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string) ([]*models.Transaction, error) { +func (s *TransactionService) GetTransactionsInMonthByPage(c core.Context, uid int64, year int32, month int32, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, mustHavePictures bool) ([]*models.Transaction, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } @@ -394,6 +395,7 @@ func (s *TransactionService) GetTransactionsInMonthByPage(c core.Context, uid in condition, conditionParams := s.buildTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionDbType, categoryIds, accountIds, tagFilters, amountFilter, keyword, true) sess := s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...) sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagFilters, noTags) + sess = s.appendFilterPicturesConditionToQuery(sess, uid, mustHavePictures) err = sess.OrderBy("transaction_time desc").Find(&transactions) @@ -452,11 +454,11 @@ func (s *TransactionService) GetTransactionsByTransactionIds(c core.Context, uid // GetAllTransactionCount returns total count of transactions func (s *TransactionService) GetAllTransactionCount(c core.Context, uid int64) (int64, error) { - return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, nil, false, "", "") + return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, nil, false, "", "", false) } // GetTransactionCount returns count of transactions -func (s *TransactionService) GetTransactionCount(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string) (int64, error) { +func (s *TransactionService) GetTransactionCount(c core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionType, categoryIds []int64, accountIds []int64, tagFilters []*models.TransactionTagFilter, noTags bool, amountFilter string, keyword string, mustHavePictures bool) (int64, error) { if uid <= 0 { return 0, errs.ErrUserIdInvalid } @@ -475,6 +477,7 @@ func (s *TransactionService) GetTransactionCount(c core.Context, uid int64, maxT condition, conditionParams := s.buildTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionDbType, categoryIds, accountIds, tagFilters, amountFilter, keyword, true) sess := s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...) sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagFilters, noTags) + sess = s.appendFilterPicturesConditionToQuery(sess, uid, mustHavePictures) return sess.Count(&models.Transaction{}) } @@ -1964,7 +1967,7 @@ func (s *TransactionService) DeleteAllTransactionsOfAccount(c core.Context, uid return errs.ErrAccountIdInvalid } - transactions, err := s.GetAllSpecifiedTransactions(c, uid, 0, 0, 0, nil, []int64{accountId}, nil, false, "", "", pageCount, true) + transactions, err := s.GetAllSpecifiedTransactions(c, uid, 0, 0, 0, nil, []int64{accountId}, nil, false, "", "", false, pageCount, true) if err != nil { return err @@ -2897,6 +2900,17 @@ func (s *TransactionService) appendFilterTagIdsConditionToQuery(sess *xorm.Sessi return sess } +func (s *TransactionService) appendFilterPicturesConditionToQuery(sess *xorm.Session, uid int64, mustHavePictures bool) *xorm.Session { + if !mustHavePictures { + return sess + } + + subQuery := builder.Select("transaction_id").From("transaction_picture_info").Where(builder.And(builder.Eq{"uid": uid}, builder.Eq{"deleted": false}, builder.Neq{"transaction_id": models.TransactionPictureNewPictureTransactionId})) + sess.And(builder.Or(builder.In("transaction_id", subQuery), builder.In("related_id", subQuery))) + + return sess +} + func (s *TransactionService) isAccountIdValid(transaction *models.Transaction) error { if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE { if transaction.RelatedAccountId != 0 && transaction.RelatedAccountId != transaction.AccountId { diff --git a/src/components/mobile/ImageBox.vue b/src/components/mobile/ImageBox.vue new file mode 100644 index 00000000..49ade100 --- /dev/null +++ b/src/components/mobile/ImageBox.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/lib/services.ts b/src/lib/services.ts index 141a6d37..41cf64be 100644 --- a/src/lib/services.ts +++ b/src/lib/services.ts @@ -526,13 +526,13 @@ export default { const tagFilter = encodeURIComponent(req.tagFilter); const amountFilter = encodeURIComponent(req.amountFilter); const keyword = encodeURIComponent(req.keyword); - return axios.get>(`v1/transactions/list.json?max_time=${req.maxTime}&min_time=${req.minTime}&type=${req.type}&category_ids=${req.categoryIds}&account_ids=${req.accountIds}&tag_filter=${tagFilter}&amount_filter=${amountFilter}&keyword=${keyword}&count=${req.count}&page=${req.page}&with_count=${req.withCount}&trim_account=true&trim_category=true&trim_tag=true`); + return axios.get>(`v1/transactions/list.json?max_time=${req.maxTime}&min_time=${req.minTime}&type=${req.type}&category_ids=${req.categoryIds}&account_ids=${req.accountIds}&tag_filter=${tagFilter}&amount_filter=${amountFilter}&keyword=${keyword}&must_have_pictures=${!!req.mustHavePictures}&count=${req.count}&page=${req.page}&with_count=${req.withCount}&with_pictures=${!!req.withPictures}&trim_account=true&trim_category=true&trim_tag=true`); }, getAllTransactionsByMonth: (req: TransactionListInMonthByPageRequest): ApiResponsePromise => { const tagFilter = encodeURIComponent(req.tagFilter); const amountFilter = encodeURIComponent(req.amountFilter); const keyword = encodeURIComponent(req.keyword); - return axios.get>(`v1/transactions/list/by_month.json?year=${req.year}&month=${req.month}&type=${req.type}&category_ids=${req.categoryIds}&account_ids=${req.accountIds}&tag_filter=${tagFilter}&amount_filter=${amountFilter}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`); + return axios.get>(`v1/transactions/list/by_month.json?year=${req.year}&month=${req.month}&type=${req.type}&category_ids=${req.categoryIds}&account_ids=${req.accountIds}&tag_filter=${tagFilter}&amount_filter=${amountFilter}&keyword=${keyword}&must_have_pictures=${!!req.mustHavePictures}&with_pictures=${!!req.withPictures}&trim_account=true&trim_category=true&trim_tag=true`); }, getAllTransactions: (req: TransactionAllListRequest): ApiResponsePromise => { return axios.get>(`v1/transactions/list/all.json?trim_account=true&with_pictures=${!!req.withPictures}&trim_category=true&trim_tag=true&start_time=${req.startTime}&end_time=${req.endTime}`); diff --git a/src/lib/transaction.ts b/src/lib/transaction.ts index 59a02dfd..cc2a5c4b 100644 --- a/src/lib/transaction.ts +++ b/src/lib/transaction.ts @@ -3,7 +3,7 @@ import { TransactionType } from '@/core/transaction.ts'; import { Account } from '@/models/account.ts'; import { TransactionCategory } from '@/models/transaction_category.ts'; import { TransactionTag } from '@/models/transaction_tag.ts'; -import { TransactionPicture } from '@/models/transaction_picture_info.ts'; +import { TransactionPicture, type TransactionPictureInfoBasicResponse } from '@/models/transaction_picture_info.ts'; import { Transaction } from '@/models/transaction.ts'; import { @@ -32,6 +32,16 @@ export interface SetTransactionOptions { comment?: string; } +export function* allTransactionPictures(transactions: Transaction[]): Iterable<[Transaction, TransactionPictureInfoBasicResponse]> { + for (const transaction of transactions) { + if (transaction.pictures) { + for (const pictureInfo of transaction.pictures) { + yield [transaction, pictureInfo]; + } + } + } +} + export function setTransactionModelByTransaction(transaction: Transaction, transaction2: Transaction | null | undefined, allCategories: Record, allCategoriesMap: Record, allVisibleAccounts: Account[], allAccountsMap: Record, allTagsMap: Record, defaultAccountId: string, options: SetTransactionOptions, setContextData: boolean): void { if (isDefined(options.time)) { transaction.time = options.time; diff --git a/src/locales/de.json b/src/locales/de.json index 97495dfc..993558b0 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1755,6 +1755,7 @@ "View Details": "Details anzeigen", "Transaction List": "Transaktionsliste", "Transaction Calendar": "Transaktionskalender", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Transaktionsdetails", "Statistics & Analysis": "Statistiken & Analysen", "Insights Explorer": "Daten-Explorer", diff --git a/src/locales/en.json b/src/locales/en.json index 49bccd47..9c791a26 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1755,6 +1755,7 @@ "View Details": "View Details", "Transaction List": "Transaction List", "Transaction Calendar": "Transaction Calendar", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Transaction Details", "Statistics & Analysis": "Statistics & Analysis", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/es.json b/src/locales/es.json index 11328694..fb56f641 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1755,6 +1755,7 @@ "View Details": "Ver Detalles", "Transaction List": "Listado de Transacciones", "Transaction Calendar": "Calendario de Transacciones", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Detalles", "Statistics & Analysis": "Estadísticas y Análisis", "Insights Explorer": "Explorador de Datos", diff --git a/src/locales/fr.json b/src/locales/fr.json index ff0e3457..45d4f8bc 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1755,6 +1755,7 @@ "View Details": "Voir les détails", "Transaction List": "Liste des transactions", "Transaction Calendar": "Calendrier des transactions", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Détails de la transaction", "Statistics & Analysis": "Statistiques et analyse", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/it.json b/src/locales/it.json index 4cf1e41d..74be971e 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1755,6 +1755,7 @@ "View Details": "Visualizza dettagli", "Transaction List": "Elenco transazioni", "Transaction Calendar": "Transaction Calendar", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Dettagli transazione", "Statistics & Analysis": "Statistiche e analisi", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/ja.json b/src/locales/ja.json index e2ca4e9d..1617aaa3 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1755,6 +1755,7 @@ "View Details": "詳細を表示", "Transaction List": "取引リスト", "Transaction Calendar": "Transaction Calendar", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "取引の詳細", "Statistics & Analysis": "統計と分析", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/kn.json b/src/locales/kn.json index 948b6597..fb73baac 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -1755,6 +1755,7 @@ "View Details": "ವಿವರಗಳನ್ನು ನೋಡಿ", "Transaction List": "ವಹಿವಾಟು ಪಟ್ಟಿ", "Transaction Calendar": "ವಹಿವಾಟು ಕ್ಯಾಲೆಂಡರ್", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "ವಹಿವಾಟಿನ ವಿವರಗಳು", "Statistics & Analysis": "ಸಂಖ್ಯಾಶಾಸ್ತ್ರ ಮತ್ತು ವಿಶ್ಲೇಷಣೆ", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/ko.json b/src/locales/ko.json index 29facf46..afc27c93 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1755,6 +1755,7 @@ "View Details": "세부사항 보기", "Transaction List": "거래 목록", "Transaction Calendar": "거래 달력", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "거래 세부사항", "Statistics & Analysis": "통계 및 분석", "Insights Explorer": "인사이트 탐색기", diff --git a/src/locales/nl.json b/src/locales/nl.json index fb23e139..5423bebb 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -1755,6 +1755,7 @@ "View Details": "Details bekijken", "Transaction List": "Transactielijst", "Transaction Calendar": "Transactiekalender", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Transactiedetails", "Statistics & Analysis": "Statistieken & Analyse", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 0f283599..6c3df344 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1755,6 +1755,7 @@ "View Details": "Ver Detalhes", "Transaction List": "Lista de Transações", "Transaction Calendar": "Calendário de Transações", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Detalhes da Transação", "Statistics & Analysis": "Estatísticas e Análise", "Insights Explorer": "Explorador de Insights", diff --git a/src/locales/ru.json b/src/locales/ru.json index f0ea192f..4052ce9b 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1755,6 +1755,7 @@ "View Details": "Просмотреть детали", "Transaction List": "Список транзакций", "Transaction Calendar": "Календарь транзакций", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Детали транзакции", "Statistics & Analysis": "Статистика и анализ", "Insights Explorer": "Исследователь идей", diff --git a/src/locales/sl.json b/src/locales/sl.json index 0d03b363..385790a2 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -1755,6 +1755,7 @@ "View Details": "Ogled podrobnosti", "Transaction List": "Seznam transakcij", "Transaction Calendar": "Koledar transakcij", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Podrobnosti transakcije", "Statistics & Analysis": "Statistika in analiza", "Insights Explorer": "Vpogledi in raziskovanje", diff --git a/src/locales/ta.json b/src/locales/ta.json index 6f23f088..96f76aa7 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -1755,6 +1755,7 @@ "View Details": "விவரங்களை பார்க்கவும்", "Transaction List": "பரிவர்த்தனை பட்டியல்", "Transaction Calendar": "பரிவர்த்தனை நாட்காட்டி", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "பரிவர்த்தனையின் விவரங்கள்", "Statistics & Analysis": "புள்ளியியல் மற்றும் பகுப்பாய்வு", "Insights Explorer": "நுண்ணறிவு ஆய்வுக்கருவி", diff --git a/src/locales/th.json b/src/locales/th.json index fe9af3ce..85715758 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -1755,6 +1755,7 @@ "View Details": "ดูรายละเอียด", "Transaction List": "รายการธุรกรรม", "Transaction Calendar": "ปฏิทินธุรกรรม", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "รายละเอียดธุรกรรม", "Statistics & Analysis": "สถิติ & การวิเคราะห์", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/tr.json b/src/locales/tr.json index 1ce495f3..a746deb7 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -1755,6 +1755,7 @@ "View Details": "Detayları Gör", "Transaction List": "İşlem Listesi", "Transaction Calendar": "İşlem Takvimi", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "İşlem Detayları", "Statistics & Analysis": "İstatistik & Analiz", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/uk.json b/src/locales/uk.json index 0d6cde9b..16a75024 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1755,6 +1755,7 @@ "View Details": "Переглянути деталі", "Transaction List": "Список транзакцій", "Transaction Calendar": "Transaction Calendar", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Деталі по транзакціях", "Statistics & Analysis": "Статистика та аналіз", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/vi.json b/src/locales/vi.json index 57785ddc..1ef42c66 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1755,6 +1755,7 @@ "View Details": "Xem chi tiết", "Transaction List": "Danh sách giao dịch", "Transaction Calendar": "Transaction Calendar", + "Transaction Gallery": "Transaction Gallery", "Transaction Details": "Chi tiết giao dịch", "Statistics & Analysis": "Thống kê & Phân tích", "Insights Explorer": "Insights Explorer", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index c0c85134..dc1c8c0a 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1755,6 +1755,7 @@ "View Details": "查看详情", "Transaction List": "交易列表", "Transaction Calendar": "交易日历", + "Transaction Gallery": "交易相册", "Transaction Details": "交易详情", "Statistics & Analysis": "统计分析", "Insights Explorer": "洞察探索", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 6ae8d58a..37d0536f 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1755,6 +1755,7 @@ "View Details": "查看詳情", "Transaction List": "交易清單", "Transaction Calendar": "交易日曆", + "Transaction Gallery": "交易相簿", "Transaction Details": "交易詳情", "Statistics & Analysis": "統計分析", "Insights Explorer": "洞察探索", diff --git a/src/mobile-main.ts b/src/mobile-main.ts index 0fc0177c..6c6f31a9 100644 --- a/src/mobile-main.ts +++ b/src/mobile-main.ts @@ -55,6 +55,7 @@ import MonthPicker from '@/components/common/MonthPicker.vue'; import TransactionCalendar from '@/components/common/TransactionCalendar.vue'; import ItemIcon from '@/components/mobile/ItemIcon.vue'; +import ImageBox from '@/components/mobile/ImageBox.vue'; import LanguageSelectButton from '@/components/mobile/LanguageSelectButton.vue'; import PieChart from '@/components/mobile/PieChart.vue'; import TrendsBarChart from '@/components/mobile/TrendsBarChart.vue'; @@ -150,6 +151,7 @@ app.component('MonthPicker', MonthPicker); app.component('TransactionCalendar', TransactionCalendar); app.component('ItemIcon', ItemIcon); +app.component('ImageBox', ImageBox); app.component('LanguageSelectButton', LanguageSelectButton); app.component('PieChart', PieChart); app.component('TrendsBarChart', TrendsBarChart); diff --git a/src/models/transaction.ts b/src/models/transaction.ts index 6c86426d..0802da3e 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -614,6 +614,8 @@ export interface TransactionListByMaxTimeRequest { readonly tagFilter: string; readonly amountFilter: string; readonly keyword: string; + readonly mustHavePictures?: boolean; + readonly withPictures?: boolean; } export interface TransactionListInMonthByPageRequest { @@ -625,6 +627,8 @@ export interface TransactionListInMonthByPageRequest { readonly tagFilter: string; readonly amountFilter: string; readonly keyword: string; + readonly mustHavePictures?: boolean; + readonly withPictures?: boolean; } export interface TransactionAllListRequest { diff --git a/src/stores/transaction.ts b/src/stores/transaction.ts index 76b77ad5..3cd37bea 100644 --- a/src/stores/transaction.ts +++ b/src/stores/transaction.ts @@ -827,7 +827,7 @@ export const useTransactionsStore = defineStore('transactions', () => { }; } - function loadTransactions({ reload, count, page, withCount, autoExpand, defaultCurrency }: { reload?: boolean, count?: number, page?: number, withCount?: boolean, autoExpand: boolean, defaultCurrency: string }): Promise { + function loadTransactions({ reload, count, page, mustHavePictures, withCount, withPictures, autoExpand, defaultCurrency }: { reload?: boolean, count?: number, page?: number, mustHavePictures?: boolean, withCount?: boolean, withPictures?: boolean, autoExpand: boolean, defaultCurrency: string }): Promise { let actualMaxTime = transactionsNextTimeId.value; if (reload && transactionsFilter.value.maxTime > 0) { @@ -843,6 +843,8 @@ export const useTransactionsStore = defineStore('transactions', () => { count: count || 50, page: page || 1, withCount: !!withCount, + withPictures: !!withPictures, + mustHavePictures: !!mustHavePictures, type: transactionsFilter.value.type, categoryIds: transactionsFilter.value.categoryIds, accountIds: transactionsFilter.value.accountIds, @@ -917,7 +919,7 @@ export const useTransactionsStore = defineStore('transactions', () => { }); } - function loadMonthlyAllTransactions({ year, month, autoExpand, defaultCurrency }: { year: number, month: number, autoExpand: boolean, defaultCurrency: string }): Promise { + function loadMonthlyAllTransactions({ year, month, mustHavePictures, withPictures, autoExpand, defaultCurrency }: { year: number, month: number, mustHavePictures?: boolean, withPictures?: boolean, autoExpand: boolean, defaultCurrency: string }): Promise { return new Promise((resolve, reject) => { services.getAllTransactionsByMonth({ year: year, @@ -927,7 +929,9 @@ export const useTransactionsStore = defineStore('transactions', () => { accountIds: transactionsFilter.value.accountIds, tagFilter: transactionsFilter.value.tagFilter, amountFilter: transactionsFilter.value.amountFilter, - keyword: transactionsFilter.value.keyword + keyword: transactionsFilter.value.keyword, + mustHavePictures: !!mustHavePictures, + withPictures: !!withPictures }).then(response => { const data = response.data; diff --git a/src/views/base/transactions/TransactionListPageBase.ts b/src/views/base/transactions/TransactionListPageBase.ts index c196e4e8..51eb9486 100644 --- a/src/views/base/transactions/TransactionListPageBase.ts +++ b/src/views/base/transactions/TransactionListPageBase.ts @@ -22,6 +22,7 @@ import type { TransactionCategory } from '@/models/transaction_category.ts'; import { TransactionTagGroup } from '@/models/transaction_tag_group.ts'; import type { TransactionTag } from '@/models/transaction_tag.ts'; import { type Transaction, TransactionTagFilter } from '@/models/transaction.ts'; +import type { TransactionPictureInfoBasicResponse } from '@/models/transaction_picture_info.ts'; import { getUtcOffsetByUtcOffsetMinutes, @@ -49,6 +50,7 @@ export class TransactionListPageType implements TypeAndName { public static readonly List = new TransactionListPageType(0, 'Transaction List'); public static readonly Calendar = new TransactionListPageType(1, 'Transaction Calendar'); + public static readonly Gallery = new TransactionListPageType(2, 'Transaction Gallery'); public static readonly Default = TransactionListPageType.List; @@ -401,6 +403,10 @@ export function useTransactionListPageBase() { } } + function getTransactionPictureUrl(pictureInfo?: TransactionPictureInfoBasicResponse | null): string | undefined { + return transactionsStore.getTransactionPictureUrl(pictureInfo); + } + return { // states pageType, @@ -458,5 +464,6 @@ export function useTransactionListPageBase() { getDisplayAmount, getDisplayMonthTotalAmount, getTransactionTypeName, + getTransactionPictureUrl }; } diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index a9aa3dbb..e1f296e7 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -31,7 +31,7 @@ v-model="queryType" /> -
+
{{ tt('Transactions Per Page') }} - + @@ -595,7 +595,53 @@ -
+ +
+ +
+ +
+ {{ tt('No transaction data') }} +
+ +
+
+
+ {{ getDisplayLongDate(transactions[0] as Transaction) }} + + {{ getWeekdayLongName((transactions[0] as Transaction).displayDayOfWeek as WeekDay) }} + +
+
+
+ + + + + +
+ +
+
+
+
+
+ +
@@ -681,6 +727,7 @@ import { type Year0BasedMonth, type LocalizedRecentMonthDateRange, type TimeRangeAndDateType, + type WeekDay, DateRangeScene, DateRange } from '@/core/datetime.ts'; @@ -720,6 +767,7 @@ import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts'; +import { allTransactionPictures } from '@/lib/transaction.ts'; import { isDataExportingEnabled, isDataImportingEnabled, isTransactionFromAIImageRecognitionEnabled } from '@/lib/server_settings.ts'; import { scrollToSelectedItem, startDownloadFile } from '@/lib/ui/common.ts'; import logger from '@/lib/logger.ts'; @@ -739,7 +787,8 @@ import { mdiArrowRight, mdiPound, mdiMagicStaff, - mdiTextBoxOutline + mdiTextBoxOutline, + mdiTextBoxEditOutline } from '@mdi/js'; interface TransactionListProps { @@ -830,6 +879,7 @@ const { getDisplayAmount, getDisplayMonthTotalAmount, getTransactionTypeName, + getTransactionPictureUrl } = useTransactionListPageBase(); const settingsStore = useSettingsStore(); @@ -886,7 +936,7 @@ const allPageCounts = computed(() => { return pageCounts; }); -const recentMonthDateRanges = computed(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type, true)); +const recentMonthDateRanges = computed(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type, true)); const allTransactionTemplates = computed(() => { const allTemplates = transactionTemplatesStore.allVisibleTemplates; @@ -902,7 +952,7 @@ const allowCategoryTypes = computed(() => { }); const transactions = computed(() => { - if (pageType.value === TransactionListPageType.List.type) { + if (pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type) { if (queryMonthlyData.value) { const transactionData = currentMonthTransactionData.value; @@ -942,6 +992,22 @@ const transactions = computed(() => { } }); +const transactionsByDay = computed>(() => { + const transactionsByDay: Record = {}; + + for (const transaction of transactions.value) { + if (!transaction.gregorianCalendarYearDashMonthDashDay) { + continue; + } + + const transactions: Transaction[] = transactionsByDay[transaction.gregorianCalendarYearDashMonthDashDay] ?? []; + transactions.push(transaction); + transactionsByDay[transaction.gregorianCalendarYearDashMonthDashDay] = transactions; + } + + return transactionsByDay; +}); + const recentDateRangeIndex = computed({ get: () => getRecentDateRangeIndex(recentMonthDateRanges.value, query.value.dateType, query.value.minTime, query.value.maxTime, firstDayOfWeek.value, fiscalYearStart.value), set: (value) => { @@ -1166,6 +1232,7 @@ function init(initProps: TransactionListProps): void { function reload(force: boolean, init: boolean): void { loading.value = true; + const isGalleryMode = pageType.value === TransactionListPageType.Gallery.type; const page = currentPage.value; Promise.all([ @@ -1188,6 +1255,8 @@ function reload(force: boolean, init: boolean): void { return transactionsStore.loadMonthlyAllTransactions({ year: currentYear, month: currentMonth, + mustHavePictures: isGalleryMode, + withPictures: isGalleryMode, autoExpand: true, defaultCurrency: defaultCurrency.value }); @@ -1196,7 +1265,9 @@ function reload(force: boolean, init: boolean): void { reload: true, count: countPerPage.value, page: page, + mustHavePictures: isGalleryMode, withCount: page <= 1, + withPictures: isGalleryMode, autoExpand: true, defaultCurrency: defaultCurrency.value }); @@ -1896,4 +1967,8 @@ init(props); .transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span.transaction-calendar-daily-amount { font-size: 0.95rem; } + +.transaction-gallery-container { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); +} diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue index eb88f3af..c9f74fd5 100644 --- a/src/views/mobile/transactions/ListPage.vue +++ b/src/views/mobile/transactions/ListPage.vue @@ -80,10 +80,10 @@
- - + @@ -101,7 +101,8 @@ - + + + + + + @@ -156,14 +172,14 @@ - - + + + + + + + v-if="pageType === TransactionListPageType.List.type || pageType === TransactionListPageType.Gallery.type"> {{ tt('Load More') }} @@ -309,7 +346,7 @@ :class="{ 'list-item-selected': query.dateType === dateRange.type }" :key="dateRange.type" v-for="dateRange in allDateRanges" - v-show="pageType === TransactionListPageType.List.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type" + v-show="pageType === TransactionListPageType.List.type || pageType === TransactionListPageType.Gallery.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type" @click="changeDateFilter(dateRange.type)">