chart data source supports expense and income by primary category

This commit is contained in:
MaysWind
2021-01-26 22:59:13 +08:00
parent fb155aae47
commit dd70247e08
3 changed files with 138 additions and 56 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ const allChartDataTypes = {
IncomeBySecondaryCategory: 5 IncomeBySecondaryCategory: 5
}; };
const defaultChartDataType = allChartDataTypes.ExpenseBySecondaryCategory; const defaultChartDataType = allChartDataTypes.ExpenseByPrimaryCategory;
export default { export default {
allChartTypes: allChartTypes, allChartTypes: allChartTypes,
+11 -1
View File
@@ -771,8 +771,18 @@ const stores = {
item.category = state.allTransactionCategoriesMap[item.categoryId]; item.category = state.allTransactionCategoriesMap[item.categoryId];
} }
if (item.category && item.category.parentId !== '0') {
item.primaryCategory = state.allTransactionCategoriesMap[item.category.parentId];
} else {
item.primaryCategory = item.category;
}
if (item.account && item.account.currency !== defaultCurrency) { if (item.account && item.account.currency !== defaultCurrency) {
item.amountInDefaultCurrency = getExchangedAmount(state)(item.amount, item.account.currency, defaultCurrency); const amount = getExchangedAmount(state)(item.amount, item.account.currency, defaultCurrency);
if (utils.isNumber(amount)) {
item.amountInDefaultCurrency = Math.floor(amount);
}
} else if (item.account && item.account.currency === defaultCurrency) { } else if (item.account && item.account.currency === defaultCurrency) {
item.amountInDefaultCurrency = item.amount; item.amountInDefaultCurrency = item.amount;
} else { } else {
+126 -54
View File
@@ -2,12 +2,25 @@
<f7-page> <f7-page>
<f7-navbar> <f7-navbar>
<f7-nav-left :back-link="$t('Back')"></f7-nav-left> <f7-nav-left :back-link="$t('Back')"></f7-nav-left>
<f7-nav-title :title="$t('Statistics')"></f7-nav-title> <f7-nav-title>
<f7-nav-right> <f7-link popover-open=".chart-data-type-popover-menu">
<f7-link icon-f7="ellipsis" @click="showMoreActionSheet = true"></f7-link> <span>{{ query.chartDataType | chartDataTypeName(allChartDataTypes) | localized }}</span>
</f7-nav-right> <f7-icon size="14px" :f7="showChartDataTypePopover ? 'arrowtriangle_up_fill' : 'arrowtriangle_down_fill'"></f7-icon>
</f7-link>
</f7-nav-title>
</f7-navbar> </f7-navbar>
<f7-popover class="chart-data-type-popover-menu" :opened="showChartDataTypePopover"
@popover:open="showChartDataTypePopover = true" @popover:close="showChartDataTypePopover = false">
<f7-list>
<f7-list-item
v-for="dataType in allChartDataTypes" :key="dataType.type"
:title="$t(dataType.name)" @click="setChartDataType(dataType.type)">
<f7-icon slot="after" class="list-item-checked" f7="checkmark_alt" v-if="query.chartDataType === dataType.type"></f7-icon>
</f7-list-item>
</f7-list>
</f7-popover>
<f7-card> <f7-card>
<f7-card-content class="no-safe-areas chart-container" :padding="false"> <f7-card-content class="no-safe-areas chart-container" :padding="false">
<v-chart :options="chartData" v-if="chartData" /> <v-chart :options="chartData" v-if="chartData" />
@@ -31,22 +44,6 @@
<span :class="{ 'tabbar-item-changed': query.chartType === $constants.statistics.allChartTypes.Bar }">{{ $t('Bar Chart') }}</span> <span :class="{ 'tabbar-item-changed': query.chartType === $constants.statistics.allChartTypes.Bar }">{{ $t('Bar Chart') }}</span>
</f7-link> </f7-link>
</f7-toolbar> </f7-toolbar>
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group>
<f7-actions-label>{{ $t('Expense Chart') }}</f7-actions-label>
<f7-actions-button @click="setChartDataType($constants.statistics.allChartDataTypes.ExpenseByAccount)">{{ $t('Expense By Account') }}</f7-actions-button>
<f7-actions-button @click="setChartDataType($constants.statistics.allChartDataTypes.ExpenseBySecondaryCategory)">{{ $t('Expense By Secondary Category') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-label>{{ $t('Income Chart') }}</f7-actions-label>
<f7-actions-button @click="setChartDataType($constants.statistics.allChartDataTypes.IncomeByAccount)">{{ $t('Income By Account') }}</f7-actions-button>
<f7-actions-button @click="setChartDataType($constants.statistics.allChartDataTypes.IncomeBySecondaryCategory)">{{ $t('Income By Secondary Category') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
</f7-actions-group>
</f7-actions>
</f7-page> </f7-page>
</template> </template>
@@ -55,7 +52,7 @@ export default {
data() { data() {
return { return {
loading: true, loading: true,
showMoreActionSheet: false showChartDataTypePopover: false
}; };
}, },
computed: { computed: {
@@ -73,22 +70,44 @@ export default {
query() { query() {
return this.$store.state.transactionStatisticsFilter; return this.$store.state.transactionStatisticsFilter;
}, },
chartData() { allChartDataTypes() {
return [
{
type: this.$constants.statistics.allChartDataTypes.ExpenseByAccount,
name: 'Expense By Account'
},
{
type: this.$constants.statistics.allChartDataTypes.ExpenseByPrimaryCategory,
name: 'Expense By Primary Category'
},
{
type: this.$constants.statistics.allChartDataTypes.ExpenseBySecondaryCategory,
name: 'Expense By Secondary Category'
},
{
type: this.$constants.statistics.allChartDataTypes.IncomeByAccount,
name: 'Income By Account'
},
{
type: this.$constants.statistics.allChartDataTypes.IncomeByPrimaryCategory,
name: 'Income By Primary Category'
},
{
type: this.$constants.statistics.allChartDataTypes.IncomeBySecondaryCategory,
name: 'Income By Secondary Category'
},
];
},
statisticsData() {
const self = this; const self = this;
if (!self.$store.state.transactionStatistics ||
!self.$store.state.transactionStatistics.items ||
!self.$store.state.transactionStatistics.items.length) {
return self.skeletonChart();
}
const combinedData = {}; const combinedData = {};
const allData = [];
let allAmount = 0;
for (let i = 0; i < self.$store.state.transactionStatistics.items.length; i++) { for (let i = 0; i < self.$store.state.transactionStatistics.items.length; i++) {
const item = self.$store.state.transactionStatistics.items[i]; const item = self.$store.state.transactionStatistics.items[i];
if (!item.account || !item.category) { if (!item.account || !item.primaryCategory || !item.category) {
continue; continue;
} }
@@ -111,59 +130,102 @@ export default {
if (self.query.chartDataType === self.$constants.statistics.allChartDataTypes.ExpenseByAccount || if (self.query.chartDataType === self.$constants.statistics.allChartDataTypes.ExpenseByAccount ||
self.query.chartDataType === self.$constants.statistics.allChartDataTypes.IncomeByAccount) { self.query.chartDataType === self.$constants.statistics.allChartDataTypes.IncomeByAccount) {
if (self.$utilities.isNumber(item.amountInDefaultCurrency)) { if (self.$utilities.isNumber(item.amountInDefaultCurrency)) {
let data = combinedData[item.account.name]; let data = combinedData[item.account.id];
if (data) { if (data) {
data.totalAmount += item.amountInDefaultCurrency; data.totalAmount += item.amountInDefaultCurrency;
} else { } else {
data = { data = {
totalAmount: item.amountInDefaultCurrency, name: item.account.name,
color: item.account.color || self.$constants.colors.defaultAccountColor icon: item.account.icon || self.$constants.icons.defaultAccountIcon.icon,
color: item.account.color || self.$constants.colors.defaultAccountColor,
totalAmount: item.amountInDefaultCurrency
} }
} }
combinedData[item.account.name] = data; allAmount += item.amountInDefaultCurrency;
combinedData[item.account.id] = data;
}
} else if (self.query.chartDataType === self.$constants.statistics.allChartDataTypes.ExpenseByPrimaryCategory ||
self.query.chartDataType === self.$constants.statistics.allChartDataTypes.IncomeByPrimaryCategory) {
if (self.$utilities.isNumber(item.amountInDefaultCurrency)) {
let data = combinedData[item.primaryCategory.id];
if (data) {
data.totalAmount += item.amountInDefaultCurrency;
} else {
data = {
name: item.primaryCategory.name,
icon: item.account.icon || self.$constants.icons.defaultCategoryIcon.icon,
color: item.primaryCategory.color || self.$constants.colors.defaultCategoryColor,
totalAmount: item.amountInDefaultCurrency
}
}
allAmount += item.amountInDefaultCurrency;
combinedData[item.primaryCategory.id] = data;
} }
} else if (self.query.chartDataType === self.$constants.statistics.allChartDataTypes.ExpenseBySecondaryCategory || } else if (self.query.chartDataType === self.$constants.statistics.allChartDataTypes.ExpenseBySecondaryCategory ||
self.query.chartDataType === self.$constants.statistics.allChartDataTypes.IncomeBySecondaryCategory) { self.query.chartDataType === self.$constants.statistics.allChartDataTypes.IncomeBySecondaryCategory) {
if (self.$utilities.isNumber(item.amountInDefaultCurrency)) { if (self.$utilities.isNumber(item.amountInDefaultCurrency)) {
let data = combinedData[item.category.name]; let data = combinedData[item.category.id];
if (data) { if (data) {
data.totalAmount += item.amountInDefaultCurrency; data.totalAmount += item.amountInDefaultCurrency;
} else { } else {
data = { data = {
totalAmount: item.amountInDefaultCurrency, name: item.category.name,
color: item.category.color || self.$constants.colors.defaultCategoryColor icon: item.account.icon || self.$constants.icons.defaultCategoryIcon.icon,
color: item.category.color || self.$constants.colors.defaultCategoryColor,
totalAmount: item.amountInDefaultCurrency
} }
} }
combinedData[item.category.name] = data; allAmount += item.amountInDefaultCurrency;
combinedData[item.category.id] = data;
} }
} }
} }
for (let legendName in combinedData) { const allStatisticsData = [];
if (!Object.prototype.hasOwnProperty.call(combinedData, legendName)) {
for (let id in combinedData) {
if (!Object.prototype.hasOwnProperty.call(combinedData, id)) {
continue; continue;
} }
const totalAmount = Math.floor(combinedData[legendName].totalAmount) / 100; const data = combinedData[id];
data.percent = data.totalAmount * 100 / allAmount;
const data = { allStatisticsData.push(data);
name: legendName,
value: totalAmount,
itemStyle: {
color: `#${combinedData[legendName].color}`
}
};
allData.push(data);
} }
if (self.query.chartType === self.$constants.statistics.allChartTypes.Bar) { allStatisticsData.sort(function (data1, data2) {
allData.sort(function (data1, data2) { return data1.totalAmount - data2.totalAmount;
return data1.value - data2.value; });
return allStatisticsData;
},
chartData() {
const self = this;
if (!self.$store.state.transactionStatistics ||
!self.$store.state.transactionStatistics.items ||
!self.$store.state.transactionStatistics.items.length) {
return self.skeletonChart();
}
const allData = [];
for (let i = 0; i < this.statisticsData.length; i++) {
const data = this.statisticsData[i];
allData.push({
name: data.name,
value: data.totalAmount / 100,
itemStyle: {
color: `#${data.color}`
}
}); });
} }
@@ -296,6 +358,7 @@ export default {
this.$store.dispatch('updateTransactionStatisticsFilter', { this.$store.dispatch('updateTransactionStatisticsFilter', {
chartDataType: chartDataType chartDataType: chartDataType
}); });
this.showChartDataTypePopover = false;
}, },
skeletonChart() { skeletonChart() {
const skeletonChartData = { const skeletonChartData = {
@@ -357,6 +420,15 @@ export default {
} }
}, },
filters: { filters: {
chartDataTypeName(dataType, allChartDataTypes) {
for (let i = 0; i < allChartDataTypes.length; i++) {
if (allChartDataTypes[i].type === dataType) {
return allChartDataTypes[i].name;
}
}
return 'Statistics';
},
dateRange() { dateRange() {
return 'Date'; return 'Date';
} }