chet novoe

This commit is contained in:
Vladimir Voronin
2024-10-25 21:05:18 +03:00
parent f7b0ec50bf
commit f1573b9e30
7 changed files with 144 additions and 103 deletions

View File

@@ -4,6 +4,10 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
.p-inputnumber-input{
width: 7rem;
}
/*#app {*/ /*#app {*/
/* !*max-width: 1280px;*!*/ /* !*max-width: 1280px;*!*/
/* !*margin: 0 auto;*!*/ /* !*margin: 0 auto;*!*/

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import ProgressSpinner from "primevue/progressspinner";
</script>
<template>
<div class="relative w-full h-screen">
<!-- Полупрозрачный белый фон -->
<div class="absolute top-0 left-0 w-full h-full bg-white opacity-50 z-0"></div>
<!-- Спиннер поверх -->
<div class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-50">
<ProgressSpinner
style="width: 50px; height: 50px;"
strokeWidth="8"
fill="transparent"
animationDuration=".5s"
aria-label="Custom ProgressSpinner"
/>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,28 +1,29 @@
<template> <template>
<div class="px-4 bg-gray-100 h-full "> <LoadingView v-if="loading"/>
<div v-else class="px-4 bg-gray-100 h-full ">
<!-- Заголовок --> <!-- Заголовок -->
<h2 class="text-4xl mb-6 font-bold">Monthly Budgets</h2> <h2 class="text-4xl mb-6 font-bold">Monthly Budgets</h2>
<!-- Плитка с бюджетами --> <!-- Плитка с бюджетами -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Будущие и текущие бюджеты --> <!-- Будущие и текущие бюджеты -->
<div v-for="budget in upcomingBudgets" :key="budget.id" class="p-4 shadow-lg rounded-lg bg-white"> <div v-for="budget in budgetInfos" :key="budget.budget.id" class="p-4 shadow-lg rounded-lg bg-white" :class="budget.budget.dateTo < new Date() ? 'bg-gray-100 opacity-60' : ''">
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between">
<div class="text-xl font-bold mb-2">{{ budget.month }}</div> <div class="text-xl font-bold mb-2">{{ budget.budget.name }}</div>
<router-link to="/budgets/1"> <router-link :to="'/budgets/'+budget.budget.id">
<Button icon="pi pi-arrow-circle-right" rounded text size="large"/> <i class="pi pi-arrow-circle-right text-green-500" style="font-size: 1.5rem;"/>
</router-link> </router-link>
</div> </div>
<div class="text-sm text-gray-600 mb-4"> <div class="text-sm text-gray-600 mb-4">
{{ budget.startDate }} - {{ budget.endDate }} {{ formatDate(budget.budget.dateFrom) }} - {{ formatDate(budget.budget.dateTo) }}
</div> </div>
<div class="mb-4"> <div class="mb-4">
<div class="text-sm">Total Income: <span class="font-bold">{{ budget.totalIncome }}</span></div> <div class="text-sm">Total Income: <span class="font-bold">{{ formatAmount(budget.totalIncomes) }} </span></div>
<div class="text-sm">Total Expenses: <span class="font-bold">{{ budget.totalExpenses }}</span></div> <div class="text-sm">Total Expenses: <span class="font-bold">{{ formatAmount(budget.totalExpenses) }} </span></div>
<div class="text-sm">Planned Expenses: <span class="font-bold">{{ budget.plannedExpenses }}</span></div> <div class="text-sm">Planned Expenses: <span class="font-bold">{{ formatAmount(budget.totalExpenses) }} </span></div>
<div class="text-sm flex items-center"> <div class="text-sm flex items-center">
Unplanned Expenses: Unplanned Expenses:
<span class="ml-2 font-bold">{{ budget.remainingForUnplanned }}</span> <span class="ml-2 font-bold">{{ formatAmount(budget.totalIncomes - budget.totalExpenses) }} </span>
<!-- Прогресс бар --> <!-- Прогресс бар -->
<ProgressBar :value="budget.unplannedProgress" class="ml-4 w-full"/> <ProgressBar :value="budget.unplannedProgress" class="ml-4 w-full"/>
</div> </div>
@@ -51,18 +52,18 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import {ref} from 'vue'; import {onMounted, ref} from 'vue';
import ProgressBar from 'primevue/progressbar'; import ProgressBar from 'primevue/progressbar';
import Button from "primevue/button"; import {BudgetInfo} from "@/models/Budget";
import {getBudgetInfos} from "@/services/budgetsService";
import {formatAmount, formatDate} from "@/utils/utils";
import LoadingView from "@/components/LoadingView.vue";
export default { const loading = ref(false)
components: { const budgetInfos = ref<BudgetInfo[]>([])
ProgressBar,
Button const upcomingBudgets = ref([
},
setup() {
const upcomingBudgets = ref([
{ {
id: 1, id: 1,
month: 'October 2024', month: 'October 2024',
@@ -85,9 +86,8 @@ export default {
remainingForUnplanned: '70,000 RUB', remainingForUnplanned: '70,000 RUB',
unplannedProgress: 50, unplannedProgress: 50,
}, },
]); ]);
const pastBudgets = ref([
const pastBudgets = ref([
{ {
id: 3, id: 3,
month: 'September 2024', month: 'September 2024',
@@ -110,14 +110,14 @@ export default {
remainingForUnplanned: '50,000 RUB', remainingForUnplanned: '50,000 RUB',
unplannedProgress: 85, unplannedProgress: 85,
}, },
]); ]);
return { onMounted(async () => {
upcomingBudgets, loading.value = true;
pastBudgets, budgetInfos.value = await getBudgetInfos()
}; console.log(budgetInfos.value)
}, loading.value = false
}; })
</script> </script>
<style scoped> <style scoped>

View File

@@ -1,20 +1,6 @@
<template> <template>
<Toast/> <Toast/>
<div v-if="loading" class="relative w-full h-screen"> <LoadingView v-if="loading"/>
<!-- Полупрозрачный белый фон -->
<div class="absolute top-0 left-0 w-full h-full bg-white opacity-50 z-0"></div>
<!-- Спиннер поверх -->
<div class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-50">
<ProgressSpinner
style="width: 50px; height: 50px;"
strokeWidth="8"
fill="transparent"
animationDuration=".5s"
aria-label="Custom ProgressSpinner"
/>
</div>
</div>
<div v-else class="px-4 bg-gray-100 h-full "> <div v-else class="px-4 bg-gray-100 h-full ">
<div v-if="updateLoading" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-50"> <div v-if="updateLoading" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-50">
@@ -216,6 +202,7 @@ import UnplannedCategoryView from "@/components/budgets/UnplannedCategoryView.vu
import {TransactionType} from "@/models/Transaction"; import {TransactionType} from "@/models/Transaction";
import Toast from "primevue/toast"; import Toast from "primevue/toast";
import Button from "primevue/button"; import Button from "primevue/button";
import LoadingView from "@/components/LoadingView.vue";
const loading = ref(true); const loading = ref(true);
const updateLoading = ref(false); const updateLoading = ref(false);

View File

@@ -18,6 +18,7 @@ import {
} from "@/services/transactionService"; } from "@/services/transactionService";
import {getCategories, getCategoryTypes} from "@/services/categoryService"; import {getCategories, getCategoryTypes} from "@/services/categoryService";
import {useToast} from "primevue/usetoast"; import {useToast} from "primevue/usetoast";
import LoadingView from "@/components/LoadingView.vue";
const props = defineProps({ const props = defineProps({
visible: { visible: {
@@ -192,9 +193,7 @@ onMounted(async () => {
<Drawer :visible="visible" :header="isEditing ? 'Edit Transaction' : 'Create Transaction'" :showCloseIcon="false" <Drawer :visible="visible" :header="isEditing ? 'Edit Transaction' : 'Create Transaction'" :showCloseIcon="false"
position="right" @hide="closeDrawer" position="right" @hide="closeDrawer"
class="!w-128 "> class="!w-128 ">
<div v-if="loading"> <LoadingView v-if="loading"/>
Loading...
</div>
<div v-else class=" grid gap-4 w-full "> <div v-else class=" grid gap-4 w-full ">
<div class="relative w-full justify-center justify-items-center "> <div class="relative w-full justify-center justify-items-center ">
@@ -253,11 +252,11 @@ onMounted(async () => {
</div> </div>
</div> </div>
</div> </div>
<div class="grid grid-cols-4"> <div class="flex flex-row gap-4">
<div class=" ">
<FloatLabel variant="on" class="w-10">
<InputNumber class="!w-10" <FloatLabel variant="on" class="">
<InputNumber class=""
:invalid="!editedTransaction.amount" :invalid="!editedTransaction.amount"
:minFractionDigits="0" :minFractionDigits="0"
id="amount" id="amount"
@@ -267,12 +266,12 @@ onMounted(async () => {
locale="ru-RU" locale="ru-RU"
/> />
<label for="amount" class="!w-10">Amount</label> <label for="amount" class="">Amount</label>
</FloatLabel> </FloatLabel>
</div>
<!-- Comment Input --> <!-- Comment Input -->
<div class="field col-12 col-span-3">
<FloatLabel variant="on" class="l"> <FloatLabel variant="on" class="w-full">
<label for="comment">Comment</label> <label for="comment">Comment</label>
<InputText class="w-full" <InputText class="w-full"
:invalid="!editedTransaction.comment" :invalid="!editedTransaction.comment"
@@ -281,7 +280,7 @@ onMounted(async () => {
/> />
</FloatLabel> </FloatLabel>
</div>
</div> </div>
<!-- Date Picker --> <!-- Date Picker -->
@@ -309,7 +308,7 @@ onMounted(async () => {
<!-- Buttons --> <!-- Buttons -->
<div class="field col-12 flex justify-content-end gap-4"> <div class="fixed col-12 bottom-6 flex justify-content-end gap-4">
<Button label="Save" icon="pi pi-check" class="p-button-success" <Button label="Save" icon="pi pi-check" class="p-button-success"
@click="isEditing ? updateTransaction() : createTransaction()"/> @click="isEditing ? updateTransaction() : createTransaction()"/>

View File

@@ -4,7 +4,8 @@ import { useRouter } from 'vue-router';
// Создаем экземпляр axios // Создаем экземпляр axios
const api = axios.create({ const api = axios.create({
baseURL: 'https://luminic.space/api/v1', // baseURL: 'https://luminic.space/api/v1',
baseURL: 'http://localhost:8000/api/v1',
}); });
// Устанавливаем токен из localStorage при каждом запуске // Устанавливаем токен из localStorage при каждом запуске

View File

@@ -1,7 +1,29 @@
import apiClient from '@/services/axiosSetup'; import apiClient from '@/services/axiosSetup';
import {BudgetCategory} from "@/models/Budget"; import {Budget, BudgetCategory} from "@/models/Budget";
// Импортируете настроенный экземпляр axios // Импортируете настроенный экземпляр axios
export const getBudgetInfos = async () => {
console.log('getBudgetInfos');
let response = await apiClient.get('/budgets/');
let budgetInfos = response.data;
budgetInfos.forEach((budgetInfo: Budget) => {
budgetInfo.budget.dateFrom = new Date(budgetInfo.budget.dateFrom);
budgetInfo.budget.dateTo = new Date(budgetInfo.budget.dateTo);
budgetInfo.plannedExpenses.forEach(e => {
e.date = new Date(e.date)
})
budgetInfo.plannedIncomes.forEach(e => {
e.date = new Date(e.date)
})
budgetInfo.transactions.forEach(e => {
e.date = new Date(e.date)
})
})
return budgetInfos
}
export const getBudgetInfo = async (budget_id: number) => { export const getBudgetInfo = async (budget_id: number) => {
console.log('getBudgetInfo'); console.log('getBudgetInfo');
let budgetInfo = await apiClient.get('/budgets/' + budget_id); let budgetInfo = await apiClient.get('/budgets/' + budget_id);