fix CRM contacts
This commit is contained in:
@@ -5,7 +5,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
const body = document.body;
|
||||
|
||||
// Базовая функция для получения base URL (объявляем ДО использования)
|
||||
const baseUrl = '{{ base_url("/") }}'.replace(/\/+$/, '');
|
||||
const baseUrl = '/'.replace(/\/+$/, '');
|
||||
|
||||
if (sidebarToggle) {
|
||||
// Обработчик клика
|
||||
|
||||
@@ -24,6 +24,16 @@ class ContactsManager {
|
||||
this.loadContacts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить заголовки запроса
|
||||
*/
|
||||
getHeaders() {
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Загрузить список контактов
|
||||
*/
|
||||
@@ -31,9 +41,8 @@ class ContactsManager {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/list/${this.clientId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
|
||||
@@ -106,6 +115,7 @@ class ContactsManager {
|
||||
* Отобразить одну строку контакта
|
||||
*/
|
||||
renderRow(contact) {
|
||||
const escapedId = this.escapeJs(contact.id);
|
||||
return `
|
||||
<tr data-id="${contact.id}" class="contact-row">
|
||||
<td>
|
||||
@@ -129,29 +139,27 @@ class ContactsManager {
|
||||
value="${this.escapeHtml(contact.position || '')}" style="display: none;" placeholder="Должность">
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="contact-actions">
|
||||
<div class="btn-group contact-actions">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
onclick="contactsManager.edit(${contact.id})" title="Редактировать">
|
||||
onclick="contactsManager.edit('${escapedId}')" title="Редактировать">
|
||||
<i class="fa-solid fa-pen"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm"
|
||||
onclick="contactsManager.remove(${contact.id})" title="Удалить">
|
||||
onclick="contactsManager.remove('${escapedId}')" title="Удалить">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="edit-actions" style="display: none;">
|
||||
<div class="btn-group edit-actions" style="display: none;">
|
||||
<button type="button" class="btn btn-outline-success btn-sm"
|
||||
onclick="contactsManager.save(${contact.id})" title="Сохранить">
|
||||
onclick="contactsManager.save('${escapedId}')" title="Сохранить">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm"
|
||||
onclick="contactsManager.cancel(${contact.id})" title="Отмена">
|
||||
onclick="contactsManager.cancel('${escapedId}')" title="Отмена">
|
||||
<i class="fa-solid fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
</td>`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,18 +233,16 @@ class ContactsManager {
|
||||
// Создание нового
|
||||
response = await fetch(`${this.apiUrl}/store`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
} else {
|
||||
// Обновление существующего
|
||||
response = await fetch(`${this.apiUrl}/update/${contactId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
@@ -245,13 +251,15 @@ class ContactsManager {
|
||||
|
||||
if (result.success) {
|
||||
// Обновляем локальный массив
|
||||
const index = this.contacts.findIndex(c => c.id === contactId);
|
||||
// contactId может быть строкой из data-id, а c.id - числом из БД
|
||||
const contactIdStr = String(contactId);
|
||||
const index = this.contacts.findIndex(c => String(c.id) === contactIdStr);
|
||||
if (index !== -1) {
|
||||
if (result.item) {
|
||||
// Обновляем с реальным ID от сервера
|
||||
this.contacts[index] = { ...data, id: result.item.id };
|
||||
} else {
|
||||
this.contacts[index] = data;
|
||||
this.contacts[index] = { ...data, id: contactId };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,9 +278,10 @@ class ContactsManager {
|
||||
* Отменить редактирование
|
||||
*/
|
||||
cancel(contactId) {
|
||||
if (contactId.toString().startsWith('new_')) {
|
||||
const contactIdStr = String(contactId);
|
||||
if (contactIdStr.startsWith('new_')) {
|
||||
// Удаляем новую строку
|
||||
this.contacts = this.contacts.filter(c => c.id !== contactId);
|
||||
this.contacts = this.contacts.filter(c => String(c.id) !== contactIdStr);
|
||||
this.render();
|
||||
} else {
|
||||
// Перезагружаем данные
|
||||
@@ -291,16 +300,17 @@ class ContactsManager {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/delete/${contactId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.contacts = this.contacts.filter(c => c.id !== contactId);
|
||||
// contactId может быть строкой, а c.id - числом
|
||||
const contactIdStr = String(contactId);
|
||||
this.contacts = this.contacts.filter(c => String(c.id) !== contactIdStr);
|
||||
this.render();
|
||||
this.showSuccess(result.message || 'Контакт удалён');
|
||||
} else {
|
||||
@@ -361,6 +371,23 @@ class ContactsManager {
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Экранирование для JavaScript строки
|
||||
*/
|
||||
escapeJs(text) {
|
||||
if (!text) return '';
|
||||
// Приводим к строке, так как id может быть числом
|
||||
const str = String(text);
|
||||
return str
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/'/g, "\\'")
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/</g, '\\x3c')
|
||||
.replace(/>/g, '\\x3e');
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация при загрузке страницы
|
||||
|
||||
Reference in New Issue
Block a user