chet novoe

This commit is contained in:
Vladimir Voronin
2024-10-30 12:49:10 +03:00
parent eede3430b0
commit 5e49e223ee
2 changed files with 91 additions and 63 deletions

View File

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

View File

@@ -27,11 +27,11 @@ export const getBudgetInfos = async () => {
export const getBudgetTransactions = async (budgetId, transactionType, categoryType) => { export const getBudgetTransactions = async (budgetId, transactionType, categoryType) => {
let url = `/budgets/${budgetId}/transactions` let url = `/budgets/${budgetId}/transactions`
if (transactionType) { if (transactionType && !categoryType) {
url += '/' + transactionType url += '/?type=' + transactionType
} }
if (transactionType && categoryType) { if (transactionType && categoryType) {
url += '/'+categoryType url += '/'+transactionType+'/'+categoryType
} }
// if (!categoryType) { // if (!categoryType) {
// throw new Error('No CategoryType'); // throw new Error('No CategoryType');