This commit is contained in:
xds
2025-02-13 16:55:00 +03:00
parent 9cf3b8ef82
commit 6b04f4f82d
2 changed files with 119 additions and 13 deletions

View File

@@ -12,7 +12,7 @@ import {
} from "@/services/budgetsService";
import {Budget, BudgetCategory, Warn} from "@/models/Budget";
import {useRoute} from "vue-router";
import {formatAmount, formatDate} from "@/utils/utils";
import {formatAmount, formatDate, getMonthName, getMonthName2} from "@/utils/utils";
import ProgressBar from "primevue/progressbar";
import ProgressSpinner from "primevue/progressspinner";
import BudgetCategoryView from "@/components/budgets/BudgetCategoryView.vue";
@@ -27,7 +27,7 @@ import Divider from "primevue/divider";
import TransactionForm from "@/components/transactions/TransactionForm.vue";
import Checkbox from "primevue/checkbox";
import {useDrawerStore} from "@/stores/drawerStore";
import { EventBus } from '@/utils/EventBus.ts';
import {EventBus} from '@/utils/EventBus.ts';
// Зарегистрируем плагин
ChartJS.register(ChartDataLabels);
@@ -624,6 +624,74 @@ const expandCats = (value: boolean) => {
}
}
};
const calendarExpanded = ref(false);
const calendar = ref<{ date: Date, dateStr: string, expenses: any[], expensesSum: number }[]>([]);
watch([budget, plannedExpenses], () => {
if (!budget.value?.dateFrom || !budget.value?.dateTo) {
calendar.value = [];
return;
}
const result: { date: Date, dateStr: string, expenses: any[], expensesSum: number, }[] = [];
const startDate = new Date(budget.value.dateFrom);
const endDate = new Date(budget.value.dateTo);
let currentDate = new Date(startDate);
let lastDateWithExpenses = null;
let periodStart = null;
while (currentDate <= endDate) {
const formattedDate = currentDate.toISOString().split("T")[0];
const expenses = plannedExpenses.value.filter((transaction) => {
return transaction.date === formattedDate;
});
const expensesSum = expenses.reduce((sum, expense) => sum + (expense.amount || 0), 0);
if (expenses.length == 0) {
if (!periodStart) periodStart = new Date(currentDate); // Сохраняем начало периода без трат
} else {
if (lastDateWithExpenses && periodStart) {
// Добавляем период без трат, если он был
result.push({
date: currentDate,
dateStr: periodStart.toLocaleDateString('ru-RU') === new Date(new Date(currentDate).setDate(currentDate.getDate() - 1)).toLocaleDateString('ru-RU')
? periodStart.getUTCDate() + " " + getMonthName2(periodStart.getMonth(), "род") + " " + periodStart.getUTCFullYear() + ' трат нет.'
: `В период с ${periodStart.toLocaleDateString('ru-RU')} по ${new Date(new Date(currentDate).setDate(currentDate.getDate() - 1)).toLocaleDateString('ru-RU')} трат нет.`,
expenses: [],
expensesSum: 0,
});
periodStart = null;
}
// Добавляем день с тратами
lastDateWithExpenses = new Date(currentDate)
result.push({
date: currentDate,
dateStr: currentDate.getUTCDate() + " " + getMonthName2(currentDate.getMonth(), "род") + " " + currentDate.getUTCFullYear(),
expenses: expenses,
expensesSum: expensesSum,
});
// lastDateWithExpenses = new Date(currentDate); // Сохраняем дату с тратами
}
currentDate.setDate(currentDate.getDate() + 1);
}
// Добавляем последний период без трат, если он был
if (lastDateWithExpenses && periodStart) {
result.push({
date: currentDate,
dateStr: `В период с ${periodStart.toLocaleDateString('ru-RU')} по ${lastDateWithExpenses.toLocaleDateString('ru-RU')} трат нет.`,
expenses: [],
expensesSum: 0
});
periodStart = null;
}
calendar.value = result;
}, {immediate: true});
onMounted(async () => {
updateLoading.value = true;
@@ -637,7 +705,7 @@ onMounted(async () => {
// fetchBudgetCategories(),
// fetchBudgetTransactions(),
]);
EventBus.on('transactions-updated', fetchBudgetInfo,true);
EventBus.on('transactions-updated', fetchBudgetInfo, true);
} catch (error) {
console.error('Error during fetching data:', error);
} finally {
@@ -645,7 +713,7 @@ onMounted(async () => {
}
});
onUnmounted( async () => {
onUnmounted(async () => {
EventBus.off('transactions-updated', fetchBudgetInfo);
})
</script>
@@ -656,7 +724,7 @@ onUnmounted( async () => {
<div v-else class="px-4 bg-gray-100 h-full ">
<div class=" flex flex-col gap-3">
<div class=" flex flex-col gap-3">
<div class="flex flex-row justify-between ">
<div class="flex flex-col gap-2">
<h2 class="text-4xl font-bold">Бюджет {{ budget.name }} </h2>
@@ -698,6 +766,9 @@ onUnmounted( async () => {
</div>
</div>
<!-- hui {{calendar}}-->
<div class="flex flex-col gap-2">
<!-- Аналитика и плановые доходы/расходы -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4 items-start ">
@@ -934,12 +1005,34 @@ onUnmounted( async () => {
<div>
<!-- Планируемые расходы -->
<div class="pb-4">
<div class="flex flex-row gap-4 items-center mb-4">
<h3 class="text-2xl font-bold text-rose-500 ">Расходы</h3>
<button @click="openDrawer('PLANNED', 'EXPENSE')">
<span class="font-light text-sm">+ Добавить</span>
</button>
</div>
<div class="flex flex-col gap-4 pb-4">
<div class="flex flex-row gap-2"><span class="text-lg font-bold items-center">Календарь</span>
<button class="font-light text-sm" @click="calendarExpanded = !calendarExpanded">
{{ calendarExpanded ? 'Скрыть' : 'Раскрыть' }}
</button>
</div>
<div v-for="day, dayOne in calendar" class="flex flex-col justify-between p-4 shadow-lg rounded-lg " v-if="calendarExpanded"
:class="day.date.toISOString().split('T')[0] == new Date().toISOString().split('T')[0]? 'bg-emerald-200' : 'bg-white '">
<p class="font-bold text-xl">{{ day.dateStr }} <span
v-if="day.expensesSum>0"> Траты по плану: {{ formatAmount(day.expensesSum) }} </span></p>
<BudgetTransactionView v-for="expense in day.expenses" :key="expense.id"
:transaction="expense"
:is-list="false"
@transaction-updated="updateTransactions"
@transaction-checked="updateTransactions"
/>
</div>
</div>
<ul class="grid grid-cols-1 md:grid-cols-2 gap-4">
<li v-for="(category, categoryId) in categoriesTransactions" :key="categoryId"
class="flex flex-col justify-between p-4 shadow-lg rounded-lg bg-white ">
@@ -949,9 +1042,9 @@ onUnmounted( async () => {
<span class=" font-bold line-clamp-1" style="font-size: 1.25rem">{{
category.name.category.icon
}} {{ category.name.category.name }}</span>
<button @click="openDrawer('INSTANT', 'EXPENSE', category.name.category.id)">
<i class="pi pi-plus-circle"/>
</button>
<button @click="openDrawer('INSTANT', 'EXPENSE', category.name.category.id)">
<i class="pi pi-plus-circle"/>
</button>
</div>
<div class="flex flex-row w-fit gap-1 justify-between">
@@ -1058,10 +1151,10 @@ onUnmounted( async () => {
</div>
</div>
<!-- <TransactionForm v-if="drawerOpened" :visible="drawerOpened" :transaction-type="transactionType"-->
<!-- :category-type="categoryType" @close-drawer="closeDrawer" @transaction-updated="updateTransactions"-->
<!-- @delete-transaction="updateTransactions"-->
<!-- @create-transaction="updateTransactions"/>-->
<!-- <TransactionForm v-if="drawerOpened" :visible="drawerOpened" :transaction-type="transactionType"-->
<!-- :category-type="categoryType" @close-drawer="closeDrawer" @transaction-updated="updateTransactions"-->
<!-- @delete-transaction="updateTransactions"-->
<!-- @create-transaction="updateTransactions"/>-->
</div>
<div id="footer" class="h-24 bg-gray-100"/>

View File

@@ -45,6 +45,19 @@ export const getMonthName = (month: number) => {
}
}
export const getMonthName2 = (monthIndex: number, caseName: "имен" | "род" | "дат" | "вин" | "твор" | "пред") => {
const months = {
имен: ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"],
род: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"],
дат: ["январю", "февралю", "марту", "апрелю", "маю", "июню", "июлю", "августу", "сентябрю", "октябрю", "ноябрю", "декабрю"],
вин: ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"],
твор: ["январём", "февралём", "мартом", "апрелем", "маем", "июнем", "июлем", "августом", "сентябрем", "октябрем", "ноябрём", "декабрём"],
пред: ["январе", "феврале", "марте", "апреле", "мае", "июне", "июле", "августе", "сентябре", "октябре", "ноябре", "декабре"]
};
return months[caseName][monthIndex];
}
export const generateRandomColors = () => {
const r = Math.floor(Math.random() * 256);
@@ -52,7 +65,7 @@ export const generateRandomColors = () => {
const b = Math.floor(Math.random() * 256);
const a = 0.5; // Прозрачность от 0.00 до 1.00
return [r,g,b]
return [r, g, b]
}
// Пример использования