mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 17:54:30 +08:00
support filtering transaction amount
This commit is contained in:
@@ -89,6 +89,7 @@ func startWebServer(c *cli.Context) error {
|
|||||||
_ = v.RegisterValidation("validEmail", validators.ValidEmail)
|
_ = v.RegisterValidation("validEmail", validators.ValidEmail)
|
||||||
_ = v.RegisterValidation("validCurrency", validators.ValidCurrency)
|
_ = v.RegisterValidation("validCurrency", validators.ValidCurrency)
|
||||||
_ = v.RegisterValidation("validHexRGBColor", validators.ValidHexRGBColor)
|
_ = v.RegisterValidation("validHexRGBColor", validators.ValidHexRGBColor)
|
||||||
|
_ = v.RegisterValidation("validAmountFilter", validators.ValidAmountFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
router.NoRoute(bindApi(api.Default.ApiNotFound))
|
router.NoRoute(bindApi(api.Default.ApiNotFound))
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (a *TransactionsApi) TransactionCountHandler(c *core.Context) (any, *errs.E
|
|||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, transactionCountReq.Keyword)
|
totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, transactionCountReq.AmountFilter, transactionCountReq.Keyword)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionCountHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionCountHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
@@ -118,7 +118,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (any, *errs.Er
|
|||||||
var totalCount int64
|
var totalCount int64
|
||||||
|
|
||||||
if transactionListReq.WithCount {
|
if transactionListReq.WithCount {
|
||||||
totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.Keyword)
|
totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.AmountFilter, transactionListReq.Keyword)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
@@ -126,7 +126,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (any, *errs.Er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.Keyword, transactionListReq.Page, transactionListReq.Count, true, true)
|
transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.Page, transactionListReq.Count, true, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transactions earlier than \"%d\" for user \"uid:%d\", because %s", transactionListReq.MaxTime, uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transactions earlier than \"%d\" for user \"uid:%d\", because %s", transactionListReq.MaxTime, uid, err.Error())
|
||||||
@@ -206,7 +206,7 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (any, *er
|
|||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.Keyword)
|
transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, transactionListReq.AmountFilter, transactionListReq.Keyword)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionMonthListHandler] failed to get transactions in month \"%d-%d\" for user \"uid:%d\", because %s", transactionListReq.Year, transactionListReq.Month, uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionMonthListHandler] failed to get transactions in month \"%d-%d\" for user \"uid:%d\", because %s", transactionListReq.Year, transactionListReq.Month, uid, err.Error())
|
||||||
|
|||||||
@@ -82,3 +82,8 @@ func GetParameterInvalidCurrencyMessage(field string) string {
|
|||||||
func GetParameterInvalidHexRGBColorMessage(field string) string {
|
func GetParameterInvalidHexRGBColorMessage(field string) string {
|
||||||
return fmt.Sprintf("parameter \"%s\" is invalid color", field)
|
return fmt.Sprintf("parameter \"%s\" is invalid color", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetParameterInvalidAmountFilterMessage returns specific error message for invalid amount filter parameter error
|
||||||
|
func GetParameterInvalidAmountFilterMessage(field string) string {
|
||||||
|
return fmt.Sprintf("parameter \"%s\" is invalid amount filter", field)
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,12 +94,13 @@ type TransactionModifyRequest struct {
|
|||||||
|
|
||||||
// TransactionCountRequest represents transaction count request
|
// TransactionCountRequest represents transaction count request
|
||||||
type TransactionCountRequest struct {
|
type TransactionCountRequest struct {
|
||||||
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
||||||
CategoryId int64 `form:"category_id" binding:"min=0"`
|
CategoryId int64 `form:"category_id" binding:"min=0"`
|
||||||
AccountId int64 `form:"account_id" binding:"min=0"`
|
AccountId int64 `form:"account_id" binding:"min=0"`
|
||||||
Keyword string `form:"keyword"`
|
AmountFilter string `form:"amount_filter" binding:"validAmountFilter"`
|
||||||
MaxTime int64 `form:"max_time" binding:"min=0"`
|
Keyword string `form:"keyword"`
|
||||||
MinTime int64 `form:"min_time" binding:"min=0"`
|
MaxTime int64 `form:"max_time" binding:"min=0"`
|
||||||
|
MinTime int64 `form:"min_time" binding:"min=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionListByMaxTimeRequest represents all parameters of transaction listing by max time request
|
// TransactionListByMaxTimeRequest represents all parameters of transaction listing by max time request
|
||||||
@@ -107,6 +108,7 @@ type TransactionListByMaxTimeRequest struct {
|
|||||||
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
||||||
CategoryId int64 `form:"category_id" binding:"min=0"`
|
CategoryId int64 `form:"category_id" binding:"min=0"`
|
||||||
AccountId int64 `form:"account_id" binding:"min=0"`
|
AccountId int64 `form:"account_id" binding:"min=0"`
|
||||||
|
AmountFilter string `form:"amount_filter" binding:"validAmountFilter"`
|
||||||
Keyword string `form:"keyword"`
|
Keyword string `form:"keyword"`
|
||||||
MaxTime int64 `form:"max_time" binding:"min=0"`
|
MaxTime int64 `form:"max_time" binding:"min=0"`
|
||||||
MinTime int64 `form:"min_time" binding:"min=0"`
|
MinTime int64 `form:"min_time" binding:"min=0"`
|
||||||
@@ -125,6 +127,7 @@ type TransactionListInMonthByPageRequest struct {
|
|||||||
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
Type TransactionDbType `form:"type" binding:"min=0,max=4"`
|
||||||
CategoryId int64 `form:"category_id" binding:"min=0"`
|
CategoryId int64 `form:"category_id" binding:"min=0"`
|
||||||
AccountId int64 `form:"account_id" binding:"min=0"`
|
AccountId int64 `form:"account_id" binding:"min=0"`
|
||||||
|
AmountFilter string `form:"amount_filter" binding:"validAmountFilter"`
|
||||||
Keyword string `form:"keyword"`
|
Keyword string `form:"keyword"`
|
||||||
TrimAccount bool `form:"trim_account"`
|
TrimAccount bool `form:"trim_account"`
|
||||||
TrimCategory bool `form:"trim_category"`
|
TrimCategory bool `form:"trim_category"`
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ func (s *TransactionService) GetAllTransactions(c *core.Context, uid int64, page
|
|||||||
|
|
||||||
// GetAllTransactionsByMaxTime returns all transactions before given time
|
// 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) {
|
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, "", 1, count, false, noDuplicated)
|
return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, "", "", 1, count, false, noDuplicated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionsByMaxTime returns transactions before given time
|
// GetTransactionsByMaxTime returns transactions before given time
|
||||||
func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, 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.TransactionDbType, categoryIds []int64, accountIds []int64, amountFilter string, keyword string, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return nil, errs.ErrUserIdInvalid
|
return nil, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -101,14 +101,14 @@ func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64
|
|||||||
actualCount++
|
actualCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, keyword, noDuplicated)
|
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, amountFilter, keyword, noDuplicated)
|
||||||
err = s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).Limit(int(actualCount), int(count*(page-1))).OrderBy("transaction_time desc").Find(&transactions)
|
err = s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).Limit(int(actualCount), int(count*(page-1))).OrderBy("transaction_time desc").Find(&transactions)
|
||||||
|
|
||||||
return transactions, err
|
return transactions, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionsInMonthByPage returns all transactions in given year and month
|
// GetTransactionsInMonthByPage returns all transactions in given year and month
|
||||||
func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, keyword string) ([]*models.Transaction, error) {
|
func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, amountFilter string, keyword string) ([]*models.Transaction, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return nil, errs.ErrUserIdInvalid
|
return nil, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid i
|
|||||||
|
|
||||||
var transactions []*models.Transaction
|
var transactions []*models.Transaction
|
||||||
|
|
||||||
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, keyword, true)
|
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, amountFilter, keyword, true)
|
||||||
err = s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).OrderBy("transaction_time desc").Find(&transactions)
|
err = s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).OrderBy("transaction_time desc").Find(&transactions)
|
||||||
|
|
||||||
transactionsInMonth := make([]*models.Transaction, 0, len(transactions))
|
transactionsInMonth := make([]*models.Transaction, 0, len(transactions))
|
||||||
@@ -163,11 +163,11 @@ func (s *TransactionService) GetTransactionByTransactionId(c *core.Context, uid
|
|||||||
|
|
||||||
// GetAllTransactionCount returns total count of transactions
|
// GetAllTransactionCount returns total count of transactions
|
||||||
func (s *TransactionService) GetAllTransactionCount(c *core.Context, uid int64) (int64, error) {
|
func (s *TransactionService) GetAllTransactionCount(c *core.Context, uid int64) (int64, error) {
|
||||||
return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, "")
|
return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMonthTransactionCount returns total count of transactions in given year and month
|
// GetMonthTransactionCount returns total count of transactions in given year and month
|
||||||
func (s *TransactionService) GetMonthTransactionCount(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, keyword string, utcOffset int16) (int64, error) {
|
func (s *TransactionService) GetMonthTransactionCount(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, amountFilter string, keyword string, utcOffset int16) (int64, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return 0, errs.ErrUserIdInvalid
|
return 0, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -183,16 +183,16 @@ func (s *TransactionService) GetMonthTransactionCount(c *core.Context, uid int64
|
|||||||
minTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startTime.Unix())
|
minTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startTime.Unix())
|
||||||
maxTransactionTime := utils.GetMinTransactionTimeFromUnixTime(endTime.Unix()) - 1
|
maxTransactionTime := utils.GetMinTransactionTimeFromUnixTime(endTime.Unix()) - 1
|
||||||
|
|
||||||
return s.GetTransactionCount(c, uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, keyword)
|
return s.GetTransactionCount(c, uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, amountFilter, keyword)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionCount returns count of transactions
|
// GetTransactionCount returns count of transactions
|
||||||
func (s *TransactionService) GetTransactionCount(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, keyword string) (int64, error) {
|
func (s *TransactionService) GetTransactionCount(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, amountFilter string, keyword string) (int64, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return 0, errs.ErrUserIdInvalid
|
return 0, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, keyword, true)
|
condition, conditionParams := s.getTransactionQueryCondition(uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, amountFilter, keyword, true)
|
||||||
return s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).Count(&models.Transaction{})
|
return s.UserDataDB(uid).NewSession(c).Where(condition, conditionParams...).Count(&models.Transaction{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,7 +1331,7 @@ func (s *TransactionService) GetTransactionMapByList(transactions []*models.Tran
|
|||||||
return transactionMap
|
return transactionMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionService) getTransactionQueryCondition(uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, keyword string, noDuplicated bool) (string, []any) {
|
func (s *TransactionService) getTransactionQueryCondition(uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, amountFilter string, keyword string, noDuplicated bool) (string, []any) {
|
||||||
condition := "uid=? AND deleted=?"
|
condition := "uid=? AND deleted=?"
|
||||||
conditionParams := make([]any, 0, 16)
|
conditionParams := make([]any, 0, 16)
|
||||||
conditionParams = append(conditionParams, uid)
|
conditionParams = append(conditionParams, uid)
|
||||||
@@ -1399,6 +1399,58 @@ func (s *TransactionService) getTransactionQueryCondition(uid int64, maxTransact
|
|||||||
condition = condition + " AND account_id IN (" + conditions.String() + ")"
|
condition = condition + " AND account_id IN (" + conditions.String() + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if amountFilter != "" {
|
||||||
|
amountFilterItems := strings.Split(amountFilter, ":")
|
||||||
|
|
||||||
|
if len(amountFilterItems) == 2 && amountFilterItems[0] == "gt" {
|
||||||
|
value, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND amount > ?"
|
||||||
|
conditionParams = append(conditionParams, value)
|
||||||
|
}
|
||||||
|
} else if len(amountFilterItems) == 2 && amountFilterItems[0] == "lt" {
|
||||||
|
value, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND amount < ?"
|
||||||
|
conditionParams = append(conditionParams, value)
|
||||||
|
}
|
||||||
|
} else if len(amountFilterItems) == 2 && amountFilterItems[0] == "eq" {
|
||||||
|
value, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND amount = ?"
|
||||||
|
conditionParams = append(conditionParams, value)
|
||||||
|
}
|
||||||
|
} else if len(amountFilterItems) == 2 && amountFilterItems[0] == "ne" {
|
||||||
|
value, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND amount <> ?"
|
||||||
|
conditionParams = append(conditionParams, value)
|
||||||
|
}
|
||||||
|
} else if len(amountFilterItems) == 3 && amountFilterItems[0] == "bt" {
|
||||||
|
value1, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
value2, err := utils.StringToInt64(amountFilterItems[2])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND amount >= ? AND amount <= ?"
|
||||||
|
conditionParams = append(conditionParams, value1)
|
||||||
|
conditionParams = append(conditionParams, value2)
|
||||||
|
}
|
||||||
|
} else if len(amountFilterItems) == 3 && amountFilterItems[0] == "nb" {
|
||||||
|
value1, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
value2, err := utils.StringToInt64(amountFilterItems[2])
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
condition = condition + " AND (amount < ? OR amount > ?)"
|
||||||
|
conditionParams = append(conditionParams, value1)
|
||||||
|
conditionParams = append(conditionParams, value2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if keyword != "" {
|
if keyword != "" {
|
||||||
condition = condition + " AND comment LIKE ?"
|
condition = condition + " AND comment LIKE ?"
|
||||||
conditionParams = append(conditionParams, "%%"+keyword+"%%")
|
conditionParams = append(conditionParams, "%%"+keyword+"%%")
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ func getValidationErrorText(err validator.FieldError) string {
|
|||||||
return errs.GetParameterInvalidCurrencyMessage(fieldName)
|
return errs.GetParameterInvalidCurrencyMessage(fieldName)
|
||||||
case "validHexRGBColor":
|
case "validHexRGBColor":
|
||||||
return errs.GetParameterInvalidHexRGBColorMessage(fieldName)
|
return errs.GetParameterInvalidHexRGBColorMessage(fieldName)
|
||||||
|
case "validAmountFilter":
|
||||||
|
return errs.GetParameterInvalidAmountFilterMessage(fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs.GetParameterInvalidMessage(fieldName)
|
return errs.GetParameterInvalidMessage(fieldName)
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidAmountFilter returns whether the given amount filter is valid
|
||||||
|
func ValidAmountFilter(fl validator.FieldLevel) bool {
|
||||||
|
if value, ok := fl.Field().Interface().(string); ok {
|
||||||
|
if value == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
amountFilterItems := strings.Split(value, ":")
|
||||||
|
|
||||||
|
if len(amountFilterItems) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
amount1, err := utils.StringToInt64(amountFilterItems[1])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if amountFilterItems[0] == "gt" || amountFilterItems[0] == "lt" || amountFilterItems[0] == "eq" || amountFilterItems[0] == "ne" {
|
||||||
|
if len(amountFilterItems) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if amountFilterItems[0] == "bt" || amountFilterItems[0] == "nb" {
|
||||||
|
if len(amountFilterItems) != 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
amount2, err := utils.StringToInt64(amountFilterItems[2])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if amount2 < amount1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -86,6 +86,57 @@ const allDigitGroupingTypeMap = {
|
|||||||
[allDigitGroupingType.ThousandsSeparator.type]: allDigitGroupingType.ThousandsSeparator
|
[allDigitGroupingType.ThousandsSeparator.type]: allDigitGroupingType.ThousandsSeparator
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const allAmountFilterType = {
|
||||||
|
GreaterThan: {
|
||||||
|
type: 'gt',
|
||||||
|
name: 'Greater than',
|
||||||
|
paramCount: 1
|
||||||
|
},
|
||||||
|
LessThan:{
|
||||||
|
type: 'lt',
|
||||||
|
name: 'Less than',
|
||||||
|
paramCount: 1
|
||||||
|
},
|
||||||
|
EqualTo:{
|
||||||
|
type: 'eq',
|
||||||
|
name: 'Equal to',
|
||||||
|
paramCount: 1
|
||||||
|
},
|
||||||
|
NotEqualTo:{
|
||||||
|
type: 'ne',
|
||||||
|
name: 'Not equal to',
|
||||||
|
paramCount: 1
|
||||||
|
},
|
||||||
|
Between:{
|
||||||
|
type: 'bt',
|
||||||
|
name: 'Between',
|
||||||
|
paramCount: 2
|
||||||
|
},
|
||||||
|
NotBetween:{
|
||||||
|
type: 'nb',
|
||||||
|
name: 'Not between',
|
||||||
|
paramCount: 2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const allAmountFilterTypeArray = [
|
||||||
|
allAmountFilterType.GreaterThan,
|
||||||
|
allAmountFilterType.LessThan,
|
||||||
|
allAmountFilterType.EqualTo,
|
||||||
|
allAmountFilterType.NotEqualTo,
|
||||||
|
allAmountFilterType.Between,
|
||||||
|
allAmountFilterType.NotBetween,
|
||||||
|
];
|
||||||
|
|
||||||
|
const allAmountFilterTypeMap = {
|
||||||
|
[allAmountFilterType.GreaterThan.type]: allAmountFilterType.GreaterThan,
|
||||||
|
[allAmountFilterType.LessThan.type]: allAmountFilterType.LessThan,
|
||||||
|
[allAmountFilterType.EqualTo.type]: allAmountFilterType.EqualTo,
|
||||||
|
[allAmountFilterType.NotEqualTo.type]: allAmountFilterType.NotEqualTo,
|
||||||
|
[allAmountFilterType.Between.type]: allAmountFilterType.Between,
|
||||||
|
[allAmountFilterType.NotBetween.type]: allAmountFilterType.NotBetween
|
||||||
|
};
|
||||||
|
|
||||||
const defaultDecimalSeparator = allDecimalSeparator.Dot;
|
const defaultDecimalSeparator = allDecimalSeparator.Dot;
|
||||||
const defaultDigitGroupingSymbol = allDigitGroupingSymbol.Comma;
|
const defaultDigitGroupingSymbol = allDigitGroupingSymbol.Comma;
|
||||||
const defaultDigitGroupingType = allDigitGroupingType.ThousandsSeparator;
|
const defaultDigitGroupingType = allDigitGroupingType.ThousandsSeparator;
|
||||||
@@ -101,6 +152,9 @@ export default {
|
|||||||
allDigitGroupingType: allDigitGroupingType,
|
allDigitGroupingType: allDigitGroupingType,
|
||||||
allDigitGroupingTypeArray: allDigitGroupingTypeArray,
|
allDigitGroupingTypeArray: allDigitGroupingTypeArray,
|
||||||
allDigitGroupingTypeMap: allDigitGroupingTypeMap,
|
allDigitGroupingTypeMap: allDigitGroupingTypeMap,
|
||||||
|
allAmountFilterType: allAmountFilterType,
|
||||||
|
allAmountFilterTypeArray: allAmountFilterTypeArray,
|
||||||
|
allAmountFilterTypeMap: allAmountFilterTypeMap,
|
||||||
defaultDecimalSeparator: defaultDecimalSeparator,
|
defaultDecimalSeparator: defaultDecimalSeparator,
|
||||||
defaultDigitGroupingSymbol: defaultDigitGroupingSymbol,
|
defaultDigitGroupingSymbol: defaultDigitGroupingSymbol,
|
||||||
defaultDigitGroupingType: defaultDigitGroupingType,
|
defaultDigitGroupingType: defaultDigitGroupingType,
|
||||||
|
|||||||
@@ -175,6 +175,14 @@ const parameterizedErrors = [
|
|||||||
field: 'parameter',
|
field: 'parameter',
|
||||||
localized: true
|
localized: true
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
localeKey: 'parameter invalid amount filter',
|
||||||
|
regex: /^parameter "(\w+)" is invalid amount filter$/,
|
||||||
|
parameters: [{
|
||||||
|
field: 'parameter',
|
||||||
|
localized: true
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -279,13 +279,15 @@ export default {
|
|||||||
id
|
id
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getTransactions: ({ maxTime, minTime, count, page, withCount, type, categoryId, accountId, keyword }) => {
|
getTransactions: ({ maxTime, minTime, count, page, withCount, type, categoryId, accountId, amountFilter, keyword }) => {
|
||||||
|
amountFilter = encodeURIComponent(amountFilter);
|
||||||
keyword = encodeURIComponent(keyword);
|
keyword = encodeURIComponent(keyword);
|
||||||
return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&count=${count}&page=${page}&with_count=${withCount}&trim_account=true&trim_category=true&trim_tag=true`);
|
return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_id=${categoryId}&account_id=${accountId}&amount_filter=${amountFilter}&keyword=${keyword}&count=${count}&page=${page}&with_count=${withCount}&trim_account=true&trim_category=true&trim_tag=true`);
|
||||||
},
|
},
|
||||||
getAllTransactionsByMonth: ({ year, month, type, categoryId, accountId, keyword }) => {
|
getAllTransactionsByMonth: ({ year, month, type, categoryId, accountId, amountFilter, keyword }) => {
|
||||||
|
amountFilter = encodeURIComponent(amountFilter);
|
||||||
keyword = encodeURIComponent(keyword);
|
keyword = encodeURIComponent(keyword);
|
||||||
return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`);
|
return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_id=${categoryId}&account_id=${accountId}&amount_filter=${amountFilter}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`);
|
||||||
},
|
},
|
||||||
getTransactionStatistics: ({ startTime, endTime, useTransactionTimezone }) => {
|
getTransactionStatistics: ({ startTime, endTime, useTransactionTimezone }) => {
|
||||||
const queryParams = [];
|
const queryParams = [];
|
||||||
|
|||||||
@@ -707,6 +707,7 @@ export default {
|
|||||||
'time': 'Time',
|
'time': 'Time',
|
||||||
'startTime': 'Start Time',
|
'startTime': 'Start Time',
|
||||||
'endTime': 'End Time',
|
'endTime': 'End Time',
|
||||||
|
'amountFilter': 'Amount Filter',
|
||||||
'sourceAccountId': 'Source Account ID',
|
'sourceAccountId': 'Source Account ID',
|
||||||
'destinationAccountId': 'Destination Account ID',
|
'destinationAccountId': 'Destination Account ID',
|
||||||
'sourceAmount': 'Source Amount',
|
'sourceAmount': 'Source Amount',
|
||||||
@@ -731,6 +732,7 @@ export default {
|
|||||||
'parameter invalid email format': '{parameter} is invalid format',
|
'parameter invalid email format': '{parameter} is invalid format',
|
||||||
'parameter invalid currency': '{parameter} is invalid format',
|
'parameter invalid currency': '{parameter} is invalid format',
|
||||||
'parameter invalid color': '{parameter} is invalid format',
|
'parameter invalid color': '{parameter} is invalid format',
|
||||||
|
'parameter invalid amount filter': '{parameter} is invalid format',
|
||||||
},
|
},
|
||||||
'OK': 'OK',
|
'OK': 'OK',
|
||||||
'Cancel': 'Cancel',
|
'Cancel': 'Cancel',
|
||||||
@@ -799,6 +801,12 @@ export default {
|
|||||||
'Select Time': 'Select Time',
|
'Select Time': 'Select Time',
|
||||||
'Now': 'Now',
|
'Now': 'Now',
|
||||||
'Custom': 'Custom',
|
'Custom': 'Custom',
|
||||||
|
'Greater than': 'Greater than',
|
||||||
|
'Less than': 'Less than',
|
||||||
|
'Equal to': 'Equal to',
|
||||||
|
'Not equal to': 'Not equal to',
|
||||||
|
'Between': 'Between',
|
||||||
|
'Not between': 'Not between',
|
||||||
'Pie Chart': 'Pie Chart',
|
'Pie Chart': 'Pie Chart',
|
||||||
'Bar Chart': 'Bar Chart',
|
'Bar Chart': 'Bar Chart',
|
||||||
'Area Chart': 'Area Chart',
|
'Area Chart': 'Area Chart',
|
||||||
@@ -921,7 +929,9 @@ export default {
|
|||||||
'This Month': 'This Month',
|
'This Month': 'This Month',
|
||||||
'This Year': 'This Year',
|
'This Year': 'This Year',
|
||||||
'Monthly income': 'Monthly income',
|
'Monthly income': 'Monthly income',
|
||||||
|
'Filter Amount': 'Filter Amount',
|
||||||
'Unable to retrieve transaction overview': 'Unable to retrieve transaction overview',
|
'Unable to retrieve transaction overview': 'Unable to retrieve transaction overview',
|
||||||
|
'Incorrect amount range': 'Incorrect amount range',
|
||||||
'Data is up to date': 'Data is up to date',
|
'Data is up to date': 'Data is up to date',
|
||||||
'Data has been updated': 'Data has been updated',
|
'Data has been updated': 'Data has been updated',
|
||||||
'Net assets': 'Net assets',
|
'Net assets': 'Net assets',
|
||||||
@@ -1066,6 +1076,8 @@ export default {
|
|||||||
'Default Sort Order': 'Default Sort Order',
|
'Default Sort Order': 'Default Sort Order',
|
||||||
'Timezone Used for Date Range': 'Timezone Used for Date Range',
|
'Timezone Used for Date Range': 'Timezone Used for Date Range',
|
||||||
'Amount': 'Amount',
|
'Amount': 'Amount',
|
||||||
|
'Min Amount': 'Min Amount',
|
||||||
|
'Max Amount': 'Max Amount',
|
||||||
'Display Order': 'Display Order',
|
'Display Order': 'Display Order',
|
||||||
'Name': 'Name',
|
'Name': 'Name',
|
||||||
'Sort by Amount': 'Sort by Amount',
|
'Sort by Amount': 'Sort by Amount',
|
||||||
|
|||||||
@@ -707,6 +707,7 @@ export default {
|
|||||||
'time': '时间',
|
'time': '时间',
|
||||||
'startTime': '开始时间',
|
'startTime': '开始时间',
|
||||||
'endTime': '结束时间',
|
'endTime': '结束时间',
|
||||||
|
'amountFilter': '金额过滤',
|
||||||
'sourceAccountId': '来源账户ID',
|
'sourceAccountId': '来源账户ID',
|
||||||
'destinationAccountId': '目标账户ID',
|
'destinationAccountId': '目标账户ID',
|
||||||
'sourceAmount': '源金额',
|
'sourceAmount': '源金额',
|
||||||
@@ -731,6 +732,7 @@ export default {
|
|||||||
'parameter invalid email format': '{parameter}格式错误',
|
'parameter invalid email format': '{parameter}格式错误',
|
||||||
'parameter invalid currency': '{parameter}格式错误',
|
'parameter invalid currency': '{parameter}格式错误',
|
||||||
'parameter invalid color': '{parameter}格式错误',
|
'parameter invalid color': '{parameter}格式错误',
|
||||||
|
'parameter invalid amount filter': '{parameter}格式错误',
|
||||||
},
|
},
|
||||||
'OK': '确定',
|
'OK': '确定',
|
||||||
'Cancel': '取消',
|
'Cancel': '取消',
|
||||||
@@ -799,6 +801,12 @@ export default {
|
|||||||
'Select Time': '选择时间',
|
'Select Time': '选择时间',
|
||||||
'Now': '现在',
|
'Now': '现在',
|
||||||
'Custom': '自定义',
|
'Custom': '自定义',
|
||||||
|
'Greater than': '大于',
|
||||||
|
'Less than': '小于',
|
||||||
|
'Equal to': '等于',
|
||||||
|
'Not equal to': '不等于',
|
||||||
|
'Between': '介于',
|
||||||
|
'Not between': '不介于',
|
||||||
'Pie Chart': '饼图',
|
'Pie Chart': '饼图',
|
||||||
'Bar Chart': '条形图',
|
'Bar Chart': '条形图',
|
||||||
'Area Chart': '面积图',
|
'Area Chart': '面积图',
|
||||||
@@ -921,7 +929,9 @@ export default {
|
|||||||
'This Month': '本月',
|
'This Month': '本月',
|
||||||
'This Year': '今年',
|
'This Year': '今年',
|
||||||
'Monthly income': '当月收入',
|
'Monthly income': '当月收入',
|
||||||
|
'Filter Amount': '过滤金额',
|
||||||
'Unable to retrieve transaction overview': '无法获取交易概要',
|
'Unable to retrieve transaction overview': '无法获取交易概要',
|
||||||
|
'Incorrect amount range': '金额范围错误',
|
||||||
'Data is up to date': '数据已是最新',
|
'Data is up to date': '数据已是最新',
|
||||||
'Data has been updated': '数据已更新',
|
'Data has been updated': '数据已更新',
|
||||||
'Net assets': '净资产',
|
'Net assets': '净资产',
|
||||||
@@ -1066,6 +1076,8 @@ export default {
|
|||||||
'Default Sort Order': '默认排序方式',
|
'Default Sort Order': '默认排序方式',
|
||||||
'Timezone Used for Date Range': '时间范围使用的时区',
|
'Timezone Used for Date Range': '时间范围使用的时区',
|
||||||
'Amount': '金额',
|
'Amount': '金额',
|
||||||
|
'Min Amount': '最小金额',
|
||||||
|
'Max Amount': '最大金额',
|
||||||
'Display Order': '显示顺序',
|
'Display Order': '显示顺序',
|
||||||
'Name': '名称',
|
'Name': '名称',
|
||||||
'Sort by Amount': '按金额排序',
|
'Sort by Amount': '按金额排序',
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ const router = createRouter({
|
|||||||
initType: route.query.type,
|
initType: route.query.type,
|
||||||
initCategoryId: route.query.categoryId,
|
initCategoryId: route.query.categoryId,
|
||||||
initAccountId: route.query.accountId,
|
initAccountId: route.query.accountId,
|
||||||
|
initAmountFilter: route.query.amountFilter,
|
||||||
initKeyword: route.query.keyword
|
initKeyword: route.query.keyword
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import UnlockPage from '@/views/mobile/UnlockPage.vue';
|
|||||||
|
|
||||||
import TransactionListPage from '@/views/mobile/transactions/ListPage.vue';
|
import TransactionListPage from '@/views/mobile/transactions/ListPage.vue';
|
||||||
import TransactionEditPage from '@/views/mobile/transactions/EditPage.vue';
|
import TransactionEditPage from '@/views/mobile/transactions/EditPage.vue';
|
||||||
|
import TransactionAmountFilterPage from '@/views/mobile/transactions/AmountFilterPage.vue';
|
||||||
|
|
||||||
import AccountListPage from '@/views/mobile/accounts/ListPage.vue';
|
import AccountListPage from '@/views/mobile/accounts/ListPage.vue';
|
||||||
import AccountEditPage from '@/views/mobile/accounts/EditPage.vue';
|
import AccountEditPage from '@/views/mobile/accounts/EditPage.vue';
|
||||||
@@ -148,6 +149,11 @@ const routes = [
|
|||||||
async: asyncResolve(TransactionListPage),
|
async: asyncResolve(TransactionListPage),
|
||||||
beforeEnter: [checkLogin]
|
beforeEnter: [checkLogin]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/transaction/filter/amount',
|
||||||
|
async: asyncResolve(TransactionAmountFilterPage),
|
||||||
|
beforeEnter: [checkLogin]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/transaction/add',
|
path: '/transaction/add',
|
||||||
async: asyncResolve(TransactionEditPage),
|
async: asyncResolve(TransactionEditPage),
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
type: 0,
|
type: 0,
|
||||||
categoryId: '0',
|
categoryId: '0',
|
||||||
accountId: '0',
|
accountId: '0',
|
||||||
|
amountFilter: '',
|
||||||
keyword: ''
|
keyword: ''
|
||||||
},
|
},
|
||||||
transactions: [],
|
transactions: [],
|
||||||
@@ -365,6 +366,7 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
this.transactionsFilter.type = 0;
|
this.transactionsFilter.type = 0;
|
||||||
this.transactionsFilter.categoryId = '0';
|
this.transactionsFilter.categoryId = '0';
|
||||||
this.transactionsFilter.accountId = '0';
|
this.transactionsFilter.accountId = '0';
|
||||||
|
this.transactionsFilter.amountFilter = '';
|
||||||
this.transactionsFilter.keyword = '';
|
this.transactionsFilter.keyword = '';
|
||||||
this.transactions = [];
|
this.transactions = [];
|
||||||
this.transactionsNextTimeId = 0;
|
this.transactionsNextTimeId = 0;
|
||||||
@@ -412,6 +414,12 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
this.transactionsFilter.accountId = '0';
|
this.transactionsFilter.accountId = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter && isString(filter.amountFilter)) {
|
||||||
|
this.transactionsFilter.amountFilter = filter.amountFilter;
|
||||||
|
} else {
|
||||||
|
this.transactionsFilter.amountFilter = '';
|
||||||
|
}
|
||||||
|
|
||||||
if (filter && isString(filter.keyword)) {
|
if (filter && isString(filter.keyword)) {
|
||||||
this.transactionsFilter.keyword = filter.keyword;
|
this.transactionsFilter.keyword = filter.keyword;
|
||||||
} else {
|
} else {
|
||||||
@@ -443,6 +451,10 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
this.transactionsFilter.accountId = filter.accountId;
|
this.transactionsFilter.accountId = filter.accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter && isString(filter.amountFilter)) {
|
||||||
|
this.transactionsFilter.amountFilter = filter.amountFilter;
|
||||||
|
}
|
||||||
|
|
||||||
if (filter && isString(filter.keyword)) {
|
if (filter && isString(filter.keyword)) {
|
||||||
this.transactionsFilter.keyword = filter.keyword;
|
this.transactionsFilter.keyword = filter.keyword;
|
||||||
}
|
}
|
||||||
@@ -469,6 +481,10 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
querys.push('minTime=' + this.transactionsFilter.minTime);
|
querys.push('minTime=' + this.transactionsFilter.minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.transactionsFilter.amountFilter) {
|
||||||
|
querys.push('amountFilter=' + encodeURIComponent(this.transactionsFilter.amountFilter));
|
||||||
|
}
|
||||||
|
|
||||||
if (this.transactionsFilter.keyword) {
|
if (this.transactionsFilter.keyword) {
|
||||||
querys.push('keyword=' + encodeURIComponent(this.transactionsFilter.keyword));
|
querys.push('keyword=' + encodeURIComponent(this.transactionsFilter.keyword));
|
||||||
}
|
}
|
||||||
@@ -497,6 +513,7 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
type: self.transactionsFilter.type,
|
type: self.transactionsFilter.type,
|
||||||
categoryId: self.transactionsFilter.categoryId,
|
categoryId: self.transactionsFilter.categoryId,
|
||||||
accountId: self.transactionsFilter.accountId,
|
accountId: self.transactionsFilter.accountId,
|
||||||
|
amountFilter: self.transactionsFilter.amountFilter,
|
||||||
keyword: self.transactionsFilter.keyword
|
keyword: self.transactionsFilter.keyword
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
@@ -571,6 +588,7 @@ export const useTransactionsStore = defineStore('transactions', {
|
|||||||
type: self.transactionsFilter.type,
|
type: self.transactionsFilter.type,
|
||||||
categoryId: self.transactionsFilter.categoryId,
|
categoryId: self.transactionsFilter.categoryId,
|
||||||
accountId: self.transactionsFilter.accountId,
|
accountId: self.transactionsFilter.accountId,
|
||||||
|
amountFilter: self.transactionsFilter.amountFilter,
|
||||||
keyword: self.transactionsFilter.keyword
|
keyword: self.transactionsFilter.keyword
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
|||||||
@@ -192,7 +192,56 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</th>
|
</th>
|
||||||
<th class="transaction-table-column-amount">{{ $t('Amount') }}</th>
|
<th class="transaction-table-column-amount">
|
||||||
|
<v-menu ref="amountFilterMenu" class="transaction-amount-menu"
|
||||||
|
eager location="bottom" max-height="500"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
v-model="amountMenuState"
|
||||||
|
@update:model-value="scrollAmountMenuToSelectedItem">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<div class="d-flex align-center cursor-pointer"
|
||||||
|
:class="{ 'readonly': loading, 'text-primary': query.amountFilter }" v-bind="props">
|
||||||
|
<span>{{ $t('Amount') }}</span>
|
||||||
|
<v-icon :icon="icons.dropdownMenu" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<v-list :selected="[query.amountFilter.split(':')[0]]">
|
||||||
|
<v-list-item key="0" value="0" class="text-sm" density="compact"
|
||||||
|
:class="{ 'list-item-selected': !query.amountFilter }"
|
||||||
|
:append-icon="(!query.amountFilter && !currentAmountFilterType ? icons.check : null)">
|
||||||
|
<v-list-item-title class="cursor-pointer"
|
||||||
|
@click="changeAmountFilter('')">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<span class="text-sm ml-3">{{ $t('All') }}</span>
|
||||||
|
</div>
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<template :key="filterType.type"
|
||||||
|
v-for="filterType in allAmountFilterTypes">
|
||||||
|
<v-list-item class="text-sm" density="compact"
|
||||||
|
:value="filterType.type"
|
||||||
|
:class="{ 'list-item-selected': query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) }"
|
||||||
|
:append-icon="(query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type ? icons.check : null)">
|
||||||
|
<v-list-item-title class="cursor-pointer"
|
||||||
|
@click="currentAmountFilterType = filterType.type">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<span class="text-sm ml-3">{{ $t(filterType.name) }}</span>
|
||||||
|
<span class="text-sm ml-4" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type">{{ queryAmount }}</span>
|
||||||
|
<amount-input class="transaction-amount-filter-value ml-4" density="compact" v-model="currentAmountFilterValue1"
|
||||||
|
v-if="currentAmountFilterType === filterType.type"/>
|
||||||
|
<span class="ml-2 mr-2" v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2">~</span>
|
||||||
|
<amount-input class="transaction-amount-filter-value" density="compact" v-model="currentAmountFilterValue2"
|
||||||
|
v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2"/>
|
||||||
|
<v-btn class="ml-2" density="compact" color="primary" variant="tonal"
|
||||||
|
@click="changeAmountFilter(filterType.type)"
|
||||||
|
v-if="currentAmountFilterType === filterType.type">{{ $t('Apply') }}</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</template>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</th>
|
||||||
<th class="transaction-table-column-account">
|
<th class="transaction-table-column-account">
|
||||||
<v-menu ref="accountFilterMenu" class="transaction-account-menu"
|
<v-menu ref="accountFilterMenu" class="transaction-account-menu"
|
||||||
eager location="bottom" max-height="500"
|
eager location="bottom" max-height="500"
|
||||||
@@ -353,11 +402,13 @@ import { useAccountsStore } from '@/stores/account.js';
|
|||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
|
|
||||||
|
import numeralConstants from '@/consts/numeral.js';
|
||||||
import datetimeConstants from '@/consts/datetime.js';
|
import datetimeConstants from '@/consts/datetime.js';
|
||||||
import currencyConstants from '@/consts/currency.js';
|
import currencyConstants from '@/consts/currency.js';
|
||||||
import accountConstants from '@/consts/account.js';
|
import accountConstants from '@/consts/account.js';
|
||||||
import transactionConstants from '@/consts/transaction.js';
|
import transactionConstants from '@/consts/transaction.js';
|
||||||
import { getNameByKeyValue } from '@/lib/common.js';
|
import { isString, getNameByKeyValue } from '@/lib/common.js';
|
||||||
|
import logger from '@/lib/logger.js';
|
||||||
import {
|
import {
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
parseDateFromUnixTime,
|
parseDateFromUnixTime,
|
||||||
@@ -406,6 +457,7 @@ export default {
|
|||||||
'initType',
|
'initType',
|
||||||
'initCategoryId',
|
'initCategoryId',
|
||||||
'initAccountId',
|
'initAccountId',
|
||||||
|
'initAmountFilter',
|
||||||
'initKeyword'
|
'initKeyword'
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
@@ -421,8 +473,12 @@ export default {
|
|||||||
searchKeyword: '',
|
searchKeyword: '',
|
||||||
customMinDatetime: 0,
|
customMinDatetime: 0,
|
||||||
customMaxDatetime: 0,
|
customMaxDatetime: 0,
|
||||||
|
currentAmountFilterType: '',
|
||||||
|
currentAmountFilterValue1: '0',
|
||||||
|
currentAmountFilterValue2: '0',
|
||||||
currentPageTransactions: [],
|
currentPageTransactions: [],
|
||||||
categoryMenuState: false,
|
categoryMenuState: false,
|
||||||
|
amountMenuState: false,
|
||||||
alwaysShowNav: mdAndUp.value,
|
alwaysShowNav: mdAndUp.value,
|
||||||
showNav: mdAndUp.value,
|
showNav: mdAndUp.value,
|
||||||
showCustomDateRangeDialog: false,
|
showCustomDateRangeDialog: false,
|
||||||
@@ -497,6 +553,25 @@ export default {
|
|||||||
queryAccountName() {
|
queryAccountName() {
|
||||||
return getNameByKeyValue(this.allAccounts, this.query.accountId, null, 'name', this.$t('Account'));
|
return getNameByKeyValue(this.allAccounts, this.query.accountId, null, 'name', this.$t('Account'));
|
||||||
},
|
},
|
||||||
|
queryAmount() {
|
||||||
|
if (!this.query.amountFilter) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const amountFilterItems = this.query.amountFilter.split(':');
|
||||||
|
|
||||||
|
if (amountFilterItems.length < 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayAmount = [];
|
||||||
|
|
||||||
|
for (let i = 1; i < amountFilterItems.length; i++) {
|
||||||
|
displayAmount.push(this.getDisplayCurrency(amountFilterItems[i], false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayAmount.join(' ~ ');
|
||||||
|
},
|
||||||
queryMonthlyData() {
|
queryMonthlyData() {
|
||||||
return isDateRangeMatchOneMonth(this.query.minTime, this.query.maxTime);
|
return isDateRangeMatchOneMonth(this.query.minTime, this.query.maxTime);
|
||||||
},
|
},
|
||||||
@@ -597,6 +672,9 @@ export default {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
allAmountFilterTypes() {
|
||||||
|
return numeralConstants.allAmountFilterTypeArray;
|
||||||
|
},
|
||||||
allTransactionTypes() {
|
allTransactionTypes() {
|
||||||
return transactionConstants.allTransactionTypes;
|
return transactionConstants.allTransactionTypes;
|
||||||
},
|
},
|
||||||
@@ -638,6 +716,7 @@ export default {
|
|||||||
type: this.initType,
|
type: this.initType,
|
||||||
categoryId: this.initCategoryId,
|
categoryId: this.initCategoryId,
|
||||||
accountId: this.initAccountId,
|
accountId: this.initAccountId,
|
||||||
|
amountFilter: this.initAmountFilter,
|
||||||
keyword: this.initKeyword
|
keyword: this.initKeyword
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -666,6 +745,7 @@ export default {
|
|||||||
type: to.query.type,
|
type: to.query.type,
|
||||||
categoryId: to.query.categoryId,
|
categoryId: to.query.categoryId,
|
||||||
accountId: to.query.accountId,
|
accountId: to.query.accountId,
|
||||||
|
amountFilter: to.query.amountFilter,
|
||||||
keyword: to.query.keyword
|
keyword: to.query.keyword
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -691,10 +771,12 @@ export default {
|
|||||||
type: parseInt(query.type) > 0 ? parseInt(query.type) : undefined,
|
type: parseInt(query.type) > 0 ? parseInt(query.type) : undefined,
|
||||||
categoryId: query.categoryId,
|
categoryId: query.categoryId,
|
||||||
accountId: query.accountId,
|
accountId: query.accountId,
|
||||||
|
amountFilter: query.amountFilter || '',
|
||||||
keyword: query.keyword || ''
|
keyword: query.keyword || ''
|
||||||
});
|
});
|
||||||
|
|
||||||
this.searchKeyword = query.keyword || '';
|
this.searchKeyword = query.keyword || '';
|
||||||
|
this.currentAmountFilterType = '';
|
||||||
|
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
this.reload(false);
|
this.reload(false);
|
||||||
@@ -855,6 +937,50 @@ export default {
|
|||||||
this.transactionsStore.clearTransactions();
|
this.transactionsStore.clearTransactions();
|
||||||
this.$router.push(this.getFilterLinkUrl());
|
this.$router.push(this.getFilterLinkUrl());
|
||||||
},
|
},
|
||||||
|
changeAmountFilter(filterType) {
|
||||||
|
this.currentAmountFilterType = '';
|
||||||
|
this.amountMenuState = false;
|
||||||
|
|
||||||
|
if (this.query.amountFilter === filterType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let amountFilter = filterType;
|
||||||
|
|
||||||
|
if (filterType) {
|
||||||
|
const amountCount = this.getAmountFilterParameterCount(filterType);
|
||||||
|
|
||||||
|
if (!amountCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amountCount === 1) {
|
||||||
|
amountFilter += ':' + this.currentAmountFilterValue1;
|
||||||
|
} else if (amountCount === 2) {
|
||||||
|
if (this.currentAmountFilterValue2 < this.currentAmountFilterValue1) {
|
||||||
|
this.$refs.snackbar.showMessage('Incorrect amount range');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountFilter += ':' + this.currentAmountFilterValue1 + ':' + this.currentAmountFilterValue2;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.query.amountFilter === amountFilter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transactionsStore.updateTransactionListFilter({
|
||||||
|
amountFilter: amountFilter
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
this.currentPageTransactions = [];
|
||||||
|
this.transactionsStore.clearTransactions();
|
||||||
|
this.$router.push(this.getFilterLinkUrl());
|
||||||
|
},
|
||||||
changeAccountFilter(accountId) {
|
changeAccountFilter(accountId) {
|
||||||
if (this.query.accountId === accountId) {
|
if (this.query.accountId === accountId) {
|
||||||
return;
|
return;
|
||||||
@@ -929,6 +1055,34 @@ export default {
|
|||||||
this.scrollMenuToSelectedItem(this.$refs.categoryFilterMenu);
|
this.scrollMenuToSelectedItem(this.$refs.categoryFilterMenu);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
scrollAmountMenuToSelectedItem(opened) {
|
||||||
|
if (opened) {
|
||||||
|
this.currentAmountFilterType = '';
|
||||||
|
|
||||||
|
let amount1 = 0, amount2 = 0;
|
||||||
|
|
||||||
|
if (isString(this.query.amountFilter)) {
|
||||||
|
try {
|
||||||
|
const filterItems = this.query.amountFilter.split(':');
|
||||||
|
const amountCount = this.getAmountFilterParameterCount(filterItems[0]);
|
||||||
|
|
||||||
|
if (filterItems.length === 2 && amountCount === 1) {
|
||||||
|
amount1 = parseInt(filterItems[1]);
|
||||||
|
} else if (filterItems.length === 3 && amountCount === 2) {
|
||||||
|
amount1 = parseInt(filterItems[1]);
|
||||||
|
amount2 = parseInt(filterItems[2]);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
logger.warn('cannot parse amount from filter value, original value is ' + this.query.amountFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentAmountFilterValue1 = amount1;
|
||||||
|
this.currentAmountFilterValue2 = amount2;
|
||||||
|
|
||||||
|
this.scrollMenuToSelectedItem(this.$refs.amountFilterMenu);
|
||||||
|
}
|
||||||
|
},
|
||||||
scrollAccountMenuToSelectedItem(opened) {
|
scrollAccountMenuToSelectedItem(opened) {
|
||||||
if (opened) {
|
if (opened) {
|
||||||
this.scrollMenuToSelectedItem(this.$refs.accountFilterMenu);
|
this.scrollMenuToSelectedItem(this.$refs.accountFilterMenu);
|
||||||
@@ -1005,6 +1159,10 @@ export default {
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
getAmountFilterParameterCount(filterType) {
|
||||||
|
const amountFilterType = numeralConstants.allAmountFilterTypeMap[filterType];
|
||||||
|
return amountFilterType ? amountFilterType.paramCount : 0;
|
||||||
|
},
|
||||||
getFilterLinkUrl() {
|
getFilterLinkUrl() {
|
||||||
return `/transaction/list?${this.transactionsStore.getTransactionListPageParams()}`;
|
return `/transaction/list?${this.transactionsStore.getTransactionListPageParams()}`;
|
||||||
}
|
}
|
||||||
@@ -1071,11 +1229,21 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.transaction-category-menu .item-icon,
|
.transaction-category-menu .item-icon,
|
||||||
|
.transaction-amount-menu .item-icon,
|
||||||
.transaction-account-menu .item-icon,
|
.transaction-account-menu .item-icon,
|
||||||
.transaction-table .item-icon {
|
.transaction-table .item-icon {
|
||||||
padding-bottom: 3px;
|
padding-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transaction-amount-filter-value {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transaction-amount-filter-value input.v-field__input {
|
||||||
|
min-height: 32px !important;
|
||||||
|
padding: 0 8px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.transaction-category-menu .has-children-item-selected span {
|
.transaction-category-menu .has-children-item-selected span {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
<template>
|
||||||
|
<f7-page @page:afterin="onPageAfterIn">
|
||||||
|
<f7-navbar>
|
||||||
|
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
||||||
|
<f7-nav-title :title="$t('Filter Amount')"></f7-nav-title>
|
||||||
|
<f7-nav-right>
|
||||||
|
<f7-link :text="$t('Apply')" @click="confirm"></f7-link>
|
||||||
|
</f7-nav-right>
|
||||||
|
</f7-navbar>
|
||||||
|
|
||||||
|
<f7-list form strong inset dividers class="margin-vertical">
|
||||||
|
<f7-list-item
|
||||||
|
class="ebk-small-amount"
|
||||||
|
link="#" no-chevron
|
||||||
|
:header="amount1Header"
|
||||||
|
:title="getDisplayAmount(amount1)"
|
||||||
|
@click="showAmount1Sheet = true"
|
||||||
|
>
|
||||||
|
<number-pad-sheet :min-value="allowedMinAmount"
|
||||||
|
:max-value="allowedMaxAmount"
|
||||||
|
v-model:show="showAmount1Sheet"
|
||||||
|
v-model="amount1"
|
||||||
|
></number-pad-sheet>
|
||||||
|
</f7-list-item>
|
||||||
|
|
||||||
|
<f7-list-item
|
||||||
|
class="ebk-small-amount"
|
||||||
|
link="#" no-chevron
|
||||||
|
:header="amount2Header"
|
||||||
|
:title="getDisplayAmount(amount2)"
|
||||||
|
@click="showAmount2Sheet = true"
|
||||||
|
v-if="amountCount === 2"
|
||||||
|
>
|
||||||
|
<number-pad-sheet :min-value="allowedMinAmount"
|
||||||
|
:max-value="allowedMaxAmount"
|
||||||
|
v-model:show="showAmount2Sheet"
|
||||||
|
v-model="amount2"
|
||||||
|
></number-pad-sheet>
|
||||||
|
</f7-list-item>
|
||||||
|
</f7-list>
|
||||||
|
|
||||||
|
<f7-list form strong inset dividers class="margin-vertical">
|
||||||
|
<f7-list-item :key="filterType.type" :title="$t(filterType.name)"
|
||||||
|
v-for="filterType in allAmountFilterTypes"
|
||||||
|
@click="type = filterType.type">
|
||||||
|
<template #after>
|
||||||
|
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="type === filterType.type"></f7-icon>
|
||||||
|
</template>
|
||||||
|
</f7-list-item>
|
||||||
|
</f7-list>
|
||||||
|
</f7-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapStores } from 'pinia';
|
||||||
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
|
import { useUserStore } from '@/stores/user.js';
|
||||||
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
|
|
||||||
|
import numeralConstants from '@/consts/numeral.js';
|
||||||
|
import transactionConstants from '@/consts/transaction.js';
|
||||||
|
import { isString } from '@/lib/common.js';
|
||||||
|
import logger from '@/lib/logger.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: [
|
||||||
|
'f7route',
|
||||||
|
'f7router'
|
||||||
|
],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
type: '',
|
||||||
|
amount1: 0,
|
||||||
|
amount2: 0,
|
||||||
|
showAmount1Sheet: false,
|
||||||
|
showAmount2Sheet: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapStores(useSettingsStore, useUserStore, useTransactionsStore),
|
||||||
|
allAmountFilterTypes() {
|
||||||
|
return numeralConstants.allAmountFilterTypeArray;
|
||||||
|
},
|
||||||
|
allowedMinAmount() {
|
||||||
|
return transactionConstants.minAmountNumber;
|
||||||
|
},
|
||||||
|
allowedMaxAmount() {
|
||||||
|
return transactionConstants.maxAmountNumber;
|
||||||
|
},
|
||||||
|
amountCount() {
|
||||||
|
return this.getAmountFilterParameterCount(this.type);
|
||||||
|
},
|
||||||
|
title() {
|
||||||
|
const amountFilterType = numeralConstants.allAmountFilterTypeMap[this.type];
|
||||||
|
return amountFilterType ? this.$t(amountFilterType.name) : this.$t('Amount');
|
||||||
|
},
|
||||||
|
amount1Header() {
|
||||||
|
if (this.type === numeralConstants.allAmountFilterType.GreaterThan.type
|
||||||
|
|| this.type === numeralConstants.allAmountFilterType.Between.type
|
||||||
|
|| this.type === numeralConstants.allAmountFilterType.NotBetween.type) {
|
||||||
|
return this.$t('Min Amount');
|
||||||
|
} else if (this.type === numeralConstants.allAmountFilterType.LessThan.type) {
|
||||||
|
return this.$t('Max Amount');
|
||||||
|
} else {
|
||||||
|
return this.$t('Amount');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
amount2Header() {
|
||||||
|
if (this.type === numeralConstants.allAmountFilterType.Between.type) {
|
||||||
|
return this.$t('Max Amount');
|
||||||
|
} else if (this.type === numeralConstants.allAmountFilterType.NotBetween.type) {
|
||||||
|
return this.$t('Max Amount');
|
||||||
|
} else {
|
||||||
|
return this.$t('Amount');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const query = this.f7route.query;
|
||||||
|
this.type = query.type;
|
||||||
|
|
||||||
|
let amount1 = 0, amount2 = 0;
|
||||||
|
|
||||||
|
if (isString(query.value)) {
|
||||||
|
try {
|
||||||
|
const filterItems = query.value.split(':');
|
||||||
|
const amountCount = this.getAmountFilterParameterCount(filterItems[0]);
|
||||||
|
|
||||||
|
if (filterItems.length === 2 && amountCount === 1) {
|
||||||
|
amount1 = parseInt(filterItems[1]);
|
||||||
|
} else if (filterItems.length === 3 && amountCount === 2) {
|
||||||
|
amount1 = parseInt(filterItems[1]);
|
||||||
|
amount2 = parseInt(filterItems[2]);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
logger.warn('cannot parse amount from filter value, original value is ' + query.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.amount1 = amount1;
|
||||||
|
this.amount2 = amount2;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPageAfterIn() {
|
||||||
|
this.$routeBackOnError(this.f7router, 'loadingError');
|
||||||
|
},
|
||||||
|
confirm() {
|
||||||
|
const router = this.f7router;
|
||||||
|
let amountFilter = this.type;
|
||||||
|
|
||||||
|
if (this.amountCount === 1) {
|
||||||
|
amountFilter += ':' + this.amount1;
|
||||||
|
} else if (this.amountCount === 2) {
|
||||||
|
if (this.amount2 < this.amount1) {
|
||||||
|
this.$toast('Incorrect amount range');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountFilter += ':' + this.amount1 + ':' + this.amount2;
|
||||||
|
} else {
|
||||||
|
router.back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transactionsStore.updateTransactionListFilter({
|
||||||
|
amountFilter: amountFilter
|
||||||
|
});
|
||||||
|
this.transactionsStore.updateTransactionListInvalidState(true);
|
||||||
|
router.back();
|
||||||
|
},
|
||||||
|
getDisplayAmount(value) {
|
||||||
|
return this.$locale.formatAmountWithCurrency(this.settingsStore, this.userStore, value, false);
|
||||||
|
},
|
||||||
|
getAmountFilterParameterCount(filterType) {
|
||||||
|
const amountFilterType = numeralConstants.allAmountFilterTypeMap[filterType];
|
||||||
|
return amountFilterType ? amountFilterType.paramCount : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
<span :class="{ 'tabbar-item-changed': query.accountId > 0 }">{{ queryAccountName }}</span>
|
<span :class="{ 'tabbar-item-changed': query.accountId > 0 }">{{ queryAccountName }}</span>
|
||||||
</f7-link>
|
</f7-link>
|
||||||
<f7-link popover-open=".more-popover-menu">
|
<f7-link popover-open=".more-popover-menu">
|
||||||
<f7-icon f7="ellipsis_vertical" :class="{ 'tabbar-item-changed': query.type > 0 }"></f7-icon>
|
<f7-icon f7="ellipsis_vertical" :class="{ 'tabbar-item-changed': query.type > 0 || query.amountFilter }"></f7-icon>
|
||||||
</f7-link>
|
</f7-link>
|
||||||
</f7-toolbar>
|
</f7-toolbar>
|
||||||
|
|
||||||
@@ -403,6 +403,23 @@
|
|||||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.type === 4"></f7-icon>
|
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.type === 4"></f7-icon>
|
||||||
</template>
|
</template>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
|
<f7-list-item group-title :title="$t('Amount')" />
|
||||||
|
<f7-list-item :class="{ 'list-item-selected': !query.amountFilter }" :title="$t('All')" @click="changeAmountFilter('')">
|
||||||
|
<template #after>
|
||||||
|
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="!query.amountFilter"></f7-icon>
|
||||||
|
</template>
|
||||||
|
</f7-list-item>
|
||||||
|
<f7-list-item :key="filterType.type"
|
||||||
|
:class="{ 'list-item-selected': query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) }"
|
||||||
|
:title="$t(filterType.name)"
|
||||||
|
v-for="filterType in allAmountFilterTypes"
|
||||||
|
@click="changeAmountFilter(filterType.type)">
|
||||||
|
<template #after>
|
||||||
|
<span class="margin-right-half" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`)">{{ queryAmount }}</span>
|
||||||
|
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`)"></f7-icon>
|
||||||
|
</template>
|
||||||
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-popover>
|
</f7-popover>
|
||||||
|
|
||||||
@@ -426,6 +443,7 @@ import { useAccountsStore } from '@/stores/account.js';
|
|||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
|
|
||||||
|
import numeralConstants from '@/consts/numeral.js';
|
||||||
import datetimeConstants from '@/consts/datetime.js';
|
import datetimeConstants from '@/consts/datetime.js';
|
||||||
import currencyConstants from '@/consts/currency.js';
|
import currencyConstants from '@/consts/currency.js';
|
||||||
import accountConstants from '@/consts/account.js';
|
import accountConstants from '@/consts/account.js';
|
||||||
@@ -518,6 +536,25 @@ export default {
|
|||||||
queryAccountName() {
|
queryAccountName() {
|
||||||
return getNameByKeyValue(this.allAccounts, this.query.accountId, null, 'name', this.$t('Account'));
|
return getNameByKeyValue(this.allAccounts, this.query.accountId, null, 'name', this.$t('Account'));
|
||||||
},
|
},
|
||||||
|
queryAmount() {
|
||||||
|
if (!this.query.amountFilter) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const amountFilterItems = this.query.amountFilter.split(':');
|
||||||
|
|
||||||
|
if (amountFilterItems.length < 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayAmount = [];
|
||||||
|
|
||||||
|
for (let i = 1; i < amountFilterItems.length; i++) {
|
||||||
|
displayAmount.push(this.getDisplayCurrency(amountFilterItems[i], false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayAmount.join(' ~ ');
|
||||||
|
},
|
||||||
transactions() {
|
transactions() {
|
||||||
if (this.loading) {
|
if (this.loading) {
|
||||||
return [];
|
return [];
|
||||||
@@ -531,6 +568,9 @@ export default {
|
|||||||
hasMoreTransaction() {
|
hasMoreTransaction() {
|
||||||
return this.transactionsStore.hasMoreTransaction;
|
return this.transactionsStore.hasMoreTransaction;
|
||||||
},
|
},
|
||||||
|
allAmountFilterTypes() {
|
||||||
|
return numeralConstants.allAmountFilterTypeArray;
|
||||||
|
},
|
||||||
allTransactionTypes() {
|
allTransactionTypes() {
|
||||||
return transactionConstants.allTransactionTypes;
|
return transactionConstants.allTransactionTypes;
|
||||||
},
|
},
|
||||||
@@ -777,6 +817,24 @@ export default {
|
|||||||
this.showAccountPopover = false;
|
this.showAccountPopover = false;
|
||||||
this.reload(null);
|
this.reload(null);
|
||||||
},
|
},
|
||||||
|
changeAmountFilter(filterType) {
|
||||||
|
if (this.query.amountFilter === filterType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterType) {
|
||||||
|
this.showMorePopover = false;
|
||||||
|
this.f7router.navigate(`/transaction/filter/amount?type=${filterType}&value=${this.query.amountFilter}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transactionsStore.updateTransactionListFilter({
|
||||||
|
amountFilter: filterType
|
||||||
|
});
|
||||||
|
|
||||||
|
this.showMorePopover = false;
|
||||||
|
this.reload(null);
|
||||||
|
},
|
||||||
changeKeywordFilter(keyword) {
|
changeKeywordFilter(keyword) {
|
||||||
if (this.query.keyword === keyword) {
|
if (this.query.keyword === keyword) {
|
||||||
return;
|
return;
|
||||||
@@ -1008,7 +1066,10 @@ export default {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-popover-menu .popover-inner, .category-popover-menu .popover-inner, .account-popover-menu .popover-inner {
|
.date-popover-menu .popover-inner,
|
||||||
|
.category-popover-menu .popover-inner,
|
||||||
|
.account-popover-menu .popover-inner,
|
||||||
|
.more-popover-menu .popover-inner{
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user