+ some fixes

This commit is contained in:
xds
2025-05-26 13:58:56 +03:00
parent 961d6ba2b9
commit df20496180
6 changed files with 129 additions and 51 deletions

View File

@@ -15,7 +15,7 @@
<!-- Название --> <!-- Название -->
<FloatLabel class="w-full" variant="on"> <FloatLabel class="w-full" variant="on">
<label for="paymentName">Название платежа</label> <label for="paymentName">Название платежа</label>
<InputText v-model="name" id="paymentName" class="!w-full"/> <InputText v-model="payment.name" id="paymentName" class="!w-full"/>
</FloatLabel> </FloatLabel>
<!-- Категория --> <!-- Категория -->
@@ -64,7 +64,7 @@
<!-- Описание --> <!-- Описание -->
<FloatLabel class="!w-full"> <FloatLabel class="!w-full">
<label for="description">Описание</label> <label for="description">Описание</label>
<Textarea v-model="description" id="description" rows="3" class="!w-full"/> <Textarea v-model="payment.description" id="description" rows="3" class="!w-full"/>
</FloatLabel> </FloatLabel>
<!-- Дата повторения (выпадающий список) --> <!-- Дата повторения (выпадающий список) -->
@@ -73,7 +73,7 @@
@click="isDaySelectorOpened = !isDaySelectorOpened"> @click="isDaySelectorOpened = !isDaySelectorOpened">
<div class="flex flex-row items-center pe-4 py-2 gap-4"> <div class="flex flex-row items-center pe-4 py-2 gap-4">
<div class="flex flex-row justify-between w-full px-4"> <div class="flex flex-row justify-between w-full px-4">
<p class="font-bold">Повторять каждый {{ repeatDay || 'N' }} день месяца</p> <p class="font-bold">Повторять каждый {{ payment.atDay || 'N' }} день месяца</p>
</div> </div>
<div> <div>
<span :class="{'rotate-90': isDaySelectorOpened}" <span :class="{'rotate-90': isDaySelectorOpened}"
@@ -98,7 +98,7 @@
<!-- Сумма --> <!-- Сумма -->
<InputGroup class="w-full"> <InputGroup class="w-full">
<InputGroupAddon></InputGroupAddon> <InputGroupAddon></InputGroupAddon>
<InputNumber v-model="amount" placeholder="Сумма"/> <InputNumber v-model="payment.amount" placeholder="Сумма"/>
<InputGroupAddon>.00</InputGroupAddon> <InputGroupAddon>.00</InputGroupAddon>
</InputGroup> </InputGroup>
@@ -117,7 +117,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, watch, computed, defineEmits} from 'vue'; import {ref, watch, computed, defineEmits, nextTick} from 'vue';
import Button from 'primevue/button'; import Button from 'primevue/button';
import InputText from 'primevue/inputtext'; import InputText from 'primevue/inputtext';
import InputNumber from 'primevue/inputnumber'; import InputNumber from 'primevue/inputnumber';
@@ -128,14 +128,19 @@ import FloatLabel from 'primevue/floatlabel';
import InputGroup from 'primevue/inputgroup'; import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from "primevue/inputgroupaddon"; import InputGroupAddon from "primevue/inputgroupaddon";
import SelectButton from 'primevue/selectbutton'; import SelectButton from 'primevue/selectbutton';
import {saveRecurrentPayment} from "@/services/recurrentService"; import {saveRecurrentPayment, updateRecurrent} from "@/services/recurrentService";
import {Category} from "@/models/Category";
import {RecurrentPayment} from "@/models/Recurrent";
import {useToast} from "primevue/usetoast";
const toast = useToast()
const props = defineProps({ const props = defineProps({
show: Boolean, // Показать/скрыть модальное окно show: Boolean, // Показать/скрыть модальное окно
expenseCategories: Array, // Внешние данные для списка категорий expenseCategories: Array, // Внешние данные для списка категорий
incomeCategories: Array, // Внешние данные для списка категорий incomeCategories: Array, // Внешние данные для списка категорий
categoryTypes: Array, categoryTypes: Array,
payment: Object | null // Для редактирования существующего платежа payment: RecurrentPayment | null // Для редактирования существующего платежа
}) })
const emits = defineEmits(["open-edit", "save-payment", "close-modal"]); const emits = defineEmits(["open-edit", "save-payment", "close-modal"]);
@@ -143,13 +148,12 @@ const emits = defineEmits(["open-edit", "save-payment", "close-modal"]);
const loading = ref(false) const loading = ref(false)
// Поля для формы // Поля для формы
const name = ref(''); const name = ref('');
const selectedCategoryType = ref(props.payment ? props.payment.type : props.categoryTypes[0]); const payment = ref(props.payment ? props.payment : new RecurrentPayment())
console.log(props.categoryTypes) const selectedCategoryType = ref(props.payment ? props.payment.category.type : props.categoryTypes[0]);
console.log(selectedCategoryType.value)
console.log(props.expenseCategories) const selectedCategory = ref(props.payment ? props.payment.category : selectedCategoryType.code == 'EXPENSE'
console.log(props.incomeCategories) ? props.expenseCategories[0]
const selectedCategory = ref(selectedCategoryType.code == 'EXPENSE' ? props.expenseCategories[0] ? props.expenseCategories[0] : props.incomeCategories[0] : props.incomeCategories[0] ? props.incomeCategories[0] : props.expenseCategories[0]); : props.incomeCategories[0]);
console.log(selectedCategory.value)
const categoryTypeChanged = (code) => { const categoryTypeChanged = (code) => {
@@ -170,12 +174,15 @@ const days = Array.from({length: 31}, (_, i) => i + 1);
// Выбор дня // Выбор дня
const selectDay = (day: number) => { const selectDay = (day: number) => {
console.log(day)
payment.value.atDay = day;
repeatDay.value = day; repeatDay.value = day;
isDaySelectorOpened.value = false; isDaySelectorOpened.value = false;
}; };
// Выбор категории // Выбор категории
const selectCategory = (category) => { const selectCategory = (category: Category) => {
payment.value.category = category;
isCategorySelectorOpened.value = false; isCategorySelectorOpened.value = false;
selectedCategory.value = category; selectedCategory.value = category;
}; };
@@ -211,13 +218,32 @@ const savePayment = async () => {
if (isEditing.value && props.payment) { if (isEditing.value && props.payment) {
paymentData.id = props.payment.id; // Если редактируем, сохраняем ID paymentData.id = props.payment.id; // Если редактируем, сохраняем ID
} }
try { // try {
await saveRecurrentPayment(paymentData) if (props.payment) {
loading.value = false await updateRecurrent(payment.value)
resetForm(); .then(res => {
} catch (error) { loading.value = false;
console.error('Error saving payment:', error); })
.catch((err) => {
console.log(err)
toast.add({severity: 'error', summary: 'Ошибка сохранения', detail: err.response.data.message, life: 3000})
})
} }
else {
await saveRecurrentPayment(payment.value)
.then(() => {
loading.value = false;
})
.catch((err) => {
toast.add({severity: 'error', summary: 'Ошибка сохранения', detail: err.response.data.message, life: 3000})
console.log(err)
})
}
// loading.value = false
// resetForm();
// } catch (error) {
// console.error('Error saving payment:', error);
// }
emits('save-payment', paymentData); emits('save-payment', paymentData);
resetForm(); resetForm();
closeModal(); closeModal();

View File

@@ -26,6 +26,7 @@ const loading = ref(false)
// Поля для формы // Поля для формы
const name = ref(''); const name = ref('');
const selectedCategoryType = ref(props.payment ? props.payment.type : props.categoryTypes[0]); const selectedCategoryType = ref(props.payment ? props.payment.type : props.categoryTypes[0]);
console.log(selectedCategoryType.value);
const selectedCategory = ref(selectedCategoryType.code == 'EXPESE' ? props.expenseCategories[0] : props.incomeCategories[0]); const selectedCategory = ref(selectedCategoryType.code == 'EXPESE' ? props.expenseCategories[0] : props.incomeCategories[0]);
const categoryTypeChanged = (code) => { const categoryTypeChanged = (code) => {

View File

@@ -7,7 +7,8 @@
<!-- Заголовок --> <!-- Заголовок -->
<div class="flex flex-col gap-4 xl:flex-row justify-between bg-gray-100"> <div class="flex flex-col gap-4 xl:flex-row justify-between bg-gray-100">
<h1 class="text-4xl text-gray-800">Ежемесячные платежи</h1> <h1 class="text-4xl text-gray-800">Ежемесячные платежи</h1>
<Button label="Добавить платеж" icon="pi pi-plus" class="text-sm !bg-blue-300 hover:!bg-blue-400 !border-blue-300" @click="toggleModal(null)"/> <Button label="Добавить платеж" icon="pi pi-plus"
class="text-sm !bg-blue-300 hover:!bg-blue-400 !border-blue-300" @click="toggleModal(null)"/>
</div> </div>
<div v-if="!space">Выберите сперва пространство</div> <div v-if="!space">Выберите сперва пространство</div>
<!-- Список рекуррентных платежей --> <!-- Список рекуррентных платежей -->
@@ -20,23 +21,24 @@
@delete-payment="deletePayment" @delete-payment="deletePayment"
/> />
<div> <div>
<!-- <div--> <!-- <div-->
<!-- class=" bg-white shadow-lg rounded-lg p-6 ">--> <!-- class=" bg-white shadow-lg rounded-lg p-6 ">-->
<!-- <div class="flex justify-between items-center">--> <!-- <div class="flex justify-between items-center">-->
<!-- <div class="flex items-center w-full justify-center gap-4" style="height: 160px;">--> <!-- <div class="flex items-center w-full justify-center gap-4" style="height: 160px;">-->
<!-- <Button text class="flex-col" @click="toggleModal">--> <!-- <Button text class="flex-col" @click="toggleModal">-->
<!-- <i class="pi pi-plus-circle" style="font-size: 2.5rem"></i>--> <!-- <i class="pi pi-plus-circle" style="font-size: 2.5rem"></i>-->
<!-- <p></p>--> <!-- <p></p>-->
<!-- </Button>--> <!-- </Button>-->
<CreateRecurrentModal <CreateRecurrentModal
v-if="showModal" v-if="showModal"
:show="showModal" :show="showModal"
:expenseCategories="expenseCategories" :expenseCategories="expenseCategories"
:incomeCategories="incomeCategories" :incomeCategories="incomeCategories"
:categoryTypes="categoryTypes" :categoryTypes="categoryTypes"
@save-payment="savePayment" :payment="editingPayment"
@close-modal="toggleModal"/> @save-payment="savePayment"
@close-modal="toggleModal"/>
</div> </div>
</div> </div>
@@ -49,13 +51,18 @@ import {computed, onMounted, ref, watch} from 'vue';
import RecurrentListItem from "@/components/settings/recurrent/RecurrentListItem.vue"; import RecurrentListItem from "@/components/settings/recurrent/RecurrentListItem.vue";
import Button from "primevue/button"; import Button from "primevue/button";
import {RecurrentPayment} from "@/models/Recurrent"; import {RecurrentPayment} from "@/models/Recurrent";
import {getRecurrentPayments} from "@/services/recurrentService"; import {deleteRecurrent, getRecurrentPayments} from "@/services/recurrentService";
import CreateRecurrentModal from "@/components/settings/recurrent/CreateRecurrentModal.vue"; import CreateRecurrentModal from "@/components/settings/recurrent/CreateRecurrentModal.vue";
import {Category, CategoryType} from "@/models/Category"; import {Category, CategoryType} from "@/models/Category";
import {getCategories, getCategoryTypes} from "@/services/categoryService"; import {deleteCategoryRequest, getCategories, getCategoryTypes} from "@/services/categoryService";
import LoadingView from "@/components/LoadingView.vue"; import LoadingView from "@/components/LoadingView.vue";
import {useSpaceStore} from "@/stores/spaceStore"; import {useSpaceStore} from "@/stores/spaceStore";
import {getBudgetInfos} from "@/services/budgetsService"; import {getBudgetInfos} from "@/services/budgetsService";
import {useConfirm} from "primevue/useconfirm";
import {useToast} from "primevue/usetoast";
const confirm = useConfirm();
const toast = useToast()
const spaceStore = useSpaceStore() const spaceStore = useSpaceStore()
@@ -84,7 +91,9 @@ const loading = ref(true);
const showModal = ref(false); const showModal = ref(false);
const toggleModal = () => { const editingPayment = ref<RecurrentPayment | null>(null);
const toggleModal = (payment: RecurrentPayment | null) => {
editingPayment.value = payment
showModal.value = !showModal.value; showModal.value = !showModal.value;
} }
@@ -137,11 +146,39 @@ const savePayment = async () => {
// Обработчики событий // Обработчики событий
const editPayment = (payment: any) => { const editPayment = (payment: RecurrentPayment) => {
toggleModal(payment)
}; };
const deletePayment = (payment: any) => { const deletePayment = (payment: RecurrentPayment) => {
console.log('delete payment:', payment);
confirm.require({
message: 'Вы уверены, что хотите выполнить это действие?\n Это нельзя будет отменить.\n',
header: `Удаление ежемесячной транзакции ${payment.name}`,
icon: 'pi pi-info-circle',
rejectLabel: 'Cancel',
rejectProps: {
label: 'Cancel',
severity: 'secondary',
outlined: true
},
acceptProps: {
label: 'Delete',
severity: 'danger'
},
accept: async () => {
await deleteRecurrent(payment.id).then(async (result) => {
await fetchRecurrentPayments()
toast.add({severity: 'info', summary: 'Confirmed', detail: 'Удалено!', life: 3000});
}).catch(((err) => {
toast.add({severity: 'error', summary: 'Rejected', detail: 'Ошибка удаления платежа', life: 3000});
})
)
},
reject: () => {
// toast.add({severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000});
}
});
}; };

View File

@@ -69,6 +69,7 @@ const editPayment = () => {
}; };
const deletePayment = () => { const deletePayment = () => {
console.log('deleting payment');
emit('delete-payment', props.payment); emit('delete-payment', props.payment);
}; };
</script> </script>

View File

@@ -2,6 +2,7 @@ import {Category} from "@/models/Category";
export class RecurrentPayment { export class RecurrentPayment {
public id: number; public id: number;
public space: Space;
public atDay: number; public atDay: number;
public category: Category; public category: Category;
public name: string; public name: string;

View File

@@ -12,6 +12,7 @@ export const getRecurrentPayments = async () => {
export const saveRecurrentPayment = async (payment: RecurrentPayment) => { export const saveRecurrentPayment = async (payment: RecurrentPayment) => {
const spaceStore = useSpaceStore() const spaceStore = useSpaceStore()
payment.space = spaceStore.space
return await apiClient.post(`/spaces/${spaceStore.space?.id}/recurrents`, payment) return await apiClient.post(`/spaces/${spaceStore.space?.id}/recurrents`, payment)
} }
// //
@@ -23,10 +24,21 @@ export const saveRecurrentPayment = async (payment: RecurrentPayment) => {
// return await apiClient.post('/categories', category); // return await apiClient.post('/categories', category);
// }; // };
// //
// export const updateCategory = async (id: number, category: any) => { export const updateRecurrent = async (recurrent: RecurrentPayment) => {
// return await apiClient.put(`/categories/${id}`, category); const id = recurrent.id
// }; const spaceStore = useSpaceStore()
// recurrent.space = spaceStore.space
// export const deleteCategory = async (id: number) => { return await apiClient.put(`/spaces/${spaceStore.space?.id}/recurrents/${id}`, recurrent)
// return await apiClient.delete(`/categories/${id}`); .then(res => res.data)
// }; .catch(err => {
console.log(err)
throw err
})
};
export const deleteRecurrent = async (id: number) => {
const spaceStore = useSpaceStore()
return await apiClient.delete(`/spaces/${spaceStore.space?.id}/recurrents/${id}`)
.then(res => res.data)
.catch(err => console.log(err))
};