Fix document upload
This commit is contained in:
parent
5e591eaea9
commit
c3259b7e6c
@ -2,7 +2,7 @@ NODE_ENV=development
|
||||
VITE_API_URL=https://joyworkdev.ru
|
||||
VITE_LARAVEL_URL=https://llar.joyworkdev.ru
|
||||
VITE_LARAVEL_API_URL=https://joyworkdev.ru
|
||||
VITE_DEV_SESSION_ID=e140a9d56a24f47046b9ab0953e5a9ee
|
||||
VITE_DEV_SESSION_ID=87ae8a661f903a5958e2a36aeaffb970
|
||||
VITE_DEV_REQUISITION_ID=17539
|
||||
#VITE_BASIC_AUTH_USER=adminlogin
|
||||
#VITE_BASIC_AUTH_PASS=adminpassword
|
||||
30
src/App.vue
30
src/App.vue
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Сделка</h1>
|
||||
<a href="#" @click.prevent="createDeal(17539)">Открыть тестовую сделку</a>
|
||||
<div><a href="#" @click.prevent="createDeal(17539)">Создать новую сделку</a></div>
|
||||
<div><a href="#" @click.prevent="editDeal(17539, 46)">Открыть тестовую сделку</a></div>
|
||||
</div>
|
||||
<DynamicDialog />
|
||||
</template>
|
||||
@ -36,12 +37,31 @@ const createDeal = (newDealReqId) => {
|
||||
})
|
||||
}
|
||||
|
||||
const editDeal = (id) => {
|
||||
isOpen.value = true
|
||||
dealId.value = id
|
||||
newDealReqId.value = null
|
||||
const editDeal = (newDealReqId, dealId) => {
|
||||
console.log('[editDeal] Открываем DealModal через DynamicDialog', dealId)
|
||||
|
||||
dialog.open(DealModal, {
|
||||
props: {
|
||||
header: 'Редактирование сделки',
|
||||
style: { width: '80vw' },
|
||||
modal: true
|
||||
},
|
||||
data: {
|
||||
newDealReqId: newDealReqId,
|
||||
deal_id: dealId
|
||||
},
|
||||
onClose: (opt) => {
|
||||
console.log('[DynamicDialog] Закрыто с данными:', opt?.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// const editDeal = (id) => {
|
||||
// isOpen.value = true
|
||||
// dealId.value = id
|
||||
// newDealReqId.value = null
|
||||
// }
|
||||
|
||||
const backToStep = () => {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
@ -294,10 +294,10 @@
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<div class="form__item flex flex-col gap-1 w-full mb-3">
|
||||
<label for="deal_sellers_count">Количество покупателей:</label>
|
||||
<label for="deal_buyers_count">Количество покупателей:</label>
|
||||
<InputNumber
|
||||
v-model="deal.buyers_count"
|
||||
id="deal_sellers_count"
|
||||
id="deal_buyers_count"
|
||||
/>
|
||||
</div>
|
||||
<div class="form__item flex flex-col gap-1 w-full mb-3">
|
||||
@ -360,8 +360,14 @@
|
||||
|
||||
<h3>Документы</h3>
|
||||
<div class="flex w-full flex-wrap">
|
||||
<DocAddModal v-if="showModalDealDoc" :deal="deal" @close="closeModalDealDoc" @select="addDoc" />
|
||||
<DocsCard v-for="doc in selectedDocs" :key="doc.id" :doc="doc" :urlLaravel="urlLaravel" @remove="removeDoc" />
|
||||
<!-- <DocAddModal v-if="showModalDealDoc" :deal="deal" @close="closeModalDealDoc" @select="addDoc" />-->
|
||||
<DocsCard
|
||||
v-for="doc in selectedDocs"
|
||||
:key="doc.id"
|
||||
:doc="doc"
|
||||
:urlLaravel="urlLaravel"
|
||||
@remove="removeDoc"
|
||||
/>
|
||||
<div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 p-2">
|
||||
<button @click="openModalDealDoc" class="w-full h-full p-2 rounded flex flex-col items-center justify-center add-deal-doc-button">
|
||||
<img src="@/shared/assets/icons/plus-green.svg" alt="Добавить документ" class="w-6 h-6">
|
||||
@ -373,7 +379,6 @@
|
||||
|
||||
<h3>Составить договор</h3>
|
||||
<div class="flex w-full flex-wrap">
|
||||
<InnerDocAddModal v-if="showModalDealContract" :deal="deal" @close="closeModalDealContract" @created="handleNewInnerDoc" />
|
||||
<button @click="openModalDealContract" class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 p-2 rounded items-center justify-center order-last add-deal-contract-button">Составить договор</button>
|
||||
</div>
|
||||
<div class="flex w-full flex-wrap">
|
||||
@ -381,10 +386,6 @@
|
||||
v-for="innerDoc in deal.inner_docs"
|
||||
:key="innerDoc.id"
|
||||
:innerDoc="innerDoc"
|
||||
:deal-clients="{
|
||||
side_one_clients: deal.side_one_clients,
|
||||
side_two_clients: deal.side_two_clients
|
||||
}"
|
||||
@remove="removeInnerDoc"
|
||||
class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 p-2"
|
||||
/>
|
||||
@ -409,12 +410,11 @@
|
||||
|
||||
<script setup>
|
||||
import MyButton from "@/shared/UI/MyButton.vue";
|
||||
import {ref, onMounted, watch, inject} from "vue";
|
||||
import {ref, onMounted, watch, inject, toRaw, markRaw} from "vue";
|
||||
import { useLaravelApi } from '@/composables/useLaravelApi';
|
||||
import { useRouter } from "vue-router";
|
||||
//import useDeal from '@/composables/useDeal';
|
||||
import { useConfirm } from "primevue/useconfirm";
|
||||
import { useToast } from "primevue/usetoast";
|
||||
import { useDialog } from 'primevue/usedialog';
|
||||
import ConfirmDialog from 'primevue/confirmdialog';
|
||||
import Toast from "primevue/toast";
|
||||
import InputText from "primevue/inputtext";
|
||||
@ -444,11 +444,11 @@ const showError = (message) => {
|
||||
|
||||
const props = defineProps({
|
||||
dealId: Number,
|
||||
isOpen: Boolean,
|
||||
onCloseModel: Function,
|
||||
onDealAdded: Function
|
||||
isOpen: Boolean
|
||||
});
|
||||
|
||||
const dialog = useDialog();
|
||||
|
||||
const dialogRef = inject('dialogRef');
|
||||
const newDealReqId = dialogRef.value.data?.newDealReqId;
|
||||
|
||||
@ -649,7 +649,7 @@ async function loadDealData(dealId) {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки сделки:', error);
|
||||
showError(error.message);
|
||||
showError(String(error?.message ?? 'Неизвестная ошибка'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -692,7 +692,6 @@ function resetForm() {
|
||||
|
||||
const url = import.meta.env.VITE_API_URL;
|
||||
const urlLaravel = import.meta.env.VITE_LARAVEL_URL
|
||||
const titleForm = ref("Данные для сделки");
|
||||
const deal = ref({
|
||||
title: '',
|
||||
side_one: '',
|
||||
@ -805,6 +804,10 @@ const validateForm = () => {
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
console.log('[DealModal] dialogRef.data:', dialogRef.value.data)
|
||||
dealId = dialogRef.value.data?.deal_id
|
||||
|
||||
try {
|
||||
// Загрузка справочников
|
||||
const [objects, clients, employees, requisitions] = await Promise.all([
|
||||
@ -824,16 +827,12 @@ onMounted(async () => {
|
||||
})) || [];
|
||||
|
||||
requisitionsList.value = reqList;
|
||||
originalRequisitionsList.value = reqList; // Сохраняем полный список
|
||||
originalRequisitionsList.value = reqList;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки:', error);
|
||||
showError('Не удалось загрузить данные');
|
||||
}
|
||||
|
||||
// if (import.meta.env.MODE === 'development') {
|
||||
// loadRequisition(import.meta.env.VITE_DEV_REQUISITION_ID, 'sideOne');
|
||||
// }
|
||||
})
|
||||
|
||||
|
||||
@ -849,7 +848,7 @@ watch(selectedRequisitionSideOneId, async (newId) => {
|
||||
|
||||
// Добавляем who_work только при создании сделки
|
||||
if (newDealReqId.value && requisitionSideOneDetails.value.who_work) {
|
||||
addResponsibleEmployee(requisitionSideOneDetails.value.who_work);
|
||||
await addResponsibleEmployee(requisitionSideOneDetails.value.who_work);
|
||||
}
|
||||
|
||||
}
|
||||
@ -914,6 +913,7 @@ watch(selectedObjectSideOneId, async (newId) => {
|
||||
selectedObjectSideOne.value = null; // Очищаем, если newId === null
|
||||
}
|
||||
});
|
||||
|
||||
// Получение деталей выбранного объекта 2 стороны
|
||||
watch(selectedObjectSideTwoId, async (newId) => {
|
||||
if (newId) {
|
||||
@ -929,6 +929,7 @@ watch(selectedObjectSideTwoId, async (newId) => {
|
||||
|
||||
// Логика для управления модальным окном и выбранными сотрудниками
|
||||
const showModalDealManager = ref(false);
|
||||
|
||||
const selectedEmployees = ref([]);
|
||||
|
||||
const openModalDealManager = () => {
|
||||
@ -948,31 +949,53 @@ const removeEmployee = (employeeId) => {
|
||||
selectedEmployees.value = selectedEmployees.value.filter(e => e.id !== employeeId);
|
||||
};
|
||||
|
||||
|
||||
const showModalDealDoc = ref(false);
|
||||
const selectedDocs = ref([]);
|
||||
|
||||
// Открыть/закрыть модальное окно выбора документа
|
||||
const openModalDealDoc = () => {
|
||||
showModalDealDoc.value = true;
|
||||
};
|
||||
console.log('[openModalDealDoc] Открываем DocAddModal через DynamicDialog')
|
||||
|
||||
dialog.open(DocAddModal, {
|
||||
props: {
|
||||
header: 'Добавление документа',
|
||||
style: { width: '50vw' },
|
||||
modal: true
|
||||
},
|
||||
data: {
|
||||
deal: deal.value
|
||||
},
|
||||
onClose: (opt) => {
|
||||
console.log('[DynamicDialog] Закрыто с данными:', opt?.data)
|
||||
if (opt?.data) {
|
||||
console.log('opt', opt?.data)
|
||||
addDoc(opt.data);
|
||||
//selectedDocs.value.push(opt.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const closeModalDealDoc = () => {
|
||||
showModalDealDoc.value = false;
|
||||
};
|
||||
|
||||
const addDoc = (doc) => {
|
||||
console.log('[DealModal] addDoc вызван с:', doc);
|
||||
|
||||
// ✅ Проверка, что doc — объект и имеет id и name
|
||||
if (!doc || typeof doc !== 'object' || !doc.id || !doc.name) {
|
||||
console.error('[DealModal] addDoc: получен невалидный doc:', doc);
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем, что объект документа содержит обязательные поля
|
||||
if (doc && doc.id && doc.name && doc.file) {
|
||||
// Проверяем, что документ еще не добавлен
|
||||
const isDuplicate = selectedDocs.value.some((d) => d.id === doc.id);
|
||||
if (!isDuplicate) {
|
||||
selectedDocs.value.push(doc); // Добавляем документ в список
|
||||
console.log('[DealModal] Документ добавлен в selectedDocs');
|
||||
}
|
||||
} else {
|
||||
console.error('Документ не содержит обязательных полей:', doc);
|
||||
}
|
||||
closeModalDealDoc(); // Закрываем модальное окно
|
||||
//closeModalDealDoc(); // Закрываем модальное окно
|
||||
};
|
||||
|
||||
// Удалить документ
|
||||
@ -1015,6 +1038,98 @@ const handleCloseDealObject = (side) => {
|
||||
};
|
||||
|
||||
|
||||
const openModalDealContract = async () => {
|
||||
if (!deal.value.id) {
|
||||
console.log('[DealModal] Сделка не сохранена, сохраняем перед открытием модального окна договора.');
|
||||
try {
|
||||
let currentDeal = deal.value
|
||||
const savedDeal = await saveDeal();
|
||||
if (savedDeal?.id) {
|
||||
if (!savedDeal?.id) return
|
||||
deal.value = savedDeal
|
||||
currentDeal = savedDeal
|
||||
const plainDeal = JSON.parse(JSON.stringify(toRaw(currentDeal)))
|
||||
|
||||
console.log('[DealModal] Сделка успешно сохранена, ID:', deal.value);
|
||||
console.log('InnerDocAddModal:', InnerDocAddModal);
|
||||
dialog.open(InnerDocAddModal, {
|
||||
props: {
|
||||
header: 'Составить договор',
|
||||
modal: true,
|
||||
},
|
||||
data: {
|
||||
deal: plainDeal,
|
||||
},
|
||||
onClose: (options) => {
|
||||
console.log('InnerDocAddModal закрыт, options:', options)
|
||||
if (options?.data) {
|
||||
handleNewInnerDoc(options.data);
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.error('[DealModal] Сделка не была сохранена (id отсутствует после saveDeal)');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[DealModal] Ошибка при сохранении сделки перед составлением договора:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('[DealModal] Сделка уже сохранена (ID:', deal.value.id, '), открываем модальное окно.');
|
||||
dialog.open(InnerDocAddModal, {
|
||||
props: {
|
||||
header: 'Составить договор',
|
||||
modal: true,
|
||||
},
|
||||
data: {
|
||||
deal: deal.value,
|
||||
},
|
||||
onClose: (options) => {
|
||||
console.log('InnerDocAddModal закрыт, options:', options);
|
||||
if (options?.data) {
|
||||
handleNewInnerDoc(options.data);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Обработка нового договора
|
||||
const handleNewInnerDoc = (newInnerDoc) => {
|
||||
console.log('Новый innerDoc получен:', newInnerDoc);
|
||||
|
||||
if (!newInnerDoc || typeof newInnerDoc !== 'object' || !newInnerDoc.id || !newInnerDoc.name) {
|
||||
console.error('[DealModal] handleNewInnerDoc: получен невалидный newInnerDoc:', newInnerDoc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deal.value.inner_docs) {
|
||||
console.warn('Массив inner_docs не существует в deal. Создаём новый массив.');
|
||||
deal.value.inner_docs = [];
|
||||
}
|
||||
|
||||
console.log('Добавляем новый договор в deal.inner_docs');
|
||||
deal.value.inner_docs.push(newInnerDoc);
|
||||
|
||||
console.log('Обновлённый список inner_docs:', deal.value.inner_docs);
|
||||
};
|
||||
|
||||
// Удаление документа
|
||||
const { fetchData: deleteData } = useLaravelApi();
|
||||
|
||||
const removeInnerDoc = async (docId) => {
|
||||
console.log('[DealModal] deleteInnerDoc:', docId);
|
||||
try {
|
||||
await deleteData(`/inner-docs/${docId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
// Удаляем документ из локального состояния
|
||||
deal.value.inner_docs = deal.value.inner_docs.filter(doc => doc.id !== docId);
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении документа:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Сохранение сделки
|
||||
const saveDeal = async () => {
|
||||
|
||||
@ -1026,7 +1141,7 @@ const saveDeal = async () => {
|
||||
detail: 'Заполните все обязательные поля',
|
||||
life: 3000,
|
||||
});
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
const { fetchData } = useLaravelApi();
|
||||
@ -1060,14 +1175,16 @@ const saveDeal = async () => {
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Успех',
|
||||
detail: isEditing.value ? 'Сделка успешно обновлена' : 'Сделка успешно создана',
|
||||
detail: String(response.data.message || (isEditing.value ? 'Сделка успешно обновлена' : 'Сделка успешно создана')),
|
||||
life: 3000,
|
||||
});
|
||||
|
||||
// Вызываем onDealAdded при успешном сохранении
|
||||
if (props.onDealAdded) {
|
||||
props.onDealAdded();
|
||||
}
|
||||
// Обновляем локальное состояние сделки
|
||||
// if (response.data.deal) {
|
||||
// deal.value = response.data.deal;
|
||||
// }
|
||||
console.log('cat', response.data)
|
||||
return response.data.deal;
|
||||
|
||||
} else {
|
||||
new Error(response.data.message || 'Ошибка при сохранении сделки');
|
||||
@ -1076,53 +1193,10 @@ const saveDeal = async () => {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Ошибка',
|
||||
detail: error.message,
|
||||
detail: String(error?.message ?? 'Неизвестная ошибка'),
|
||||
life: 3000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showModalDealContract = ref(false);
|
||||
|
||||
// Открыть/закрыть модальное окно составления договора
|
||||
const openModalDealContract = () => {
|
||||
showModalDealContract.value = true;
|
||||
};
|
||||
|
||||
const closeModalDealContract = () => {
|
||||
showModalDealContract.value = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Обработка нового договора
|
||||
const handleNewInnerDoc = (newInnerDoc) => {
|
||||
console.log('Новый innerDoc получен:', newInnerDoc);
|
||||
|
||||
if (!deal.value.inner_docs) {
|
||||
console.warn('Массив inner_docs не существует в deal. Создаём новый массив.');
|
||||
deal.value.inner_docs = [];
|
||||
}
|
||||
|
||||
console.log('Добавляем новый договор в deal.inner_docs');
|
||||
deal.value.inner_docs.push(newInnerDoc);
|
||||
|
||||
console.log('Обновлённый список inner_docs:', deal.value.inner_docs);
|
||||
};
|
||||
|
||||
// Удаление документа
|
||||
const { fetchData: deleteData } = useLaravelApi();
|
||||
|
||||
const removeInnerDoc = async (docId) => {
|
||||
try {
|
||||
await deleteData(`/inner-docs/${docId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
// Удаляем документ из локального состояния
|
||||
deal.value.inner_docs = deal.value.inner_docs.filter(doc => doc.id !== docId);
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении документа:', error);
|
||||
throw error;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1135,14 +1209,6 @@ watch(() => props.isOpen, (newVal) => {
|
||||
isOpen.value = newVal;
|
||||
});
|
||||
|
||||
// Обработчик закрытия
|
||||
// function closeModel() {
|
||||
// isOpen.value = false;
|
||||
// if (props.onCloseModel) {
|
||||
// props.onCloseModel(); // Это уже есть в вашем коде
|
||||
// }
|
||||
// }
|
||||
|
||||
const emit = defineEmits(['close', 'added']);
|
||||
const closeModel = () => {
|
||||
emit('close');
|
||||
@ -1179,17 +1245,6 @@ async function addResponsibleEmployee(userId) {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Старые
|
||||
//const fieldsStore = useFieldsStore();
|
||||
const confirm = useConfirm();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
defineExpose({ closeModel });
|
||||
</script>
|
||||
|
||||
@ -1248,13 +1303,14 @@ defineExpose({ closeModel });
|
||||
|
||||
/* Убираем стрелочки вверх/вниз для Firefox */
|
||||
input[type="number"] {
|
||||
appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
display: inline-block;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="modal dealAddDoc">
|
||||
<div class="dealAddDoc">
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeModal">×</span>
|
||||
<h3 class="mb-4">Добавление документа</h3>
|
||||
<!-- <span class="close" @click="closeModal">×</span>-->
|
||||
<!-- <h3 class="mb-4">Добавление документа</h3>-->
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="document-name" class="block text-sm font-medium text-gray-700">Название документа</label>
|
||||
@ -35,19 +35,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import {inject, ref} from 'vue';
|
||||
//import { useLaravelApi } from '@/composables/useLaravelApi';
|
||||
import { dealsApi } from '@/shared/api/deals';
|
||||
import InputText from "primevue/inputtext";
|
||||
|
||||
const props = defineProps({
|
||||
deal: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
});
|
||||
// const props = defineProps({
|
||||
// deal: {
|
||||
// type: Object,
|
||||
// required: true
|
||||
// },
|
||||
// });
|
||||
|
||||
const emit = defineEmits(['close', 'select']);
|
||||
const dialogRef = inject('dialogRef');
|
||||
const props = dialogRef.value.data;
|
||||
|
||||
//const emit = defineEmits(['close', 'select']);
|
||||
|
||||
// Реактивные переменные для названия и файла
|
||||
const documentName = ref('');
|
||||
@ -59,7 +62,7 @@ const handleFileChange = (event) => {
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
emit('close');
|
||||
//emit('close');
|
||||
};
|
||||
|
||||
// Сохранение документа
|
||||
@ -83,8 +86,9 @@ const saveDealDoc = async () => {
|
||||
|
||||
try {
|
||||
const response = await dealsApi.uploadDocument(formData);
|
||||
emit('select', response.data.data);
|
||||
closeModal();
|
||||
//emit('select', response.data.data);
|
||||
dialogRef.value.close(response.data.data)
|
||||
//closeModal();
|
||||
} catch (error) {
|
||||
console.error('Ошибка при загрузке документа:', error);
|
||||
alert('Произошла ошибка при загрузке документа');
|
||||
|
||||
@ -13,33 +13,32 @@
|
||||
|
||||
<!-- Название документа -->
|
||||
<div class="ml-4 flex flex-col justify-between flex-grow">
|
||||
<div class="font-bold text-gray-800">{{ doc.name }}</div>
|
||||
<div class="font-bold text-gray-800">{{ doc.name || 'N/A' }}</div>
|
||||
<div class="flex">
|
||||
<img src="@/shared/assets/icons/doc.svg" alt="Договор" class="w-5 h-5">
|
||||
<a :href="fileUrl" target="_blank" class="ml-2 underline document-file">{{ getFileName(doc.file) }}</a>
|
||||
<a :href="fileUrl" target="_blank" class="ml-2 underline document-file">{{ getFileName(doc.file) || 'N/A' }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button @click="confirmDelete" class="ml-auto mt-2 px-4 py-2 rounded">
|
||||
<!-- <img src="@/shared/assets/icons/trash.svg" alt="Удалить" class="w-6 h-6">-->
|
||||
<span class="simple-button delete" title="Удалить"><i class="jw-action-icon-delete"></i></span>
|
||||
</button>
|
||||
<!-- <button @click="confirmDelete" class="ml-auto mt-2 px-4 py-2 rounded">-->
|
||||
<!--<!– <img src="@/shared/assets/icons/trash.svg" alt="Удалить" class="w-6 h-6">–>-->
|
||||
<!-- <span class="simple-button delete" title="Удалить"><i class="jw-action-icon-delete"></i></span>-->
|
||||
<!-- </button>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { computed } from "vue";
|
||||
|
||||
// import { useConfirm } from 'primevue/useconfirm';
|
||||
// import { useToast } from 'primevue/usetoast';
|
||||
import { computed } from "vue";
|
||||
import defaultIconUrl from '@/shared/assets/images/deal/deal-doc-icon.png';
|
||||
|
||||
const props = defineProps({
|
||||
doc: {
|
||||
type: Object,
|
||||
required: true,
|
||||
required: false,
|
||||
validator: (doc) => doc.id && doc.name && doc.file
|
||||
},
|
||||
urlLaravel: {
|
||||
@ -53,67 +52,64 @@ const fileUrl = computed(() => {
|
||||
return `${props.urlLaravel}/storage/${props.doc.file}`;
|
||||
});
|
||||
|
||||
// Проверка, является ли файл изображением
|
||||
// // Проверка, является ли файл изображением
|
||||
const isImage = computed(() => {
|
||||
if (!props.doc.file) return false;
|
||||
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
return imageExtensions.includes(fileExtension.value);
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Расширение файла
|
||||
// // Расширение файла
|
||||
const fileExtension = computed(() => {
|
||||
if (!props.doc.file) return false;
|
||||
return props.doc.file.split('.').pop().toLowerCase();
|
||||
});
|
||||
|
||||
const getFileName = (fullPath) => {
|
||||
return fullPath.split('/').pop();
|
||||
}
|
||||
|
||||
|
||||
const emit = defineEmits(['remove']);
|
||||
|
||||
const confirm = useConfirm();
|
||||
const toast = useToast();
|
||||
|
||||
const confirmDelete = (event) => {
|
||||
confirm.require({
|
||||
target: event.currentTarget,
|
||||
message: `Удалить документ "${props.doc.name}"?`,
|
||||
header: 'Подтверждение удаления',
|
||||
acceptLabel: 'Удалить',
|
||||
rejectLabel: 'Отмена',
|
||||
acceptClass: 'p-button-danger',
|
||||
accept: async () => {
|
||||
try {
|
||||
emit('remove', props.doc.id);
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Успешно',
|
||||
detail: 'Документ удален',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Ошибка',
|
||||
detail: 'Не удалось удалить документ',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
},
|
||||
reject: () => {
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Отменено',
|
||||
detail: 'Удаление отменено',
|
||||
life: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
//
|
||||
//
|
||||
// const emit = defineEmits(['remove']);
|
||||
//
|
||||
// const confirm = useConfirm();
|
||||
// const toast = useToast();
|
||||
//
|
||||
// const confirmDelete = (event) => {
|
||||
// confirm.require({
|
||||
// target: event.currentTarget,
|
||||
// message: `Удалить документ "${props.doc.name}"?`,
|
||||
// header: 'Подтверждение удаления',
|
||||
// acceptLabel: 'Удалить',
|
||||
// rejectLabel: 'Отмена',
|
||||
// acceptClass: 'p-button-danger',
|
||||
// accept: async () => {
|
||||
// try {
|
||||
// emit('remove', props.doc.id);
|
||||
// toast.add({
|
||||
// severity: 'success',
|
||||
// summary: 'Успешно',
|
||||
// detail: 'Документ удален',
|
||||
// life: 3000
|
||||
// });
|
||||
// } catch (error) {
|
||||
// toast.add({
|
||||
// severity: 'error',
|
||||
// summary: 'Ошибка',
|
||||
// detail: 'Не удалось удалить документ',
|
||||
// life: 3000
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// reject: () => {
|
||||
// toast.add({
|
||||
// severity: 'info',
|
||||
// summary: 'Отменено',
|
||||
// detail: 'Удаление отменено',
|
||||
// life: 2000
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<div class="modal dealAddContract">
|
||||
<div v-if="deal && deal.id" class="dealAddContract">
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeModal">×</span>
|
||||
<h3>Составить договор</h3>
|
||||
|
||||
<div class="mb-4 mt-4 add-contract-title">
|
||||
<label class="mb-2">Бланк документа:</label>
|
||||
<Dropdown
|
||||
<Select
|
||||
v-model="selectedInnerBlankId"
|
||||
:options="innerBlanksList"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
class="w-full"
|
||||
:key="innerBlanksList.length"
|
||||
>
|
||||
<template #dropdownicon>
|
||||
<DropdownIcon />
|
||||
</template>
|
||||
</Dropdown>
|
||||
<!-- <template #dropdownicon>-->
|
||||
<!-- <DropdownIcon />-->
|
||||
<!-- </template>-->
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 add-contract-title">
|
||||
@ -41,19 +41,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {defineEmits, onMounted, ref} from 'vue';
|
||||
import {inject, onMounted, ref} from 'vue';
|
||||
import { useLaravelApi } from '@/composables/useLaravelApi';
|
||||
import DropdownIcon from "@/shared/assets/icons/dropdown-icon.vue";
|
||||
//import DropdownIcon from "@/shared/assets/icons/dropdown-icon.vue";
|
||||
import Textarea from "primevue/textarea";
|
||||
import Select from 'primevue/select';
|
||||
|
||||
const props = defineProps({
|
||||
deal: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close', 'select']);
|
||||
const dialogRef = inject('dialogRef');
|
||||
const deal = dialogRef.value?.data?.deal || {}
|
||||
|
||||
// Состояния формы
|
||||
const selectedInnerBlankId = ref(null);
|
||||
@ -65,23 +60,30 @@ const validationErrors = ref({});
|
||||
const { data: innerBlanksData, error: innerBlanksError, fetchData: fetchInnerBlanksData } = useLaravelApi();
|
||||
const innerBlanksList = ref([]);
|
||||
|
||||
console.log('[InnerDocAddModal] refs и useLaravelApi созданы');
|
||||
|
||||
onMounted(async () => {
|
||||
console.log(props.deal);
|
||||
// Загружаем список бланков
|
||||
// Загружаем список бланков
|
||||
try {
|
||||
await fetchInnerBlanksData('/inner-blanks');
|
||||
if (innerBlanksData.value && innerBlanksData.value.success) {
|
||||
innerBlanksList.value = innerBlanksData.value.data; // Сохраняем данные
|
||||
innerBlanksList.value = innerBlanksData.value.data;
|
||||
console.log('[InnerDocAddModal] Inner blanks list установлен:', innerBlanksList.value);
|
||||
} else {
|
||||
console.error('Ошибка при загрузке списка бланков:', innerBlanksError.value);
|
||||
console.error('[InnerDocAddModal] Ошибка при загрузке списка бланков:', innerBlanksError.value);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[InnerDocAddModal] Исключение при загрузке бланков:', err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const closeModal = () => {
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const getTemplateData = () => {
|
||||
|
||||
if (!deal) {
|
||||
console.warn('deal is undefined in getTemplateData');
|
||||
return { sobstv: [], clients: [], object_id: null };
|
||||
}
|
||||
|
||||
const sidesMap = {
|
||||
'Продавец': 'sobstv',
|
||||
'Арендодатель': 'sobstv',
|
||||
@ -98,41 +100,41 @@ const getTemplateData = () => {
|
||||
};
|
||||
|
||||
// Обработка стороны 1
|
||||
if (props.deal.side_one) {
|
||||
const roleType = sidesMap[props.deal.side_one];
|
||||
if (deal.side_one) {
|
||||
const roleType = sidesMap[deal.side_one];
|
||||
if (roleType) {
|
||||
// Основной клиент
|
||||
if (props.deal.side_one_client_main) {
|
||||
result[roleType].push(props.deal.side_one_client_main.id);
|
||||
if (deal.side_one_client_main) {
|
||||
result[roleType].push(deal.side_one_client_main.id);
|
||||
}
|
||||
// Дополнительные клиенты
|
||||
if (props.deal.side_one_clients?.length) {
|
||||
result[roleType].push(...props.deal.side_one_clients.map(c => c.id));
|
||||
if (deal.side_one_clients?.length) {
|
||||
result[roleType].push(...deal.side_one_clients.map(c => c.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка стороны 2
|
||||
if (props.deal.side_two) {
|
||||
const roleType = sidesMap[props.deal.side_two];
|
||||
if (deal.side_two) {
|
||||
const roleType = sidesMap[deal.side_two];
|
||||
if (roleType) {
|
||||
// Основной клиент
|
||||
if (props.deal.side_two_client_main) {
|
||||
result[roleType].push(props.deal.side_two_client_main.id);
|
||||
if (deal.side_two_client_main) {
|
||||
result[roleType].push(deal.side_two_client_main.id);
|
||||
}
|
||||
// Дополнительные клиенты
|
||||
if (props.deal.side_two_clients?.length) {
|
||||
result[roleType].push(...props.deal.side_two_clients.map(c => c.id));
|
||||
if (deal.side_two_clients?.length) {
|
||||
result[roleType].push(...deal.side_two_clients.map(c => c.id));
|
||||
}
|
||||
//result[roleType].push(...props.deal.side_two_clients.map(c => c.id));
|
||||
//result[roleType].push(...deal.side_two_clients.map(c => c.id));
|
||||
}
|
||||
}
|
||||
|
||||
// Объект может быть только один — либо из side_one, либо из side_two
|
||||
if (props.deal.side_one_object_id) {
|
||||
result.object_id = props.deal.side_one_object_id;
|
||||
} else if (props.deal.side_two_object_id) {
|
||||
result.object_id = props.deal.side_two_object_id;
|
||||
if (deal.side_one_object_id) {
|
||||
result.object_id = deal.side_one_object_id;
|
||||
} else if (deal.side_two_object_id) {
|
||||
result.object_id = deal.side_two_object_id;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -145,9 +147,7 @@ const saveDealInnerDoc = async () => {
|
||||
try {
|
||||
const { fetchData } = useLaravelApi();
|
||||
|
||||
console.log('Props перед payload:', props);
|
||||
|
||||
const dealId = props.deal.id ? Number(props.deal.id) : null;
|
||||
const dealId = deal.id ? Number(deal.id) : null;
|
||||
|
||||
const templateData = getTemplateData();
|
||||
|
||||
@ -155,32 +155,32 @@ const saveDealInnerDoc = async () => {
|
||||
template_data: {
|
||||
...templateData,
|
||||
blank_id: selectedInnerBlankId.value,
|
||||
side_one_requisition_id: props.deal.side_one_requisition_id,
|
||||
side_one_requisition_id: deal.side_one_requisition_id,
|
||||
},
|
||||
deal_id: dealId,
|
||||
comment: commentDealInnerBlank.value || '',
|
||||
side_one: [
|
||||
// Основной клиент стороны 1
|
||||
(props.deal.side_one_client_main ? {
|
||||
client_id: props.deal.side_one_client_main.id,
|
||||
role: props.deal.side_one
|
||||
(deal.side_one_client_main ? {
|
||||
client_id: deal.side_one_client_main.id,
|
||||
role: deal.side_one
|
||||
} : null),
|
||||
// Дополнительные клиенты стороны 1
|
||||
...(props.deal.side_one_clients?.map(client => ({
|
||||
...(deal.side_one_clients?.map(client => ({
|
||||
client_id: client.id,
|
||||
role: props.deal.side_one
|
||||
role: deal.side_one
|
||||
})) || [])
|
||||
].filter(Boolean), // Убираем null, если основного клиента нет
|
||||
side_two: [
|
||||
// Основной клиент стороны 2
|
||||
(props.deal.side_two_client_main ? {
|
||||
client_id: props.deal.side_two_client_main.id,
|
||||
role: props.deal.side_two
|
||||
(deal.side_two_client_main ? {
|
||||
client_id: deal.side_two_client_main.id,
|
||||
role: deal.side_two
|
||||
} : null),
|
||||
// Дополнительные клиенты стороны 2
|
||||
...(props.deal.side_two_clients?.map(client => ({
|
||||
...(deal.side_two_clients?.map(client => ({
|
||||
client_id: client.id,
|
||||
role: props.deal.side_two
|
||||
role: deal.side_two
|
||||
})) || [])
|
||||
].filter(Boolean), // Убираем null, если основного клиента нет
|
||||
};
|
||||
@ -193,8 +193,12 @@ const saveDealInnerDoc = async () => {
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
emit('created', response.data.data);
|
||||
closeModal();
|
||||
console.log('[InnerDocAddModal] Doc сохранен:', response.data.data);
|
||||
|
||||
console.log('dialogRef.value:', dialogRef.value);
|
||||
dialogRef.value.close(response.data.data);
|
||||
|
||||
//closeDialog(response.data.data);
|
||||
} else {
|
||||
// Обработка ошибок валидации
|
||||
if (response.data.errors) {
|
||||
@ -215,31 +219,31 @@ const saveDealInnerDoc = async () => {
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
}
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<!--<style>-->
|
||||
<!--.modal {-->
|
||||
<!-- display: flex;-->
|
||||
<!-- justify-content: center;-->
|
||||
<!-- align-items: center;-->
|
||||
<!-- position: fixed;-->
|
||||
<!-- z-index: 1;-->
|
||||
<!-- left: 0;-->
|
||||
<!-- top: 0;-->
|
||||
<!-- width: 100%;-->
|
||||
<!-- height: 100%;-->
|
||||
<!-- background-color: rgba(0, 0, 0, 0.5);-->
|
||||
<!--}-->
|
||||
<!--.modal-content {-->
|
||||
<!-- background-color: #fff;-->
|
||||
<!-- padding: 20px;-->
|
||||
<!-- border-radius: 10px;-->
|
||||
<!-- width: 80%;-->
|
||||
<!-- max-width: 500px;-->
|
||||
<!--}-->
|
||||
<!--.close {-->
|
||||
<!-- position: absolute;-->
|
||||
<!-- top: 10px;-->
|
||||
<!-- right: 20px;-->
|
||||
<!-- font-size: 24px;-->
|
||||
<!-- cursor: pointer;-->
|
||||
<!--}-->
|
||||
<!--</style>-->
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<!-- Сторона 1 -->
|
||||
<div class="clients-inner-doc mt-4">
|
||||
<h4 class="inner-doc-title">Сторона 1:</h4>
|
||||
<div v-for="side in innerDoc.deals[0]?.side_one || []" :key="side.client_id" class="mt-2 flex items-baseline">
|
||||
<div v-for="side in currentDeal[0]?.side_one || []" :key="side.client_id" class="mt-2 flex items-baseline">
|
||||
<span style="margin-right: 10px;" class="font-medium min-w-[80px]">{{ side.role }}:</span>
|
||||
<div class="ml-2 underline">
|
||||
<span>{{ getClientName(side) }} ({{ side.phone }})</span>
|
||||
@ -21,7 +21,7 @@
|
||||
<!-- Сторона 2 -->
|
||||
<div class="clients-inner-doc mt-4">
|
||||
<h4 class="inner-doc-title">Сторона 2:</h4>
|
||||
<div v-for="side in innerDoc.deals[0]?.side_two || []" :key="side.client_id" class="mt-2 flex items-baseline">
|
||||
<div v-for="side in currentDeal[0]?.side_two || []" :key="side.client_id" class="mt-2 flex items-baseline">
|
||||
<span style="margin-right: 10px;" class="font-medium min-w-[80px]">{{ side.role }}:</span>
|
||||
<div class="ml-2 underline">
|
||||
<span>{{ getClientName(side) }} ({{ side.phone }})</span>
|
||||
@ -74,10 +74,12 @@
|
||||
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
|
||||
console.log('Запуск InnerDocCard');
|
||||
|
||||
const props = defineProps({
|
||||
innerDoc: {
|
||||
type: Object,
|
||||
@ -94,6 +96,10 @@ const emit = defineEmits(['remove']);
|
||||
const confirm = useConfirm();
|
||||
const toast = useToast();
|
||||
|
||||
const currentDeal = computed(() => {
|
||||
return props.innerDoc.deals?.[0];
|
||||
});
|
||||
|
||||
// Получаем pivot данные для текущего документа
|
||||
const currentPivot = computed(() => {
|
||||
return props.innerDoc.deals?.[0]?.pivot;
|
||||
@ -105,7 +111,7 @@ const getClientName = (client) => {
|
||||
};
|
||||
|
||||
const handleEditInnerDoc = () => {
|
||||
emit('edit', props.innerDoc); // Немедленно передаем документ на редактирование
|
||||
emit('edit', props.innerDoc);
|
||||
};
|
||||
|
||||
const handleRemoveDealDoc = (event) => {
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
fetchDeal,
|
||||
createDeal,
|
||||
uploadDealDocument
|
||||
createDeal
|
||||
} from '@/shared/api/deals';
|
||||
|
||||
export default function useDeal() {
|
||||
|
||||
@ -42,14 +42,14 @@ const fetchData = (endpoint, options = {}) => {
|
||||
|
||||
// Извлекаем путь из endpoint
|
||||
const path = endpoint.replace(/^\//, '');
|
||||
|
||||
console.log('[laravelApiService] fetchData вызван с endpoint:', endpoint);
|
||||
console.log('[laravelApiService] Тип data:', data && data.constructor.name);
|
||||
console.log('[laravelApiService] data instanceof FormData:', data instanceof FormData);
|
||||
//
|
||||
// console.log('[laravelApiService] fetchData вызван с endpoint:', endpoint);
|
||||
// console.log('[laravelApiService] Тип data:', data && data.constructor.name);
|
||||
// console.log('[laravelApiService] data instanceof FormData:', data instanceof FormData);
|
||||
|
||||
const isFormData = data instanceof FormData;
|
||||
if (isFormData) {
|
||||
console.log('[laravelApiService] Используем directAxiosInstance для FormData');
|
||||
//console.log('[laravelApiService] Используем directAxiosInstance для FormData');
|
||||
|
||||
const laravelApiUrl = 'http://llar.joyworkdev.ru/api';
|
||||
|
||||
@ -64,7 +64,7 @@ const fetchData = (endpoint, options = {}) => {
|
||||
finalHeaders['X-Session-ID'] = sessionId;
|
||||
}
|
||||
|
||||
logMessage("Sending FormData directly to Laravel API: " + laravelApiUrl + endpoint);
|
||||
//logMessage("Sending FormData directly to Laravel API: " + laravelApiUrl + endpoint);
|
||||
return directAxiosInstance({
|
||||
url: endpoint,
|
||||
method,
|
||||
@ -74,8 +74,6 @@ const fetchData = (endpoint, options = {}) => {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[laravelApiService] Используем laravel_api_instance через deal/index.php');
|
||||
|
||||
const finalHeaders = { ...headers };
|
||||
if (sessionId) {
|
||||
finalHeaders['X-Session-ID'] = sessionId;
|
||||
@ -94,10 +92,6 @@ const fetchData = (endpoint, options = {}) => {
|
||||
});
|
||||
};
|
||||
|
||||
function logMessage(message) {
|
||||
console.log('[laravelApiService]', message);
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchData,
|
||||
};
|
||||
@ -3,7 +3,6 @@
|
||||
fill="#4CAF50"
|
||||
height="24px"
|
||||
width="24px"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
|
||||
@ -4,12 +4,11 @@
|
||||
width="20px"
|
||||
height="20px"
|
||||
viewBox="0 0 20 20"
|
||||
version="1.1"
|
||||
>
|
||||
<g id="layer1">
|
||||
<path
|
||||
d="M 4 4.2910156 L 3.2910156 5 L 3.6464844 5.3535156 L 10 11.708984 L 16.353516 5.3535156 L 16.708984 5 L 16 4.2910156 L 15.646484 4.6464844 L 10 10.291016 L 4.3535156 4.6464844 L 4 4.2910156 z M 4 8.2910156 L 3.2910156 9 L 3.6464844 9.3535156 L 10 15.708984 L 16.353516 9.3535156 L 16.708984 9 L 16 8.2910156 L 15.646484 8.6464844 L 10 14.291016 L 4.3535156 8.6464844 L 4 8.2910156 z "
|
||||
style="fill: #757575; fill-opacity: 1; stroke: none; stroke-width: 0px"
|
||||
style="fill: #757575; fill-opacity: 1; stroke: none; stroke-width: 0"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user