export statistics & analysis data in desktop version
This commit is contained in:
@@ -25,6 +25,9 @@ import {
|
|||||||
isArray,
|
isArray,
|
||||||
isNumber
|
isNumber
|
||||||
} from '@/lib/common.ts';
|
} from '@/lib/common.ts';
|
||||||
|
import {
|
||||||
|
formatAmount
|
||||||
|
} from '@/lib/numeral.ts';
|
||||||
import {
|
import {
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime,
|
getYearMonthLastUnixTime,
|
||||||
@@ -420,9 +423,38 @@ function clickItem(e: ECElementEvent): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportData(): { headers: string[], data: string[][] } {
|
||||||
|
const headers: string[] = [];
|
||||||
|
const data: string[][] = [];
|
||||||
|
|
||||||
|
headers.push(tt('Date'));
|
||||||
|
|
||||||
|
for (let i = 0; i < allSeries.value.length; i++) {
|
||||||
|
const id = allSeries.value[i].id;
|
||||||
|
const name = itemsMap.value[id] && props.nameField && itemsMap.value[id][props.nameField] ? getItemName(itemsMap.value[id][props.nameField] as string) : id;
|
||||||
|
headers.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < allDisplayDateRanges.value.length; i++) {
|
||||||
|
const row: string[] = [];
|
||||||
|
row.push(allDisplayDateRanges.value[i]);
|
||||||
|
row.push(...allSeries.value.map(item => formatAmount(item.data[i], {})));
|
||||||
|
data.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
headers: headers,
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function onLegendSelectChanged(e: { selected: Record<string, boolean> }): void {
|
function onLegendSelectChanged(e: { selected: Record<string, boolean> }): void {
|
||||||
selectedLegends.value = e.selected;
|
selectedLegends.value = e.selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
exportData
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Alle ungültigen Elemente auswählen",
|
"Select All Invalid Items": "Alle ungültigen Elemente auswählen",
|
||||||
"Back": "Zurück",
|
"Back": "Zurück",
|
||||||
"Load More": "Mehr laden",
|
"Load More": "Mehr laden",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Keine Daten",
|
"No data": "Keine Daten",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Vergrößern",
|
"Zoom in": "Vergrößern",
|
||||||
"Zoom out": "Verkleinern",
|
"Zoom out": "Verkleinern",
|
||||||
"Drag to Reorder": "Zum Neuanordnen ziehen",
|
"Drag to Reorder": "Zum Neuanordnen ziehen",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Höchstbetrag",
|
"Maximum Amount": "Höchstbetrag",
|
||||||
"Display Order": "Anzeigereihenfolge",
|
"Display Order": "Anzeigereihenfolge",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Nach Betrag sortieren",
|
"Sort by Amount": "Nach Betrag sortieren",
|
||||||
"Sort by Display Order": "Nach Anzeigereihenfolge sortieren",
|
"Sort by Display Order": "Nach Anzeigereihenfolge sortieren",
|
||||||
"Sort by Name": "Nach Name sortieren",
|
"Sort by Name": "Nach Name sortieren",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Datenverwaltung",
|
"Data Management": "Datenverwaltung",
|
||||||
"Unable to retrieve user statistics data": "Benutzerstatistikdaten können nicht abgerufen werden",
|
"Unable to retrieve user statistics data": "Benutzerstatistikdaten können nicht abgerufen werden",
|
||||||
"Export Data": "Daten exportieren",
|
"Export Data": "Daten exportieren",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "CSV (Kommagetrennte Werte) Datei",
|
"CSV (Comma-separated values) File": "CSV (Kommagetrennte Werte) Datei",
|
||||||
"TSV (Tab-separated values) File": "TSV (Tabulatorgetrennte Werte) Datei",
|
"TSV (Tab-separated values) File": "TSV (Tabulatorgetrennte Werte) Datei",
|
||||||
"Clear User Data": "Benutzerdaten löschen",
|
"Clear User Data": "Benutzerdaten löschen",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Select All Invalid Items",
|
"Select All Invalid Items": "Select All Invalid Items",
|
||||||
"Back": "Back",
|
"Back": "Back",
|
||||||
"Load More": "Load More",
|
"Load More": "Load More",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "No data",
|
"No data": "No data",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Zoom in",
|
"Zoom in": "Zoom in",
|
||||||
"Zoom out": "Zoom out",
|
"Zoom out": "Zoom out",
|
||||||
"Drag to Reorder": "Drag to Reorder",
|
"Drag to Reorder": "Drag to Reorder",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Maximum Amount",
|
"Maximum Amount": "Maximum Amount",
|
||||||
"Display Order": "Display Order",
|
"Display Order": "Display Order",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Sort by Amount",
|
"Sort by Amount": "Sort by Amount",
|
||||||
"Sort by Display Order": "Sort by Display Order",
|
"Sort by Display Order": "Sort by Display Order",
|
||||||
"Sort by Name": "Sort by Name",
|
"Sort by Name": "Sort by Name",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Data Management",
|
"Data Management": "Data Management",
|
||||||
"Unable to retrieve user statistics data": "Unable to retrieve user statistics data",
|
"Unable to retrieve user statistics data": "Unable to retrieve user statistics data",
|
||||||
"Export Data": "Export Data",
|
"Export Data": "Export Data",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "CSV (Comma-separated values) File",
|
"CSV (Comma-separated values) File": "CSV (Comma-separated values) File",
|
||||||
"TSV (Tab-separated values) File": "TSV (Tab-separated values) File",
|
"TSV (Tab-separated values) File": "TSV (Tab-separated values) File",
|
||||||
"Clear User Data": "Clear User Data",
|
"Clear User Data": "Clear User Data",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Seleccionar todos los artículos no válidos",
|
"Select All Invalid Items": "Seleccionar todos los artículos no válidos",
|
||||||
"Back": "Atrás",
|
"Back": "Atrás",
|
||||||
"Load More": "Cargar más",
|
"Load More": "Cargar más",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Sin datos",
|
"No data": "Sin datos",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Acercar",
|
"Zoom in": "Acercar",
|
||||||
"Zoom out": "Alejar",
|
"Zoom out": "Alejar",
|
||||||
"Drag to Reorder": "Arrastrar para reordenar",
|
"Drag to Reorder": "Arrastrar para reordenar",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Importe Máximo",
|
"Maximum Amount": "Importe Máximo",
|
||||||
"Display Order": "Orden de visualización",
|
"Display Order": "Orden de visualización",
|
||||||
"Name": "Nombre",
|
"Name": "Nombre",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Ordenar por Importe",
|
"Sort by Amount": "Ordenar por Importe",
|
||||||
"Sort by Display Order": "Ordenar por orden de visualización",
|
"Sort by Display Order": "Ordenar por orden de visualización",
|
||||||
"Sort by Name": "Ordenar por Nombre",
|
"Sort by Name": "Ordenar por Nombre",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Gestión de datos",
|
"Data Management": "Gestión de datos",
|
||||||
"Unable to retrieve user statistics data": "No se pueden recuperar datos de estadísticas de usuario",
|
"Unable to retrieve user statistics data": "No se pueden recuperar datos de estadísticas de usuario",
|
||||||
"Export Data": "Exportar datos",
|
"Export Data": "Exportar datos",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "Archivo CSV (valores separados por comas)",
|
"CSV (Comma-separated values) File": "Archivo CSV (valores separados por comas)",
|
||||||
"TSV (Tab-separated values) File": "Archivo TSV (valores separados por tabulaciones)",
|
"TSV (Tab-separated values) File": "Archivo TSV (valores separados por tabulaciones)",
|
||||||
"Clear User Data": "Borrar datos de usuario",
|
"Clear User Data": "Borrar datos de usuario",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Seleziona tutti gli elementi non validi",
|
"Select All Invalid Items": "Seleziona tutti gli elementi non validi",
|
||||||
"Back": "Indietro",
|
"Back": "Indietro",
|
||||||
"Load More": "Carica altro",
|
"Load More": "Carica altro",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Nessun dato",
|
"No data": "Nessun dato",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Ingrandisci",
|
"Zoom in": "Ingrandisci",
|
||||||
"Zoom out": "Riduci",
|
"Zoom out": "Riduci",
|
||||||
"Drag to Reorder": "Trascina per riordinare",
|
"Drag to Reorder": "Trascina per riordinare",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Importo massimo",
|
"Maximum Amount": "Importo massimo",
|
||||||
"Display Order": "Ordine di visualizzazione",
|
"Display Order": "Ordine di visualizzazione",
|
||||||
"Name": "Nome",
|
"Name": "Nome",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Ordina per importo",
|
"Sort by Amount": "Ordina per importo",
|
||||||
"Sort by Display Order": "Ordina per ordine di visualizzazione",
|
"Sort by Display Order": "Ordina per ordine di visualizzazione",
|
||||||
"Sort by Name": "Ordina per nome",
|
"Sort by Name": "Ordina per nome",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Gestione dati",
|
"Data Management": "Gestione dati",
|
||||||
"Unable to retrieve user statistics data": "Impossibile recuperare i dati statistici dell'utente",
|
"Unable to retrieve user statistics data": "Impossibile recuperare i dati statistici dell'utente",
|
||||||
"Export Data": "Esporta dati",
|
"Export Data": "Esporta dati",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "File CSV (valori separati da virgola)",
|
"CSV (Comma-separated values) File": "File CSV (valori separati da virgola)",
|
||||||
"TSV (Tab-separated values) File": "File TSV (valori separati da tabulazione)",
|
"TSV (Tab-separated values) File": "File TSV (valori separati da tabulazione)",
|
||||||
"Clear User Data": "Cancella dati utente",
|
"Clear User Data": "Cancella dati utente",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_エクスポートデータ",
|
"defaultExportFilename": "ezBookkeeping_エクスポートデータ",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_エクスポートデータ"
|
"exportFilename": "ezBookkeeping_{nickname}_エクスポートデータ",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "すべての無効なアイテムを選択します",
|
"Select All Invalid Items": "すべての無効なアイテムを選択します",
|
||||||
"Back": "戻る",
|
"Back": "戻る",
|
||||||
"Load More": "さらに読み込む",
|
"Load More": "さらに読み込む",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "データはありません",
|
"No data": "データはありません",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "拡大",
|
"Zoom in": "拡大",
|
||||||
"Zoom out": "縮小",
|
"Zoom out": "縮小",
|
||||||
"Drag to Reorder": "ドラッグして並べ替え",
|
"Drag to Reorder": "ドラッグして並べ替え",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "最大金額",
|
"Maximum Amount": "最大金額",
|
||||||
"Display Order": "表示順",
|
"Display Order": "表示順",
|
||||||
"Name": "名前",
|
"Name": "名前",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "金額で並べ替え",
|
"Sort by Amount": "金額で並べ替え",
|
||||||
"Sort by Display Order": "表示で並べ替え",
|
"Sort by Display Order": "表示で並べ替え",
|
||||||
"Sort by Name": "名前で並べ替え",
|
"Sort by Name": "名前で並べ替え",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "データ管理",
|
"Data Management": "データ管理",
|
||||||
"Unable to retrieve user statistics data": "ユーザー統計データを取得できません",
|
"Unable to retrieve user statistics data": "ユーザー統計データを取得できません",
|
||||||
"Export Data": "データのエクスポート",
|
"Export Data": "データのエクスポート",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "CSV(コンマ区切り)ファイル",
|
"CSV (Comma-separated values) File": "CSV(コンマ区切り)ファイル",
|
||||||
"TSV (Tab-separated values) File": "TSV(タブ区切り)ファイル",
|
"TSV (Tab-separated values) File": "TSV(タブ区切り)ファイル",
|
||||||
"Clear User Data": "ユーザーデータをクリア",
|
"Clear User Data": "ユーザーデータをクリア",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Выбрать все недействительные элементы",
|
"Select All Invalid Items": "Выбрать все недействительные элементы",
|
||||||
"Back": "Назад",
|
"Back": "Назад",
|
||||||
"Load More": "Загрузить еще",
|
"Load More": "Загрузить еще",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Нет данных",
|
"No data": "Нет данных",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Увеличить",
|
"Zoom in": "Увеличить",
|
||||||
"Zoom out": "Уменьшить",
|
"Zoom out": "Уменьшить",
|
||||||
"Drag to Reorder": "Перетащите для изменения порядка",
|
"Drag to Reorder": "Перетащите для изменения порядка",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Максимальная сумма",
|
"Maximum Amount": "Максимальная сумма",
|
||||||
"Display Order": "Порядок отображения",
|
"Display Order": "Порядок отображения",
|
||||||
"Name": "Имя",
|
"Name": "Имя",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Сортировать по сумме",
|
"Sort by Amount": "Сортировать по сумме",
|
||||||
"Sort by Display Order": "Сортировать по порядку отображения",
|
"Sort by Display Order": "Сортировать по порядку отображения",
|
||||||
"Sort by Name": "Сортировать по имени",
|
"Sort by Name": "Сортировать по имени",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Управление данными",
|
"Data Management": "Управление данными",
|
||||||
"Unable to retrieve user statistics data": "Не удалось получить статистические данные пользователя",
|
"Unable to retrieve user statistics data": "Не удалось получить статистические данные пользователя",
|
||||||
"Export Data": "Экспорт данных",
|
"Export Data": "Экспорт данных",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "Файл CSV (значения, разделенные запятыми)",
|
"CSV (Comma-separated values) File": "Файл CSV (значения, разделенные запятыми)",
|
||||||
"TSV (Tab-separated values) File": "Файл TSV (значения, разделенные табуляцией)",
|
"TSV (Tab-separated values) File": "Файл TSV (значения, разделенные табуляцией)",
|
||||||
"Clear User Data": "Очистить данные пользователя",
|
"Clear User Data": "Очистить данные пользователя",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Вибрати всі недійсні елементи",
|
"Select All Invalid Items": "Вибрати всі недійсні елементи",
|
||||||
"Back": "Назад",
|
"Back": "Назад",
|
||||||
"Load More": "Завантажити ще",
|
"Load More": "Завантажити ще",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Немає даних",
|
"No data": "Немає даних",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Збільшити",
|
"Zoom in": "Збільшити",
|
||||||
"Zoom out": "Зменшити",
|
"Zoom out": "Зменшити",
|
||||||
"Drag to Reorder": "Перетягніть для зміни порядку",
|
"Drag to Reorder": "Перетягніть для зміни порядку",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Максимальна сума",
|
"Maximum Amount": "Максимальна сума",
|
||||||
"Display Order": "Порядок відображення",
|
"Display Order": "Порядок відображення",
|
||||||
"Name": "Ім'я",
|
"Name": "Ім'я",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Сортувати за сумою",
|
"Sort by Amount": "Сортувати за сумою",
|
||||||
"Sort by Display Order": "Сортувати за порядком відображення",
|
"Sort by Display Order": "Сортувати за порядком відображення",
|
||||||
"Sort by Name": "Сортувати за назвою",
|
"Sort by Name": "Сортувати за назвою",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Керування даними",
|
"Data Management": "Керування даними",
|
||||||
"Unable to retrieve user statistics data": "Не вдалося отримати статистику користувача",
|
"Unable to retrieve user statistics data": "Не вдалося отримати статистику користувача",
|
||||||
"Export Data": "Експорт даних",
|
"Export Data": "Експорт даних",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "Файл CSV (значення, розділені комами)",
|
"CSV (Comma-separated values) File": "Файл CSV (значення, розділені комами)",
|
||||||
"TSV (Tab-separated values) File": "Файл TSV (значення, розділені табуляцією)",
|
"TSV (Tab-separated values) File": "Файл TSV (значення, розділені табуляцією)",
|
||||||
"Clear User Data": "Очистити дані користувача",
|
"Clear User Data": "Очистити дані користувача",
|
||||||
|
|||||||
+9
-1
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_export_data",
|
"defaultExportFilename": "ezBookkeeping_export_data",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_export_data"
|
"exportFilename": "ezBookkeeping_{nickname}_export_data",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_statistics_data",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_statistics_data"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "Chọn tất cả các mục không hợp lệ",
|
"Select All Invalid Items": "Chọn tất cả các mục không hợp lệ",
|
||||||
"Back": "Quay lại",
|
"Back": "Quay lại",
|
||||||
"Load More": "Tải thêm",
|
"Load More": "Tải thêm",
|
||||||
|
"Export Results": "Export Results",
|
||||||
"No data": "Không có dữ liệu",
|
"No data": "Không có dữ liệu",
|
||||||
|
"Data copied": "Data copied",
|
||||||
|
"Table": "Table",
|
||||||
|
"Raw Data": "Raw Data",
|
||||||
"Zoom in": "Phóng to",
|
"Zoom in": "Phóng to",
|
||||||
"Zoom out": "Thu nhỏ",
|
"Zoom out": "Thu nhỏ",
|
||||||
"Drag to Reorder": "Kéo để sắp xếp lại",
|
"Drag to Reorder": "Kéo để sắp xếp lại",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "Số tiền tối đa",
|
"Maximum Amount": "Số tiền tối đa",
|
||||||
"Display Order": "Thứ tự hiển thị",
|
"Display Order": "Thứ tự hiển thị",
|
||||||
"Name": "Tên",
|
"Name": "Tên",
|
||||||
|
"Proportion (%)": "Proportion (%)",
|
||||||
"Sort by Amount": "Sắp xếp theo số tiền",
|
"Sort by Amount": "Sắp xếp theo số tiền",
|
||||||
"Sort by Display Order": "Sắp xếp theo thứ tự hiển thị",
|
"Sort by Display Order": "Sắp xếp theo thứ tự hiển thị",
|
||||||
"Sort by Name": "Sắp xếp theo tên",
|
"Sort by Name": "Sắp xếp theo tên",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "Quản lý dữ liệu",
|
"Data Management": "Quản lý dữ liệu",
|
||||||
"Unable to retrieve user statistics data": "Không thể lấy dữ liệu thống kê người dùng",
|
"Unable to retrieve user statistics data": "Không thể lấy dữ liệu thống kê người dùng",
|
||||||
"Export Data": "Xuất dữ liệu",
|
"Export Data": "Xuất dữ liệu",
|
||||||
|
"Field Separator": "Field Separator",
|
||||||
"CSV (Comma-separated values) File": "Tệp CSV (Giá trị phân cách bằng dấu phẩy)",
|
"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)",
|
"TSV (Tab-separated values) File": "Tệp TSV (Giá trị phân cách bằng tab)",
|
||||||
"Clear User Data": "Xóa dữ liệu người dùng",
|
"Clear User Data": "Xóa dữ liệu người dùng",
|
||||||
|
|||||||
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_导出数据",
|
"defaultExportFilename": "ezBookkeeping_导出数据",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_导出数据"
|
"exportFilename": "ezBookkeeping_{nickname}_导出数据",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_统计数据",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_统计数据"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "选择全部无效项目",
|
"Select All Invalid Items": "选择全部无效项目",
|
||||||
"Back": "返回",
|
"Back": "返回",
|
||||||
"Load More": "加载更多",
|
"Load More": "加载更多",
|
||||||
|
"Export Results": "导出结果",
|
||||||
"No data": "没有数据",
|
"No data": "没有数据",
|
||||||
|
"Data copied": "数据已复制",
|
||||||
|
"Table": "表格",
|
||||||
|
"Raw Data": "原始数据",
|
||||||
"Zoom in": "放大",
|
"Zoom in": "放大",
|
||||||
"Zoom out": "缩小",
|
"Zoom out": "缩小",
|
||||||
"Drag to Reorder": "拖拽改变顺序",
|
"Drag to Reorder": "拖拽改变顺序",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "最大金额",
|
"Maximum Amount": "最大金额",
|
||||||
"Display Order": "显示顺序",
|
"Display Order": "显示顺序",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
|
"Proportion (%)": "比例 (%)",
|
||||||
"Sort by Amount": "按金额排序",
|
"Sort by Amount": "按金额排序",
|
||||||
"Sort by Display Order": "按显示顺序排序",
|
"Sort by Display Order": "按显示顺序排序",
|
||||||
"Sort by Name": "按名称排序",
|
"Sort by Name": "按名称排序",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "数据管理",
|
"Data Management": "数据管理",
|
||||||
"Unable to retrieve user statistics data": "无法获取用户统计数据",
|
"Unable to retrieve user statistics data": "无法获取用户统计数据",
|
||||||
"Export Data": "导出数据",
|
"Export Data": "导出数据",
|
||||||
|
"Field Separator": "字段分隔符",
|
||||||
"CSV (Comma-separated values) File": "CSV (逗号分隔的值) 文件",
|
"CSV (Comma-separated values) File": "CSV (逗号分隔的值) 文件",
|
||||||
"TSV (Tab-separated values) File": "TSV (制表符分隔的值) 文件",
|
"TSV (Tab-separated values) File": "TSV (制表符分隔的值) 文件",
|
||||||
"Clear User Data": "清除用户数据",
|
"Clear User Data": "清除用户数据",
|
||||||
|
|||||||
@@ -118,7 +118,9 @@
|
|||||||
},
|
},
|
||||||
"dataExport": {
|
"dataExport": {
|
||||||
"defaultExportFilename": "ezBookkeeping_匯出資料",
|
"defaultExportFilename": "ezBookkeeping_匯出資料",
|
||||||
"exportFilename": "ezBookkeeping_{nickname}_匯出資料"
|
"exportFilename": "ezBookkeeping_{nickname}_匯出資料",
|
||||||
|
"defaultExportStatisticsFileName": "ezBookkeeping_統計資料",
|
||||||
|
"exportStatisticsFileName": "ezBookkeeping_{nickname}_統計資料"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"datetime": {
|
||||||
"AM": {
|
"AM": {
|
||||||
@@ -1429,7 +1431,11 @@
|
|||||||
"Select All Invalid Items": "選擇全部無效項目",
|
"Select All Invalid Items": "選擇全部無效項目",
|
||||||
"Back": "返回",
|
"Back": "返回",
|
||||||
"Load More": "載入更多",
|
"Load More": "載入更多",
|
||||||
|
"Export Results": "匯出結果",
|
||||||
"No data": "無資料",
|
"No data": "無資料",
|
||||||
|
"Data copied": "資料已複製",
|
||||||
|
"Table": "表格",
|
||||||
|
"Raw Data": "原始資料",
|
||||||
"Zoom in": "放大",
|
"Zoom in": "放大",
|
||||||
"Zoom out": "縮小",
|
"Zoom out": "縮小",
|
||||||
"Drag to Reorder": "拖曳以重新排序",
|
"Drag to Reorder": "拖曳以重新排序",
|
||||||
@@ -1814,6 +1820,7 @@
|
|||||||
"Maximum Amount": "最大金額",
|
"Maximum Amount": "最大金額",
|
||||||
"Display Order": "顯示順序",
|
"Display Order": "顯示順序",
|
||||||
"Name": "名稱",
|
"Name": "名稱",
|
||||||
|
"Proportion (%)": "比例 (%)",
|
||||||
"Sort by Amount": "依金額排序",
|
"Sort by Amount": "依金額排序",
|
||||||
"Sort by Display Order": "依顯示順序排序",
|
"Sort by Display Order": "依顯示順序排序",
|
||||||
"Sort by Name": "依名稱排序",
|
"Sort by Name": "依名稱排序",
|
||||||
@@ -1915,6 +1922,7 @@
|
|||||||
"Data Management": "資料管理",
|
"Data Management": "資料管理",
|
||||||
"Unable to retrieve user statistics data": "無法取得使用者統計資料",
|
"Unable to retrieve user statistics data": "無法取得使用者統計資料",
|
||||||
"Export Data": "匯出資料",
|
"Export Data": "匯出資料",
|
||||||
|
"Field Separator": "欄位分隔符",
|
||||||
"CSV (Comma-separated values) File": "CSV (逗號分隔的值) 檔案",
|
"CSV (Comma-separated values) File": "CSV (逗號分隔的值) 檔案",
|
||||||
"TSV (Tab-separated values) File": "TSV (定位點分隔的值) 檔案",
|
"TSV (Tab-separated values) File": "TSV (定位點分隔的值) 檔案",
|
||||||
"Clear User Data": "清除使用者資料",
|
"Clear User Data": "清除使用者資料",
|
||||||
|
|||||||
@@ -133,6 +133,14 @@ input[type=number] {
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-container {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-theme--dark .code-container {
|
||||||
|
background-color: #2f2f2f;
|
||||||
|
}
|
||||||
|
|
||||||
/** Common class for replacing the default style of vuetify **/
|
/** Common class for replacing the default style of vuetify **/
|
||||||
.v-input.v-input--readonly input,
|
.v-input.v-input--readonly input,
|
||||||
.v-input.v-input--readonly textarea,
|
.v-input.v-input--readonly textarea,
|
||||||
|
|||||||
@@ -128,6 +128,11 @@
|
|||||||
:title="tt('Filter Transaction Tags')"
|
:title="tt('Filter Transaction Tags')"
|
||||||
@click="showFilterTagDialog = true"></v-list-item>
|
@click="showFilterTagDialog = true"></v-list-item>
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2"/>
|
||||||
|
<v-list-item :prepend-icon="mdiExport"
|
||||||
|
:title="tt('Export Results')"
|
||||||
|
:disabled="!statisticsDataHasData"
|
||||||
|
@click="exportResults"></v-list-item>
|
||||||
|
<v-divider class="my-2"/>
|
||||||
<v-list-item to="/app/settings?tab=statisticsSetting"
|
<v-list-item to="/app/settings?tab=statisticsSetting"
|
||||||
:prepend-icon="mdiFilterCogOutline"
|
:prepend-icon="mdiFilterCogOutline"
|
||||||
:title="tt('Settings')"></v-list-item>
|
:title="tt('Settings')"></v-list-item>
|
||||||
@@ -270,6 +275,7 @@
|
|||||||
:enable-click-item="true"
|
:enable-click-item="true"
|
||||||
:default-currency="defaultCurrency"
|
:default-currency="defaultCurrency"
|
||||||
:show-total-amount-in-tooltip="showTotalAmountInTrendsChart"
|
:show-total-amount-in-tooltip="showTotalAmountInTrendsChart"
|
||||||
|
ref="trendsChart"
|
||||||
id-field="id"
|
id-field="id"
|
||||||
name-field="name"
|
name-field="name"
|
||||||
value-field="totalAmount"
|
value-field="totalAmount"
|
||||||
@@ -317,14 +323,18 @@
|
|||||||
@settings:change="setTagFilter" />
|
@settings:change="setTagFilter" />
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
|
<export-dialog ref="exportDialog" />
|
||||||
|
|
||||||
<snack-bar ref="snackbar" />
|
<snack-bar ref="snackbar" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||||
|
import TrendsChart from '@/components/desktop/TrendsChart.vue';
|
||||||
import AccountFilterSettingsCard from '@/views/desktop/common/cards/AccountFilterSettingsCard.vue';
|
import AccountFilterSettingsCard from '@/views/desktop/common/cards/AccountFilterSettingsCard.vue';
|
||||||
import CategoryFilterSettingsCard from '@/views/desktop/common/cards/CategoryFilterSettingsCard.vue';
|
import CategoryFilterSettingsCard from '@/views/desktop/common/cards/CategoryFilterSettingsCard.vue';
|
||||||
import TransactionTagFilterSettingsCard from '@/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue';
|
import TransactionTagFilterSettingsCard from '@/views/desktop/common/cards/TransactionTagFilterSettingsCard.vue';
|
||||||
|
import ExportDialog from '@/views/desktop/statistics/transaction/dialogs/ExportDialog.vue';
|
||||||
|
|
||||||
import { ref, computed, useTemplateRef, watch } from 'vue';
|
import { ref, computed, useTemplateRef, watch } from 'vue';
|
||||||
import { useRouter, onBeforeRouteUpdate } from 'vue-router';
|
import { useRouter, onBeforeRouteUpdate } from 'vue-router';
|
||||||
@@ -353,7 +363,10 @@ import {
|
|||||||
isString,
|
isString,
|
||||||
isNumber,
|
isNumber,
|
||||||
arrayItemToObjectField
|
arrayItemToObjectField
|
||||||
} from '@/lib/common.ts'
|
} from '@/lib/common.ts';
|
||||||
|
import {
|
||||||
|
formatAmount
|
||||||
|
} from '@/lib/numeral.ts';
|
||||||
import {
|
import {
|
||||||
getYearAndMonthFromUnixTime,
|
getYearAndMonthFromUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
@@ -373,10 +386,13 @@ import {
|
|||||||
mdiMenu,
|
mdiMenu,
|
||||||
mdiFilterOutline,
|
mdiFilterOutline,
|
||||||
mdiFilterCogOutline,
|
mdiFilterCogOutline,
|
||||||
|
mdiExport,
|
||||||
mdiDotsVertical
|
mdiDotsVertical
|
||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
|
|
||||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||||
|
type TrendsChartType = InstanceType<typeof TrendsChart>;
|
||||||
|
type ExportDialogType = InstanceType<typeof ExportDialog>;
|
||||||
|
|
||||||
interface TransactionStatisticsProps {
|
interface TransactionStatisticsProps {
|
||||||
initAnalysisType?: string,
|
initAnalysisType?: string,
|
||||||
@@ -433,6 +449,8 @@ const transactionCategoriesStore = useTransactionCategoriesStore();
|
|||||||
const statisticsStore = useStatisticsStore();
|
const statisticsStore = useStatisticsStore();
|
||||||
|
|
||||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||||
|
const trendsChart = useTemplateRef<TrendsChartType>('trendsChart');
|
||||||
|
const exportDialog = useTemplateRef<ExportDialogType>('exportDialog');
|
||||||
|
|
||||||
const activeTab = ref<string>('statisticsPage');
|
const activeTab = ref<string>('statisticsPage');
|
||||||
const initing = ref<boolean>(true);
|
const initing = ref<boolean>(true);
|
||||||
@@ -446,6 +464,16 @@ const showFilterTagDialog = ref<boolean>(false);
|
|||||||
|
|
||||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||||
|
|
||||||
|
const statisticsDataHasData = computed<boolean>(() => {
|
||||||
|
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
||||||
|
return !!categoricalAnalysisData.value && !!categoricalAnalysisData.value.items && categoricalAnalysisData.value.items.length > 0;
|
||||||
|
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
|
||||||
|
return !!trendsAnalysisData.value && !!trendsAnalysisData.value.items && trendsAnalysisData.value.items.length > 0 && !!trendsChart.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
const allChartTypes = computed<TypeAndDisplayName[]>(() => {
|
const allChartTypes = computed<TypeAndDisplayName[]>(() => {
|
||||||
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
||||||
return getAllCategoricalChartTypes();
|
return getAllCategoricalChartTypes();
|
||||||
@@ -876,6 +904,31 @@ function setTagFilter(changed: boolean): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportResults(): void {
|
||||||
|
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis && categoricalAnalysisData.value && categoricalAnalysisData.value.items) {
|
||||||
|
exportDialog.value?.open({
|
||||||
|
headers: [
|
||||||
|
tt('Name'),
|
||||||
|
tt('Amount') + ` (${defaultCurrency.value})`,
|
||||||
|
tt('Proportion (%)')
|
||||||
|
],
|
||||||
|
data: categoricalAnalysisData.value.items
|
||||||
|
.filter(item => !item.hidden)
|
||||||
|
.map(item => [
|
||||||
|
item.name,
|
||||||
|
formatAmount(item.totalAmount, {}),
|
||||||
|
item.percent.toFixed(4)
|
||||||
|
])
|
||||||
|
});
|
||||||
|
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis && trendsAnalysisData.value && trendsAnalysisData.value.items && trendsChart.value) {
|
||||||
|
const exportData = trendsChart.value.exportData();
|
||||||
|
exportDialog.value?.open({
|
||||||
|
headers: exportData.headers || [],
|
||||||
|
data: exportData.data || []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onClickPieChartItem(item: Record<string, unknown>): void {
|
function onClickPieChartItem(item: Record<string, unknown>): void {
|
||||||
router.push(getTransactionItemLinkUrl(item['id'] as string));
|
router.push(getTransactionItemLinkUrl(item['id'] as string));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
<template>
|
||||||
|
<v-dialog width="1000" v-model="showState">
|
||||||
|
<v-card class="pa-2 pa-sm-4 pa-md-4">
|
||||||
|
<template #title>
|
||||||
|
<div class="d-flex align-center justify-center">
|
||||||
|
<div class="d-flex w-100 align-center justify-center">
|
||||||
|
<h4 class="text-h4">{{ tt('Export Results') }}</h4>
|
||||||
|
</div>
|
||||||
|
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true">
|
||||||
|
<v-icon :icon="mdiDotsVertical" />
|
||||||
|
<v-menu activator="parent">
|
||||||
|
<v-list>
|
||||||
|
<v-list-subheader :title="tt('Field Separator')"/>
|
||||||
|
<v-list-item :prepend-icon="mdiComma"
|
||||||
|
:append-icon="separator === ',' ? mdiCheck : undefined"
|
||||||
|
:title="tt('Comma')"
|
||||||
|
@click="separator = ','"></v-list-item>
|
||||||
|
<v-list-item :prepend-icon="mdiKeyboardTab"
|
||||||
|
:append-icon="separator === '\t' ? mdiCheck : undefined"
|
||||||
|
:title="tt('Tab')"
|
||||||
|
@click="separator = '\t'"></v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-card-text class="py-0 w-100 d-flex justify-center">
|
||||||
|
<v-switch class="export-data-display-switch" color="secondary"
|
||||||
|
:label="tt('Raw Data')"
|
||||||
|
v-model="showRawData"
|
||||||
|
@click="showRawData = !showRawData">
|
||||||
|
<template #prepend>
|
||||||
|
<span>{{ tt('Table') }}</span>
|
||||||
|
</template>
|
||||||
|
</v-switch>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-text class="my-md-4 w-100 d-flex justify-center">
|
||||||
|
<v-data-table
|
||||||
|
fixed-header
|
||||||
|
fixed-footer
|
||||||
|
multi-sort
|
||||||
|
density="compact"
|
||||||
|
height="365"
|
||||||
|
:headers="dataTableHeaders"
|
||||||
|
:items="dataTableItems"
|
||||||
|
:hover="true"
|
||||||
|
:hide-default-footer="true"
|
||||||
|
:items-per-page="dataTableItems.length"
|
||||||
|
:no-data-text="tt('No data')"
|
||||||
|
v-if="!showRawData"
|
||||||
|
></v-data-table>
|
||||||
|
<div class="w-100 pl-2 code-container" v-if="showRawData">
|
||||||
|
<textarea class="w-100" style="outline: none; height: 360px" :readonly="true" :value="exportedData"></textarea>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-text class="overflow-y-visible">
|
||||||
|
<div ref="buttonContainer" class="w-100 d-flex justify-center gap-4">
|
||||||
|
<v-btn-group variant="tonal" density="comfortable">
|
||||||
|
<v-btn color="primary" :disabled="!exportedData" @click="copy">{{ tt('Copy') }}</v-btn>
|
||||||
|
<v-btn density="compact" color="primary" :disabled="!exportedData" :icon="true">
|
||||||
|
<v-icon :icon="mdiMenuDown" size="24" />
|
||||||
|
<v-menu activator="parent">
|
||||||
|
<v-list>
|
||||||
|
<v-list-item :title="tt('Save')" @click="save()"></v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-btn>
|
||||||
|
</v-btn-group>
|
||||||
|
<v-btn color="secondary" variant="tonal" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<snack-bar ref="snackbar" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||||
|
|
||||||
|
import { ref, computed, useTemplateRef } from 'vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
|
||||||
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
|
|
||||||
|
import { copyTextToClipboard, startDownloadFile } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
|
import {
|
||||||
|
mdiDotsVertical,
|
||||||
|
mdiCheck,
|
||||||
|
mdiComma,
|
||||||
|
mdiKeyboardTab,
|
||||||
|
mdiMenuDown
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
|
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||||
|
|
||||||
|
const { tt } = useI18n();
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const buttonContainer = useTemplateRef<HTMLElement>('buttonContainer');
|
||||||
|
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||||
|
|
||||||
|
const showState = ref<boolean>(false);
|
||||||
|
const headers = ref<string[]>([]);
|
||||||
|
const data = ref<string[][]>([]);
|
||||||
|
const separator = ref<string>(',');
|
||||||
|
const showRawData = ref<boolean>(false);
|
||||||
|
|
||||||
|
const dataTableHeaders = computed<object[]>(() => {
|
||||||
|
return headers.value.map((header, index) => ({
|
||||||
|
key: index.toString(),
|
||||||
|
value: `column${index}`,
|
||||||
|
title: header,
|
||||||
|
sortable: index > 0,
|
||||||
|
nowrap: true
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataTableItems = computed<object[]>(() => {
|
||||||
|
return data.value.map(row => {
|
||||||
|
const item: Record<string, string> = {};
|
||||||
|
|
||||||
|
row.forEach((value, index) => {
|
||||||
|
item[`column${index}`] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const exportedData = computed<string>(() => {
|
||||||
|
let ret = '';
|
||||||
|
|
||||||
|
if (headers.value.length > 0) {
|
||||||
|
ret += headers.value.join(separator.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const row of data.value) {
|
||||||
|
ret += '\n';
|
||||||
|
ret += row.join(separator.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
function getExportFileName(fileExtension: string): string {
|
||||||
|
const nickname = userStore.currentUserNickname;
|
||||||
|
|
||||||
|
if (nickname) {
|
||||||
|
return tt('dataExport.exportStatisticsFileName', {
|
||||||
|
nickname: nickname
|
||||||
|
}) + '.' + fileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tt('dataExport.defaultExportStatisticsFileName') + '.' + fileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
function open(options: { headers: string[], data: string[][] }): void {
|
||||||
|
headers.value = options.headers || [];
|
||||||
|
data.value = options.data || [];
|
||||||
|
separator.value = ',';
|
||||||
|
showRawData.value = false;
|
||||||
|
showState.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy(): void {
|
||||||
|
copyTextToClipboard(exportedData.value, buttonContainer.value);
|
||||||
|
snackbar.value?.showMessage('Data copied');
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(): void {
|
||||||
|
let fileExtension = 'csv';
|
||||||
|
let contentType = 'text/csv';
|
||||||
|
|
||||||
|
if (separator.value === '\t') {
|
||||||
|
fileExtension = 'tsv';
|
||||||
|
contentType = 'text/tab-separated-values';
|
||||||
|
}
|
||||||
|
|
||||||
|
startDownloadFile(getExportFileName(fileExtension), new Blob([exportedData.value], { type: contentType }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel(): void {
|
||||||
|
showState.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.export-data-display-switch {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-data-display-switch.v-input--horizontal .v-input__prepend {
|
||||||
|
margin-right: 10px; /* same as the padding-left of `.v-switch .v-label` */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user