+ prediction

This commit is contained in:
xds
2025-04-07 18:26:54 +03:00
parent 2e33e07d1f
commit e97f5f8d5f
2 changed files with 82 additions and 26 deletions

View File

@@ -16,7 +16,7 @@ import {
updateTransactionRequest,
deleteTransactionRequest, getTransactions
} from "@/services/transactionService";
import {getCategories, getCategoryTypes} from "@/services/categoryService";
import {getCategories, getCategoriesPredict, getCategoryTypes} from "@/services/categoryService";
import {useToast} from "primevue/usetoast";
import LoadingView from "@/components/LoadingView.vue";
import BudgetTransactionView from "@/components/budgets/BudgetTransactionView.vue";
@@ -53,9 +53,13 @@ const categoryTypeChanged = () => {
editedTransaction.value.category = selectedCategoryType.value.code == "EXPENSE" ? expenseCategories.value[0] : incomeCategories.value[0];
}
const selectCategory = (category) => {
const isSelectedFromPredict = ref<boolean>();
const selectCategory = (category, fromPredict: boolean) => {
isCategorySelectorOpened.value = false;
editedTransaction.value.category = category;
isSelectedFromPredict.value = fromPredict;
};
@@ -70,6 +74,7 @@ const selectedTransactionType = ref<TransactionType | null>(null);
const selectedCategory = ref<Category | null>(null);
const entireCategories = ref<Category[]>([]);
const predictedCategories = ref<Category[]>([]);
const expenseCategories = ref<Category[]>([]);
const incomeCategories = ref<Category[]>([]);
const categoryTypes = ref<CategoryType[]>([]);
@@ -231,7 +236,18 @@ const createTransaction = async (): Promise<void> => {
}, 1000);
};
const predictionsLoading = ref(false);
const anotherCategories = ref([]);
const fetchPredictions = async () => {
if (editedTransaction.value?.comment) {
predictedCategories.value = await getCategoriesPredict(editedTransaction.value?.comment);
} else {
predictedCategories.value = []
}
predictedCategories.value.forEach((predictedCategory) => {
anotherCategories.value.push(entireCategories.value.find(category => predictedCategory.id != category.id));
})
}
const transactionsUpdatedEmit = async () => {
await getTransactions('INSTANT', 'EXPENSE', null, user.value.id, false, 3).then(transactionsResponse => transactions.value = transactionsResponse.data);
@@ -286,7 +302,7 @@ const deleteTransaction = async () => {
// Сброс формы
const resetForm = () => {
predictedCategories.value = []
// editedTransaction.value.date = new Date();
editedTransaction.value.amount = null;
editedTransaction.value.comment = '';
@@ -387,26 +403,7 @@ onMounted(async () => {
aria-labelledby="basic"
@change="categoryTypeChanged" class="justify-center"/>
</div>
<button class="border border-gray-300 rounded-lg w-full z-40"
@click="isCategorySelectorOpened = !isCategorySelectorOpened">
<div class="flex flex-row items-center pe-4 py-2 ">
<div class="flex flex-row justify-between w-full gap-4 px-4 items-center">
<p class="text-3xl font-bold text-gray-700 dark:text-gray-400">{{
editedTransaction.category.icon
}}</p>
<div class="flex flex-col items-start justify-items-start justify-around w-full">
<p class="font-bold text-start line-clamp-1">{{ editedTransaction.category.name }}</p>
<p class="font-light line-clamp-1 items-start text-start">{{
editedTransaction.category.description
}}</p>
</div>
</div>
<div>
<span :class="{'rotate-90': isCategorySelectorOpened}"
class="pi pi-angle-right transition-transform duration-300 text-5xl"/>
</div>
</div>
</button>
</div>
<!-- Анимированное открытие списка категорий -->
@@ -417,7 +414,7 @@ onMounted(async () => {
<button
v-for="category in editedTransaction.category.type.code == 'EXPENSE' ? expenseCategories : incomeCategories"
:key="category.id" class="border rounded-lg mx-2 mb-2"
@click="selectCategory(category)">
@click="selectCategory(category, false)">
<div class="flex flex-row justify-between w-full px-2">
<p class="text-4xl font-bold text-gray-700 dark:text-gray-400">{{ category.icon }}</p>
<div class="flex flex-col items-start justify-items-start justify-around w-full">
@@ -460,10 +457,57 @@ onMounted(async () => {
v-model="editedTransaction.comment"
@focus="keyboardOpen=true"
@blur="keyboardOpen=false"
@change="fetchPredictions"
/>
</FloatLabel>
</div>
<div class="grid grid-cols-2 gap-2">
<button v-for="category in predictedCategories" class="border-2 border-gray-300 rounded-lg w-full z-40"
:class="isSelectedFromPredict && editedTransaction.category.id == category.id ? 'border-5 border-emerald-400' : ''"
@click="selectCategory(category, true)">
<div class="flex flex-row items-center pe-4 py-2 ">
<div class="flex flex-row justify-between w-full gap-4 px-4 items-center">
<p class="text-3xl font-bold text-gray-700 dark:text-gray-400">{{
category.icon
}}</p>
<div class="flex flex-col items-start justify-items-start justify-around w-full">
<p class="font-bold text-start line-clamp-1">{{ category.name }}</p>
<p class="font-light line-clamp-1 items-start text-start">{{
category.description
}}</p>
</div>
</div>
<div>
<span :class="{'rotate-90': isCategorySelectorOpened}"
class="pi pi-angle-right transition-transform duration-300 text-5xl"/>
</div>
</div>
</button>
<button v-if="predictedCategories.length>0"
:class="!isSelectedFromPredict ? 'border-5 border-emerald-400' : 'border-5 border-gray-300'"
class="border-2 rounded-lg w-full z-40 outline-2"
@click="isCategorySelectorOpened = !isCategorySelectorOpened">
<div class="flex flex-row items-center pe-4 py-2 ">
<div class="flex flex-row justify-between w-full gap-4 px-4 items-center">
<p class="text-3xl font-bold text-gray-700 dark:text-gray-400">{{
!isSelectedFromPredict ? editedTransaction.category.icon : anotherCategories[0].icon
}}</p>
<div class="flex flex-col items-start justify-items-start justify-around w-full">
<p class="font-bold text-start line-clamp-1">{{ !isSelectedFromPredict ? editedTransaction.category.name : anotherCategories[0].name }}</p>
<p class="font-light text-xs line-clamp-1 items-start text-start">Нажмите чтобы выбрать другую категорию</p>
<!-- <p class="font-light line-clamp-1 items-start text-start">Нажмите чтобы выбрать другую категорию</p>-->
</div>
</div>
<div>
<span :class="{'rotate-90': isCategorySelectorOpened}"
class="pi pi-angle-right transition-transform duration-300 text-5xl"/>
</div>
</div>
</button>
<!-- <span v-else >Введите комментарий и категории появится</span>-->
</div>
<!-- Date Picker -->
<div class="field col-12 gap-0">

View File

@@ -15,6 +15,16 @@ export const getCategories = async (type = null) => {
});
};
export const getCategoriesPredict = async (comment:string) => {
const spaceStore = await useSpaceStore();
return await apiClient.get(`/spaces/${spaceStore.space?.id}/category-predict?comment=${comment}&cloud=0`)
.then(res => res.data)
.catch(err => {
throw err;
});
}
export const getCategoryTypes = async () => {
const spaceStore = useSpaceStore();
return await apiClient.get(`/spaces/${spaceStore.space?.id}/categories/types`);
@@ -42,7 +52,9 @@ export const deleteCategoryRequest = async (id: string) => {
const spaceStore = useSpaceStore();
return await apiClient.delete(`/spaces/${spaceStore.space?.id}/categories/${id}`)
.then(res => res.data)
.catch(err => {throw err})
.catch(err => {
throw err
})
};
export const getCategoriesSumsRequest = async (spaceId: string) => {