From 2e1a9362fcad43aa68f7855462ae8ff3279c69d5 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Mon, 30 Jun 2025 23:49:01 +0800 Subject: [PATCH] export transaction data based on the conditions on the transaction list page (#55) --- pkg/api/data_managements.go | 47 ++++++++++++++- pkg/models/data_management.go | 13 ++++ pkg/models/transaction.go | 8 +-- pkg/services/transactions.go | 28 +++++++++ src/lib/services.ts | 17 +++++- src/locales/de.json | 3 + src/locales/en.json | 3 + src/locales/es.json | 3 + src/locales/it.json | 3 + src/locales/ja.json | 3 + src/locales/pt_BR.json | 3 + src/locales/ru.json | 3 + src/locales/uk.json | 3 + src/locales/vi.json | 3 + src/locales/zh_Hans.json | 3 + src/locales/zh_Hant.json | 3 + src/models/data_management.ts | 12 ++++ src/stores/transaction.ts | 18 ++++++ src/stores/user.ts | 5 +- src/views/desktop/transactions/ListPage.vue | 66 ++++++++++++++++++++- 20 files changed, 236 insertions(+), 11 deletions(-) diff --git a/pkg/api/data_managements.go b/pkg/api/data_managements.go index 0fdb0ffd..f15b193e 100644 --- a/pkg/api/data_managements.go +++ b/pkg/api/data_managements.go @@ -197,6 +197,14 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType return nil, "", errs.ErrDataExportNotAllowed } + var exportTransactionDataReq models.ExportTransactionDataRequest + err := c.ShouldBindQuery(&exportTransactionDataReq) + + if err != nil { + log.Warnf(c, "[data_managements.ExportDataHandler] parse request failed, because %s", err.Error()) + return nil, "", errs.NewIncompleteOrIncorrectSubmissionError(err) + } + timezone := time.Local utcOffset, err := c.GetClientTimezoneOffset() @@ -253,7 +261,44 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType categoryMap := a.categories.GetCategoryMapByList(categories) tagMap := a.tags.GetTagMapByList(tags) - allTransactions, err := a.transactions.GetAllTransactions(c, uid, pageCountForDataExport, true) + allAccountIds, err := a.accounts.GetAccountOrSubAccountIds(c, exportTransactionDataReq.AccountIds, uid) + + if err != nil { + log.Warnf(c, "[data_managements.ExportDataHandler] get account error, because %s", err.Error()) + return nil, "", errs.Or(err, errs.ErrOperationFailed) + } + + allCategoryIds, err := a.categories.GetCategoryOrSubCategoryIds(c, exportTransactionDataReq.CategoryIds, uid) + + if err != nil { + log.Warnf(c, "[data_managements.ExportDataHandler] get transaction category error, because %s", err.Error()) + return nil, "", errs.Or(err, errs.ErrOperationFailed) + } + + var allTagIds []int64 + noTags := exportTransactionDataReq.TagIds == "none" + + if !noTags { + allTagIds, err = a.tags.GetTagIds(exportTransactionDataReq.TagIds) + + if err != nil { + log.Warnf(c, "[data_managements.ExportDataHandler] get transaction tag ids error, because %s", err.Error()) + return nil, "", errs.Or(err, errs.ErrOperationFailed) + } + } + + maxTransactionTime := utils.GetMaxTransactionTimeFromUnixTime(time.Now().Unix()) + minTransactionTime := int64(0) + + if exportTransactionDataReq.MaxTime > 0 { + maxTransactionTime = utils.GetMaxTransactionTimeFromUnixTime(exportTransactionDataReq.MaxTime) + } + + if exportTransactionDataReq.MinTime > 0 { + minTransactionTime = utils.GetMinTransactionTimeFromUnixTime(exportTransactionDataReq.MinTime) + } + + allTransactions, err := a.transactions.GetAllSpecifiedTransactions(c, uid, maxTransactionTime, minTransactionTime, exportTransactionDataReq.Type, allCategoryIds, allAccountIds, allTagIds, noTags, exportTransactionDataReq.TagFilterType, exportTransactionDataReq.AmountFilter, exportTransactionDataReq.Keyword, pageCountForDataExport, true) if err != nil { log.Errorf(c, "[data_managements.ExportDataHandler] failed to all transactions user \"uid:%d\", because %s", uid, err.Error()) diff --git a/pkg/models/data_management.go b/pkg/models/data_management.go index 3efa6307..8bd1be2a 100644 --- a/pkg/models/data_management.go +++ b/pkg/models/data_management.go @@ -15,3 +15,16 @@ type DataStatisticsResponse struct { TotalTransactionTemplateCount int64 `json:"totalTransactionTemplateCount,string"` TotalScheduledTransactionCount int64 `json:"totalScheduledTransactionCount,string"` } + +// ExportTransactionDataRequest represents export transaction request +type ExportTransactionDataRequest struct { + Type TransactionType `form:"type" binding:"min=0,max=4"` + CategoryIds string `form:"category_ids"` + AccountIds string `form:"account_ids"` + TagIds string `form:"tag_ids"` + TagFilterType TransactionTagFilterType `form:"tag_filter_type" binding:"min=0,max=3"` + AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` + Keyword string `form:"keyword"` + MaxTime int64 `form:"max_time" binding:"min=0"` // Unix timestamp in seconds + MinTime int64 `form:"min_time" binding:"min=0"` // Unix timestamp in seconds +} diff --git a/pkg/models/transaction.go b/pkg/models/transaction.go index da04c6c4..c04ca894 100644 --- a/pkg/models/transaction.go +++ b/pkg/models/transaction.go @@ -178,8 +178,8 @@ type TransactionCountRequest struct { TagFilterType TransactionTagFilterType `form:"tag_filter_type" binding:"min=0,max=3"` AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` Keyword string `form:"keyword"` - MaxTime int64 `form:"max_time" binding:"min=0"` - MinTime int64 `form:"min_time" binding:"min=0"` + 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 @@ -191,8 +191,8 @@ type TransactionListByMaxTimeRequest struct { TagFilterType TransactionTagFilterType `form:"tag_filter_type" binding:"min=0,max=3"` AmountFilter string `form:"amount_filter" binding:"validAmountFilter"` Keyword string `form:"keyword"` - MaxTime int64 `form:"max_time" binding:"min=0"` - MinTime int64 `form:"min_time" binding:"min=0"` + 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"` diff --git a/pkg/services/transactions.go b/pkg/services/transactions.go index 696abbef..04a0ab22 100644 --- a/pkg/services/transactions.go +++ b/pkg/services/transactions.go @@ -79,6 +79,34 @@ func (s *TransactionService) GetAllTransactionsByMaxTime(c core.Context, uid int return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, models.TRANSACTION_TAG_FILTER_HAS_ANY, "", "", 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, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, amountFilter string, keyword string, pageCount int32, noDuplicated bool) ([]*models.Transaction, error) { + if maxTransactionTime <= 0 { + maxTransactionTime = utils.GetMaxTransactionTimeFromUnixTime(time.Now().Unix()) + } + + var allTransactions []*models.Transaction + + for maxTransactionTime > 0 { + transactions, err := s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, minTransactionTime, transactionType, categoryIds, accountIds, tagIds, noTags, tagFilterType, amountFilter, keyword, 1, pageCount, false, noDuplicated) + + if err != nil { + return nil, err + } + + allTransactions = append(allTransactions, transactions...) + + if len(transactions) < int(pageCount) { + maxTransactionTime = 0 + break + } + + maxTransactionTime = transactions[len(transactions)-1].TransactionTime - 1 + } + + return allTransactions, nil +} + // 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, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, amountFilter string, keyword string, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) { if uid <= 0 { diff --git a/src/lib/services.ts b/src/lib/services.ts index 3a322db8..effec309 100644 --- a/src/lib/services.ts +++ b/src/lib/services.ts @@ -39,6 +39,7 @@ import type { RegisterResponse } from '@/models/auth_response.ts'; import type { + ExportTransactionDataRequest, ClearDataRequest, DataStatisticsResponse } from '@/models/data_management.ts'; @@ -344,13 +345,23 @@ export default { getUserDataStatistics: (): ApiResponsePromise => { return axios.get>('v1/data/statistics.json'); }, - getExportedUserData: (fileType: string): Promise> => { + getExportedUserData: (fileType: string, req?: ExportTransactionDataRequest): Promise> => { + let params = ''; + + if (req) { + const amountFilter = encodeURIComponent(req.amountFilter); + const keyword = encodeURIComponent(req.keyword); + params = `max_time=${req.maxTime}&min_time=${req.minTime}&type=${req.type}&category_ids=${req.categoryIds}&account_ids=${req.accountIds}&tag_ids=${req.tagIds}&tag_filter_type=${req.tagFilterType}&amount_filter=${amountFilter}&keyword=${keyword}`; + } else { + params = 'max_time=0&min_time=0&type=0&category_ids=&account_ids=&tag_ids=&tag_filter_type=0&amount_filter=&keyword='; + } + if (fileType === 'csv') { - return axios.get('v1/data/export.csv', { + return axios.get('v1/data/export.csv?' + params, { timeout: DEFAULT_EXPORT_API_TIMEOUT } as ApiRequestConfig); } else if (fileType === 'tsv') { - return axios.get('v1/data/export.tsv', { + return axios.get('v1/data/export.tsv?' + params, { timeout: DEFAULT_EXPORT_API_TIMEOUT } as ApiRequestConfig); } else { diff --git a/src/locales/de.json b/src/locales/de.json index 7d0621ac..a8330531 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1322,6 +1322,7 @@ "Submit": "Einreichen", "Add": "Hinzufügen", "Import": "Importieren", + "Export": "Export", "Apply": "Anwenden", "Save": "Speichern", "Save Changes": "Änderungen speichern", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "CSV (Kommagetrennte Werte) Datei", "TSV (Tab-separated values) File": "TSV (Tabulatorgetrennte Werte) Datei", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Benutzerdaten löschen", "Export all transaction data to file.": "Alle Transaktionsdaten in Datei exportieren.", diff --git a/src/locales/en.json b/src/locales/en.json index cd409f54..7853d4dd 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1322,6 +1322,7 @@ "Submit": "Submit", "Add": "Add", "Import": "Import", + "Export": "Export", "Apply": "Apply", "Save": "Save", "Save Changes": "Save Changes", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "CSV (Comma-separated values) File", "TSV (Tab-separated values) File": "TSV (Tab-separated values) File", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Clear User Data", "Export all transaction data to file.": "Export all transaction data to file.", diff --git a/src/locales/es.json b/src/locales/es.json index 87e2c1ec..55f831e9 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1322,6 +1322,7 @@ "Submit": "Enviar", "Add": "Agregar", "Import": "Importar", + "Export": "Export", "Apply": "Aplicar", "Save": "Guardar", "Save Changes": "Guardar cambios", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "Archivo CSV (valores separados por comas)", "TSV (Tab-separated values) File": "Archivo TSV (valores separados por tabulaciones)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Borrar datos de usuario", "Export all transaction data to file.": "Exportar todos los datos de la transacción a un archivo.", diff --git a/src/locales/it.json b/src/locales/it.json index 22a59da9..80029c36 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1322,6 +1322,7 @@ "Submit": "Invia", "Add": "Aggiungi", "Import": "Importa", + "Export": "Export", "Apply": "Applica", "Save": "Salva", "Save Changes": "Salva modifiche", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "File CSV (valori separati da virgola)", "TSV (Tab-separated values) File": "File TSV (valori separati da tabulazione)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Cancella dati utente", "Export all transaction data to file.": "Esporta tutti i dati delle transazioni in un file.", diff --git a/src/locales/ja.json b/src/locales/ja.json index a8c41b25..f0343476 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1322,6 +1322,7 @@ "Submit": "送信", "Add": "追加", "Import": "インポート", + "Export": "Export", "Apply": "適用", "Save": "保存", "Save Changes": "変更を保存", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "CSV(コンマ区切り)ファイル", "TSV (Tab-separated values) File": "TSV(タブ区切り)ファイル", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "ユーザーデータをクリア", "Export all transaction data to file.": "すべての取引データをファイルにエクスポートします。", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 332afaed..fc405268 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1322,6 +1322,7 @@ "Submit": "Enviar", "Add": "Adicionar", "Import": "Importar", + "Export": "Export", "Apply": "Aplicar", "Save": "Salvar", "Save Changes": "Salvar Alterações", @@ -1941,6 +1942,8 @@ "File Format": "Formato de Arquivo", "CSV (Comma-separated values) File": "Arquivo CSV (Valores separados por vírgulas)", "TSV (Tab-separated values) File": "Arquivo TSV (Valores separados por tabulações)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Arquivo Markdown", "Clear User Data": "Limpar Dados do Usuário", "Export all transaction data to file.": "Exportar todos os dados de transação para arquivo.", diff --git a/src/locales/ru.json b/src/locales/ru.json index 184df1b6..efcbe126 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1322,6 +1322,7 @@ "Submit": "Отправить", "Add": "Добавить", "Import": "Импорт", + "Export": "Export", "Apply": "Применить", "Save": "Сохранить", "Save Changes": "Сохранить изменения", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "Файл CSV (значения, разделенные запятыми)", "TSV (Tab-separated values) File": "Файл TSV (значения, разделенные табуляцией)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Очистить данные пользователя", "Export all transaction data to file.": "Экспортировать все данные о транзакциях в файл.", diff --git a/src/locales/uk.json b/src/locales/uk.json index 1f04ede3..7cf38df2 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1322,6 +1322,7 @@ "Submit": "Підтвердити", "Add": "Додати", "Import": "Імпортувати", + "Export": "Export", "Apply": "Застосувати", "Save": "Зберегти", "Save Changes": "Зберегти зміни", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "Файл CSV (значення, розділені комами)", "TSV (Tab-separated values) File": "Файл TSV (значення, розділені табуляцією)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Очистити дані користувача", "Export all transaction data to file.": "Експортувати всі транзакції у файл.", diff --git a/src/locales/vi.json b/src/locales/vi.json index c9549b68..874c61d6 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1322,6 +1322,7 @@ "Submit": "Gửi", "Add": "Thêm", "Import": "Nhập", + "Export": "Export", "Apply": "Áp dụng", "Save": "Lưu", "Save Changes": "Lưu thay đổi", @@ -1941,6 +1942,8 @@ "File Format": "File Format", "CSV (Comma-separated values) File": "Tệp CSV (Giá trị phân cách bằng dấu phẩy)", "TSV (Tab-separated values) File": "Tệp TSV (Giá trị phân cách bằng tab)", + "Export to CSV (Comma-separated values) File": "Export to CSV (Comma-separated values) File", + "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Markdown File": "Markdown File", "Clear User Data": "Xóa dữ liệu người dùng", "Export all transaction data to file.": "Xuất tất cả dữ liệu giao dịch sang tệp.", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 683a04b5..6f76df03 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1322,6 +1322,7 @@ "Submit": "提交", "Add": "添加", "Import": "导入", + "Export": "导出", "Apply": "应用", "Save": "保存", "Save Changes": "保存修改", @@ -1941,6 +1942,8 @@ "File Format": "文件格式", "CSV (Comma-separated values) File": "CSV (逗号分隔的值) 文件", "TSV (Tab-separated values) File": "TSV (制表符分隔的值) 文件", + "Export to CSV (Comma-separated values) File": "导出到 CSV (逗号分隔的值) 文件", + "Export to TSV (Tab-separated values) File": "导出到 TSV (制表符分隔的值) 文件", "Markdown File": "Markdown 文件", "Clear User Data": "清除用户数据", "Export all transaction data to file.": "导出所有交易数据到文件。", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 0e8db2aa..1fa4f931 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1322,6 +1322,7 @@ "Submit": "提交", "Add": "新增", "Import": "匯入", + "Export": "匯出", "Apply": "套用", "Save": "儲存", "Save Changes": "儲存修改", @@ -1941,6 +1942,8 @@ "File Format": "檔案格式", "CSV (Comma-separated values) File": "CSV (逗號分隔的值) 檔案", "TSV (Tab-separated values) File": "TSV (定位點分隔的值) 檔案", + "Export to CSV (Comma-separated values) File": "匯出為 CSV (逗號分隔的值) 檔案", + "Export to TSV (Tab-separated values) File": "匯出為 TSV (定位點分隔的值) 檔案", "Markdown File": "Markdown 檔案", "Clear User Data": "清除使用者資料", "Export all transaction data to file.": "匯出所有交易資料到檔案。", diff --git a/src/models/data_management.ts b/src/models/data_management.ts index 521f6bc5..dbee88f3 100644 --- a/src/models/data_management.ts +++ b/src/models/data_management.ts @@ -1,3 +1,15 @@ +export interface ExportTransactionDataRequest { + readonly maxTime: number; + readonly minTime: number; + readonly type: number; + readonly categoryIds: string; + readonly accountIds: string; + readonly tagIds: string; + readonly tagFilterType: number; + readonly amountFilter: string; + readonly keyword: string; +} + export interface ClearDataRequest { readonly password: string; } diff --git a/src/stores/transaction.ts b/src/stores/transaction.ts index c3ce8ec7..878df3e5 100644 --- a/src/stores/transaction.ts +++ b/src/stores/transaction.ts @@ -29,6 +29,9 @@ import { type ImportTransactionResponsePageWrapper, ImportTransaction } from '@/models/imported_transaction.ts'; +import { + type ExportTransactionDataRequest +} from '@/models/data_management.ts'; import { getUserTransactionDraft, @@ -780,6 +783,20 @@ export const useTransactionsStore = defineStore('transactions', () => { return querys.join('&'); } + function getExportTransactionDataRequestByTransactionFilter(): ExportTransactionDataRequest { + return { + maxTime: transactionsFilter.value.maxTime, + minTime: transactionsFilter.value.minTime, + type: transactionsFilter.value.type, + categoryIds: transactionsFilter.value.categoryIds, + accountIds: transactionsFilter.value.accountIds, + tagIds: transactionsFilter.value.tagIds, + tagFilterType: transactionsFilter.value.tagFilterType, + amountFilter: transactionsFilter.value.amountFilter, + keyword: transactionsFilter.value.keyword + }; + } + function loadTransactions({ reload, count, page, withCount, autoExpand, defaultCurrency }: { reload?: boolean, count?: number, page?: number, withCount?: boolean, autoExpand: boolean, defaultCurrency: string }): Promise { let actualMaxTime = transactionsNextTimeId.value; @@ -1308,6 +1325,7 @@ export const useTransactionsStore = defineStore('transactions', () => { initTransactionListFilter, updateTransactionListFilter, getTransactionListPageParams, + getExportTransactionDataRequestByTransactionFilter, loadTransactions, loadMonthlyAllTransactions, getTransaction, diff --git a/src/stores/user.ts b/src/stores/user.ts index 4f7a560c..4edb3300 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -16,6 +16,7 @@ import { } from '@/models/user.ts'; import type { + ExportTransactionDataRequest, DataStatisticsResponse } from '@/models/data_management.ts'; @@ -360,9 +361,9 @@ export const useUserStore = defineStore('user', () => { }); } - function getExportedUserData(fileType: string): Promise { + function getExportedUserData(fileType: string, req?: ExportTransactionDataRequest): Promise { return new Promise((resolve, reject) => { - services.getExportedUserData(fileType).then(response => { + services.getExportedUserData(fileType, req).then(response => { if (response && response.headers) { if (fileType === 'csv' && response.headers['content-type'] !== 'text/csv') { reject({ message: 'Unable to retrieve exported user data' }); diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index 86f618de..1f8d6d03 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -74,6 +74,34 @@ :disabled="loading" @click="importTransaction" v-if="isDataImportingEnabled()"> {{ tt('Import') }} + + + + {{ tt('Export to CSV (Comma-separated values) File') }} + + + {{ tt('Export to TSV (Tab-separated values) File') }} + + + + + + {{ tt('Export') }} + + + + {{ tt('Export to CSV (Comma-separated values) File') }} + + + {{ tt('Export to TSV (Tab-separated values) File') }} + + + @@ -652,6 +680,7 @@ import { useI18n } from '@/locales/helpers.ts'; import { TransactionListPageType, useTransactionListPageBase } from '@/views/base/transactions/TransactionListPageBase.ts'; import { useSettingsStore } from '@/stores/setting.ts'; +import { useUserStore } from '@/stores/user.ts'; import { useAccountsStore } from '@/stores/account.ts'; import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; @@ -704,7 +733,8 @@ import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts'; -import { isDataImportingEnabled } from '@/lib/server_settings.ts'; +import { isDataExportingEnabled, isDataImportingEnabled } from '@/lib/server_settings.ts'; +import { startDownloadFile } from '@/lib/ui/common.ts'; import { scrollToSelectedItem } from '@/lib/ui/desktop.ts'; import logger from '@/lib/logger.ts'; @@ -823,6 +853,7 @@ const { } = useTransactionListPageBase(); const settingsStore = useSettingsStore(); +const userStore = useUserStore(); const accountsStore = useAccountsStore(); const transactionCategoriesStore = useTransactionCategoriesStore(); const transactionTagsStore = useTransactionTagsStore(); @@ -859,6 +890,7 @@ const currentAmountFilterValue2 = ref(0); const currentPageTransactions = ref([]); const categoryMenuState = ref(false); const amountMenuState = ref(false); +const exportingData = ref(false); const alwaysShowNav = ref(display.mdAndUp.value); const showNav = ref(display.mdAndUp.value); const showCustomDateRangeDialog = ref(false); @@ -1574,6 +1606,38 @@ function importTransaction(): void { }); } +function exportTransactions(fileExtension: string): void { + if (exportingData.value) { + return; + } + + const nickname = userStore.currentUserNickname; + let exportFileName = ''; + + if (nickname) { + exportFileName = tt('dataExport.exportFilename', { + nickname: nickname + }) + '.' + fileExtension; + } else { + exportFileName = tt('dataExport.defaultExportFilename') + '.' + fileExtension; + } + + const exportTransactionReq = transactionsStore.getExportTransactionDataRequestByTransactionFilter(); + + exportingData.value = true; + + userStore.getExportedUserData(fileExtension, exportTransactionReq).then(data => { + startDownloadFile(exportFileName, data); + exportingData.value = false; + }).catch(error => { + exportingData.value = false; + + if (!error.processed) { + snackbar.value?.showError(error); + } + }); +} + function show(transaction: Transaction): void { if (transaction.type === TransactionType.ModifyBalance) { return;