chet novoe
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
<div :class="!updateLoading ? '' : 'h-fit bg-white opacity-50 z-0 '" class=" flex flex-col gap-3">
|
||||
<div class="flex flex-col ">
|
||||
<!-- {{ budget }}-->
|
||||
<h2 class="text-4xl font-bold">Budget for {{ budget.name }} </h2>
|
||||
<h2 class="text-4xl font-bold">Бюджет {{ budget.name }} </h2>
|
||||
<!-- <div class="flex flex-row gap-2 text-xl">{{ formatDate(budget.dateFrom) }} - -->
|
||||
<!-- {{ formatDate(budget.dateTo) }}-->
|
||||
<!-- </div> -->
|
||||
@@ -31,20 +31,24 @@
|
||||
class="bg-white p-4 shadow-lg rounded-lg flex flex-col gap-4 items-start ">
|
||||
<h3 class="text-xl font-bold">Аналитика</h3>
|
||||
|
||||
<SelectButton v-model="selectedChart" :options="modes" optionLabel="label" optionIcon="icon"> <template #option="slotProps">
|
||||
<i :class="slotProps.option.icon"></i>
|
||||
</template></SelectButton>
|
||||
<Chart v-if="selectedChart.value=='bar'" type="bar" :data="incomeExpenseChartData" :options="incomeExpenseChartOptions" class="!w-full"
|
||||
<SelectButton v-model="selectedChart" :options="modes" optionLabel="label" optionIcon="icon">
|
||||
<template #option="slotProps">
|
||||
<i :class="slotProps.option.icon"></i>
|
||||
</template>
|
||||
</SelectButton>
|
||||
<Chart v-if="selectedChart.value=='bar'" type="bar" :data="incomeExpenseChartData"
|
||||
:options="incomeExpenseChartOptions" class="!w-full"
|
||||
style="width: 100%"/>
|
||||
|
||||
<Chart v-if="selectedChart.value=='pie'" type="pie" :data="pieChartData" :options="pieChartOptions" class="chart "/>
|
||||
<Chart v-if="selectedChart.value=='pie'" type="pie" :data="pieChartData" :options="pieChartOptions"
|
||||
class="chart "/>
|
||||
|
||||
|
||||
<div class="flex gap-5 items-center justify-items-center ">
|
||||
<div class="w-full">
|
||||
<button class="grid grid-cols-2 gap-5 items-center w-full" @click="detailedShowed = !detailedShowed">
|
||||
<div class="flex flex-col items-center font-bold ">
|
||||
<h4 class="text-xl font-bold text-green-500">Сумма поступлений</h4>
|
||||
<h4 class="text-lg font-bold">Поступления</h4>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
+{{ formatAmount(totalIncomes) }}
|
||||
₽
|
||||
@@ -52,7 +56,7 @@
|
||||
<!-- <p>Total Incomes</p>-->
|
||||
</div>
|
||||
<div class="flex flex-col items-center ">
|
||||
<h4 class="text-xl font-bold text-red-500">Сумма трат</h4>
|
||||
<h4 class="text-lg font-bold ">Расходы</h4>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
-{{ formatAmount(totalExpenses) }}
|
||||
₽
|
||||
@@ -61,27 +65,27 @@
|
||||
</button>
|
||||
<div class="grid grid-cols-2 !gap-1 mt-4" :class="detailedShowed ? 'block' : 'hidden'">
|
||||
<div class="flex flex-col items-center font-bold ">
|
||||
<p class="font-bold ">Поступление в первый период</p>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
<p class="font-light ">в первый период</p>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
+{{ formatAmount(incomesByPeriod[0]) }} ₽
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="font-bold ">Траты в первый период</p>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
<p class="font-light ">в первый период</p>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
-{{ formatAmount(expensesByPeriod[0]) }} ₽
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="font-bold ">Поступления во второй период</p>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
<p class="font-light ">во второй период</p>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
+{{ formatAmount(incomesByPeriod[1]) }} ₽
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="font-bold ">Траты во второй период</p>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
<p class="font-light ">во второй период</p>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
-{{ formatAmount(expensesByPeriod[1]) }} ₽
|
||||
</div>
|
||||
</div>
|
||||
@@ -95,30 +99,30 @@
|
||||
<button class="grid grid-cols-3 justify-between gap-5 items-center w-full"
|
||||
@click="detailedShowed = !detailedShowed">
|
||||
<div class="flex flex-col items-center">
|
||||
<h4 class="text-lg">Долги</h4>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
<h4 class="text-lg">💳 Долги</h4>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
{{ loansRatio.toFixed(0) }} %
|
||||
</div>
|
||||
<!-- <p>Total Incomes</p>-->
|
||||
</div>
|
||||
<div class="flex flex-col items-center ">
|
||||
<h4 class="text-lg ">Сбережения</h4>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
<span class="text-base">💰Сбережения</span>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
{{ savingRatio.toFixed(0) }} %
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center ">
|
||||
<h4 class="text-lg ">Ежедневные</h4>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
<h4 class="text-sm">🍎 Ежедневные</h4>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
{{ dailyRatio.toFixed(0) }} %
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="grid grid-cols-2 !gap-1 mt-4" :class="detailedShowed ? 'block' : 'hidden'">
|
||||
<div v-for="transaction in transactionCategoriesSums" class="flex flex-col items-center font-bold ">
|
||||
<p class="font-bold ">{{ transaction.category.name }}</p>
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
{{ formatAmount(transaction.sum) }} ₽
|
||||
<div v-for="categorySum in transactionCategoriesSums" class="flex flex-col items-center font-bold ">
|
||||
<p class="font-light ">{{ categorySum.category.icon }} {{ categorySum.category.name }}</p>
|
||||
<div class="font-light bg-gray-100 p-1 rounded-lg box-shadow-inner text-center w-full ">
|
||||
{{ formatAmount(categorySum.sum) }} ₽
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -130,13 +134,14 @@
|
||||
</div>
|
||||
<div class=" h-full overflow-y-auto gap-4 flex-col row-span-6 hidden lg:flex">
|
||||
<div class="flex flex-row ">
|
||||
<h3 class="text-2xl font-bold mb-4 ">Transactions List</h3>
|
||||
<h3 class="text-2xl font-bold">Транзакции</h3>
|
||||
</div>
|
||||
<div class=" flex gap-2">
|
||||
<button v-for="categorySum in transactionCategoriesSums" :key="categorySum.category.id"
|
||||
class="rounded-full border p-1 bg-white border-gray-300 mb-2 px-2">
|
||||
<strong>{{ categorySum.category.name }}</strong>:
|
||||
{{ categorySum.sum }} ₽
|
||||
<div class=" flex gap-2 overflow-x-auto ">
|
||||
|
||||
<button v-for="categorySum in transactionCategoriesSums"
|
||||
class="rounded-xl border p-1 bg-white border-gray-300 mb-2 min-w-fit px-2">
|
||||
<p> <span class="text-sm font-bold">{{ categorySum.category.name }}</span>: {{ categorySum.sum }} ₽</p>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 max-h-tlist overflow-y-auto pe-2">
|
||||
@@ -154,8 +159,8 @@
|
||||
<!-- Планируемые доходы -->
|
||||
<div>
|
||||
<div class="flex flex-row gap-4 items-center">
|
||||
<h3 class="text-xl font-bold text-green-500 mb-4 ">Planned Incomes</h3>
|
||||
<Button icon="pi pi-plus" rounded outlined size="small"/>
|
||||
<h3 class="text-xl font-bold text-green-500 mb-4 ">Плановые поступления</h3>
|
||||
<!-- <Button icon="pi pi-plus" rounded outlined size="small"/>-->
|
||||
</div>
|
||||
<div class="grid grid-cols-2 mb-2">
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
@@ -180,7 +185,7 @@
|
||||
<div class="card p-4 shadow-lg rounded-lg col-span-1 h-fit">
|
||||
<!-- Планируемые расходы -->
|
||||
<div class>
|
||||
<h3 class="text-xl font-bold text-red-500 mb-4">Planned Expenses</h3>
|
||||
<h3 class="text-xl font-bold text-red-500 mb-4">Плановые расходы</h3>
|
||||
<div class="grid grid-cols-2 mb-2">
|
||||
<div class="font-bold bg-gray-100 p-1 rounded-lg box-shadow-inner w-full text-center">
|
||||
{{ formatAmount(totalPlannedExpenses) }}
|
||||
@@ -202,25 +207,25 @@
|
||||
</div>
|
||||
|
||||
<div class="row-span-1 h-fit">
|
||||
<h3 class="text-2xl font-bold mb-4">Категории</h3>
|
||||
<h3 class="text-2xl font-bold ">Категории</h3>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
|
||||
<UnplannedCategoryView v-for="category in categories" :key="category.id"
|
||||
:category="category" :budget-id="budget.id"
|
||||
@category-updated="updateBudgetCategory"
|
||||
class="p-4 shadow-lg rounded-lg bg-white flex justify-between items-center"/>
|
||||
<!-- {{categories.filter(cat => cat.category.id==35)}}-->
|
||||
<BudgetCategoryView v-for="category in categories" :key="category.id"
|
||||
:category="category" :budget-id="budget.id"
|
||||
@category-updated="updateBudgetCategory"
|
||||
class="p-4 shadow-lg rounded-lg bg-white flex justify-between items-center"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class=" h-full overflow-y-auto gap-4 flex-col row-span-6 lg:hidden ">
|
||||
<div class="flex flex-row ">
|
||||
<h3 class="text-2xl font-bold mb-4 ">Transactions List</h3>
|
||||
<h3 class="text-2xl font-bold">Транзакций</h3>
|
||||
</div>
|
||||
<div class=" flex gap-2">
|
||||
<button v-for="categorySum in transactionCategoriesSums" :key="categorySum.category.id"
|
||||
<button v-for="categorySum in transactionCategoriesSums"
|
||||
class="rounded-full border p-1 bg-white border-gray-300 mb-2 px-2">
|
||||
<strong>{{ categorySum.category.name }}</strong>:
|
||||
{{ categorySum.sum }} ₽
|
||||
<p class="text-sm">{{ categorySum.category.name }}</p>:
|
||||
{{ categorySum }} ₽
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 max-h-tlist overflow-y-auto pe-2">
|
||||
@@ -240,11 +245,11 @@
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref} from 'vue';
|
||||
import {computed, onMounted, ref} from 'vue';
|
||||
import Chart from 'primevue/chart';
|
||||
import BudgetTransactionView from "@/components/budgets/BudgetTransactionView.vue";
|
||||
import {
|
||||
getBudgetCategories, getBudgetCategoriesSums,
|
||||
getBudgetCategories,
|
||||
getBudgetInfo,
|
||||
getBudgetTransactions,
|
||||
updateBudgetCategoryRequest
|
||||
@@ -254,7 +259,7 @@ import {useRoute} from "vue-router";
|
||||
import {formatAmount} from "@/utils/utils";
|
||||
import ProgressBar from "primevue/progressbar";
|
||||
import ProgressSpinner from "primevue/progressspinner";
|
||||
import UnplannedCategoryView from "@/components/budgets/BudgetCategoryView.vue";
|
||||
import BudgetCategoryView from "@/components/budgets/BudgetCategoryView.vue";
|
||||
import {Transaction} from "@/models/Transaction";
|
||||
import Toast from "primevue/toast";
|
||||
import Button from "primevue/button";
|
||||
@@ -271,7 +276,7 @@ const loading = ref(true);
|
||||
const updateLoading = ref(false);
|
||||
const route = useRoute()
|
||||
const detailedShowed = ref(false);
|
||||
const selectedChart = ref({ "label": "bar", "icon": "pi pi-chart-bar", "value": "bar" });
|
||||
const selectedChart = ref({"label": "bar", "icon": "pi pi-chart-bar", "value": "bar"});
|
||||
const modes = [
|
||||
{label: 'bar', icon: 'pi pi-chart-bar', value: 'bar'},
|
||||
{label: 'pie', icon: 'pi pi-chart-pie', value: 'pie'}
|
||||
@@ -381,29 +386,53 @@ const transactions = ref<Transaction[]>([])
|
||||
const fetchBudgetTransactions = async () => {
|
||||
|
||||
|
||||
transactions.value = await getBudgetTransactions(route.params.id)
|
||||
transactions.value = await getBudgetTransactions(route.params.id, 'INSTANT')
|
||||
updateLoading.value = false
|
||||
}
|
||||
|
||||
const updateTransactions = async () => {
|
||||
|
||||
await Promise.all([fetchPlannedIncomes(), fetchPlannedExpenses()])
|
||||
await Promise.all([fetchPlannedIncomes(), fetchPlannedExpenses(), fetchBudgetCategories(),])
|
||||
}
|
||||
|
||||
const categories = ref<BudgetCategory[]>([])
|
||||
const fetchBudgetCategories = async () => {
|
||||
|
||||
|
||||
categories.value = await getBudgetCategories(route.params.id)
|
||||
console.log(categories.value)
|
||||
categories.value = [...categories.value];
|
||||
updateLoading.value = false
|
||||
}
|
||||
const transactionCategoriesSums = ref()
|
||||
const fetchBudgetTransactionCategoriesSums = async () => {
|
||||
|
||||
const transactionCategoriesSums = computed(() => {
|
||||
// Используем reduce для создания массива сумм по категориям
|
||||
const categorySums = transactions.value.reduce((acc, transaction) => {
|
||||
console.log(transaction.category.name)
|
||||
const category = transaction.category;
|
||||
|
||||
// Проверяем, существует ли категория в аккумуляторе
|
||||
const existingCategory = acc.find(item => item.category.id === category.id);
|
||||
|
||||
if (existingCategory) {
|
||||
// Если категория существует, добавляем сумму к текущей
|
||||
existingCategory.sum += transaction.amount;
|
||||
|
||||
} else {
|
||||
// Если категории еще нет в аккумуляторе, добавляем ее
|
||||
acc.push({ category: category, sum: transaction.amount });
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
console.log(categorySums)
|
||||
return categorySums;
|
||||
});
|
||||
|
||||
|
||||
transactionCategoriesSums.value = await getBudgetCategoriesSums(route.params.id)
|
||||
updateLoading.value = false
|
||||
}
|
||||
// const fetchBudgetTransactionCategoriesSums = async () => {
|
||||
//
|
||||
// transactionCategoriesSums.value = await getBudgetCategoriesSums(route.params.id)
|
||||
// updateLoading.value = false
|
||||
// }
|
||||
|
||||
|
||||
const budgetInfo = ref<BudgetInfo>();
|
||||
@@ -411,7 +440,7 @@ const fetchBudgetInfo = async () => {
|
||||
|
||||
|
||||
budget.value = await getBudgetInfo(route.params.id);
|
||||
updateLoading.value = false
|
||||
updateLoading.value = false
|
||||
}
|
||||
|
||||
const updateBudgetCategory = async (category) => {
|
||||
@@ -638,7 +667,6 @@ onMounted(async () => {
|
||||
fetchPlannedExpenses(),
|
||||
fetchBudgetCategories(),
|
||||
fetchBudgetTransactions(),
|
||||
fetchBudgetTransactionCategoriesSums()
|
||||
]);
|
||||
} catch (error) {
|
||||
console.error('Error during fetching data:', error);
|
||||
|
||||
@@ -27,11 +27,11 @@ export const getBudgetInfos = async () => {
|
||||
export const getBudgetTransactions = async (budgetId, transactionType, categoryType) => {
|
||||
|
||||
let url = `/budgets/${budgetId}/transactions`
|
||||
if (transactionType) {
|
||||
url += '/' + transactionType
|
||||
if (transactionType && !categoryType) {
|
||||
url += '/?type=' + transactionType
|
||||
}
|
||||
if (transactionType && categoryType) {
|
||||
url += '/'+categoryType
|
||||
url += '/'+transactionType+'/'+categoryType
|
||||
}
|
||||
// if (!categoryType) {
|
||||
// throw new Error('No CategoryType');
|
||||
|
||||
Reference in New Issue
Block a user