release 1.1
This commit is contained in:
+77
-3
@@ -36,7 +36,7 @@ const statuses = {
|
|||||||
category: "error"
|
category: "error"
|
||||||
},
|
},
|
||||||
207: {
|
207: {
|
||||||
name: "Ожидание действий всех получателей",
|
name: "Ожидание действий",
|
||||||
description: "Ожидание действий от всех получателей",
|
description: "Ожидание действий от всех получателей",
|
||||||
category: "processing"
|
category: "processing"
|
||||||
},
|
},
|
||||||
@@ -70,6 +70,11 @@ const statuses = {
|
|||||||
description: "Подписание отменено для всех получателей",
|
description: "Подписание отменено для всех получателей",
|
||||||
category: "completed"
|
category: "completed"
|
||||||
},
|
},
|
||||||
|
214: {
|
||||||
|
name: "Успешно. Требуется подписание УКЭП",
|
||||||
|
description: "Требуется подписание УКЭП медицинского работника",
|
||||||
|
category: "processing"
|
||||||
|
},
|
||||||
498: {
|
498: {
|
||||||
name: "Завершено. Отклонено всеми",
|
name: "Завершено. Отклонено всеми",
|
||||||
description: "Все получатели отказались от подписания",
|
description: "Все получатели отказались от подписания",
|
||||||
@@ -315,6 +320,23 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.action === 'searchRecipients') {
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
const result = await searchRecipients(message.data);
|
||||||
|
sendResponse(result);
|
||||||
|
} catch (error) {
|
||||||
|
sendResponse({
|
||||||
|
success: false,
|
||||||
|
message: error.message || 'Ошибка поиска получателей',
|
||||||
|
error: error.toString(),
|
||||||
|
data: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Функция расширенного поиска
|
// Функция расширенного поиска
|
||||||
@@ -442,8 +464,8 @@ async function getDocumentsFromServer(data) {
|
|||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.status === 'SUCCESS' && Array.isArray(result.data)) {
|
if (result.status === 'SUCCESS' && Array.isArray(result.data.singings)) {
|
||||||
result.data = enrichStatuses(result.data);
|
result.data.singings = enrichStatuses(result.data.singings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -616,4 +638,56 @@ async function resendDocumentsOnServer(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function searchRecipients(data) {
|
||||||
|
try {
|
||||||
|
const settings = await chrome.storage.local.get(['serverIp', 'serverPort']);
|
||||||
|
|
||||||
|
if (!settings.serverIp || !settings.serverPort) {
|
||||||
|
throw new Error('Server IP or port not configured');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `http://${settings.serverIp}:${settings.serverPort}/api/search-recipients`;
|
||||||
|
|
||||||
|
console.log('[background] Поиск получателей:', url, data);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
signal: AbortSignal.timeout(15000) // 15 секунд таймаут
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`HTTP error: ${response.status} - ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
let recipients = result;
|
||||||
|
if (result.data && Array.isArray(result.data)) {
|
||||||
|
recipients = result.data;
|
||||||
|
} else if (!Array.isArray(result)) {
|
||||||
|
recipients = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: recipients
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[background] Ошибка поиска получателей:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: error.message || 'Ошибка поиска получателей',
|
||||||
|
error: error.toString(),
|
||||||
|
data: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log('✅ Background script loaded');
|
console.log('✅ Background script loaded');
|
||||||
+30
-15
@@ -40,6 +40,8 @@ window.addEventListener('message', (event) => {
|
|||||||
|
|
||||||
async function loadPageData() {
|
async function loadPageData() {
|
||||||
storageData = await chrome.storage.local.get(dataType);
|
storageData = await chrome.storage.local.get(dataType);
|
||||||
|
const userData = await chrome.storage.local.get(userDataType);
|
||||||
|
storageData.userData = userData[userDataType];
|
||||||
|
|
||||||
if (!storageData || !storageData.metaData || Object.keys(storageData.metaData).length === 0) {
|
if (!storageData || !storageData.metaData || Object.keys(storageData.metaData).length === 0) {
|
||||||
console.log(`[EXT][content] no data for ${dataType}, injecting...`);
|
console.log(`[EXT][content] no data for ${dataType}, injecting...`);
|
||||||
@@ -101,8 +103,8 @@ window.addEventListener('message', async (event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Подготавливаем данные для отправки
|
// Подготавливаем данные для отправки
|
||||||
const userData = storageData.metaData.userData;
|
const userData = storageData.userData;
|
||||||
const patientId = storageData.metaData.patients?.[0]?.idPatientMis;
|
const patientId = storageData.metaData.patient.idPatientMis;
|
||||||
|
|
||||||
if (!userData || !patientId) {
|
if (!userData || !patientId) {
|
||||||
window.postMessage({
|
window.postMessage({
|
||||||
@@ -156,10 +158,6 @@ window.addEventListener('message', async (event) => {
|
|||||||
|
|
||||||
isProcessing = true;
|
isProcessing = true;
|
||||||
|
|
||||||
console.log('[EXT][content] Forwarding to background:', {
|
|
||||||
docNumbers: event.data.payload.docNumbers
|
|
||||||
});
|
|
||||||
|
|
||||||
// Немедленный ответ о принятии задачи
|
// Немедленный ответ о принятии задачи
|
||||||
window.postMessage({
|
window.postMessage({
|
||||||
source: 'medods-extension',
|
source: 'medods-extension',
|
||||||
@@ -178,8 +176,6 @@ window.addEventListener('message', async (event) => {
|
|||||||
event.data.payload.docNumbers.includes(parseInt(doc.number, 10))
|
event.data.payload.docNumbers.includes(parseInt(doc.number, 10))
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`📄 [Content] Найдено документов для отправки: ${filteredDocs.length}`);
|
|
||||||
|
|
||||||
if (filteredDocs.length === 0) {
|
if (filteredDocs.length === 0) {
|
||||||
window.postMessage({
|
window.postMessage({
|
||||||
source: 'medods-extension',
|
source: 'medods-extension',
|
||||||
@@ -198,8 +194,10 @@ window.addEventListener('message', async (event) => {
|
|||||||
// Собираем все данные для отправки
|
// Собираем все данные для отправки
|
||||||
const sendData = {
|
const sendData = {
|
||||||
practitioner: storageData.metaData.practitioner,
|
practitioner: storageData.metaData.practitioner,
|
||||||
patients: storageData.metaData.patients,
|
patient: storageData.metaData.patient,
|
||||||
|
recipients: event.data.payload.recipients,
|
||||||
docs: filteredDocs,
|
docs: filteredDocs,
|
||||||
|
deliveryType: event.data.payload.deliveryType
|
||||||
};
|
};
|
||||||
|
|
||||||
// Асинхронная обработка в background
|
// Асинхронная обработка в background
|
||||||
@@ -243,7 +241,7 @@ window.addEventListener('message', async (event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Получаем idPatientMis из метаданных
|
// Получаем idPatientMis из метаданных
|
||||||
const idPatientMis = storageData.metaData.patients?.[0]?.idPatientMis;
|
const idPatientMis = storageData.metaData.patient.idPatientMis;
|
||||||
|
|
||||||
if (!idPatientMis) {
|
if (!idPatientMis) {
|
||||||
window.postMessage({
|
window.postMessage({
|
||||||
@@ -289,7 +287,7 @@ window.addEventListener('message', async (event) => {
|
|||||||
|
|
||||||
// ОБРАБОТЧИК ПРОВЕРКИ ПРАВ НА ОТЗЫВ
|
// ОБРАБОТЧИК ПРОВЕРКИ ПРАВ НА ОТЗЫВ
|
||||||
if (event.data.type === 'checkRevokePermission') {
|
if (event.data.type === 'checkRevokePermission') {
|
||||||
const hasPermission = String(storageData.metaData?.userData?.id) === String(event.data.payload.userIdLpu);
|
const hasPermission = String(storageData.userData?.id) === String(event.data.payload.userIdLpu);
|
||||||
|
|
||||||
window.postMessage({
|
window.postMessage({
|
||||||
source: 'medods-extension',
|
source: 'medods-extension',
|
||||||
@@ -302,8 +300,6 @@ window.addEventListener('message', async (event) => {
|
|||||||
|
|
||||||
// ОБРАБОТЧИК ОТЗЫВА ДОКУМЕНТОВ
|
// ОБРАБОТЧИК ОТЗЫВА ДОКУМЕНТОВ
|
||||||
if (event.data.type === 'revokeDocuments') {
|
if (event.data.type === 'revokeDocuments') {
|
||||||
console.log('[EXT][content] Запрос на отзыв документов:', event.data.payload);
|
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
action: 'revokeDocuments',
|
action: 'revokeDocuments',
|
||||||
data: event.data.payload
|
data: event.data.payload
|
||||||
@@ -318,8 +314,6 @@ window.addEventListener('message', async (event) => {
|
|||||||
|
|
||||||
// ОБРАБОТЧИК ПОВТОРНОЙ ОТПРАВКИ ДОКУМЕНТОВ
|
// ОБРАБОТЧИК ПОВТОРНОЙ ОТПРАВКИ ДОКУМЕНТОВ
|
||||||
if (event.data.type === 'resendDocuments') {
|
if (event.data.type === 'resendDocuments') {
|
||||||
console.log('[EXT][content] Запрос на повторную отправку документов:', event.data.payload);
|
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
action: 'resendDocuments',
|
action: 'resendDocuments',
|
||||||
data: event.data.payload
|
data: event.data.payload
|
||||||
@@ -332,6 +326,27 @@ window.addEventListener('message', async (event) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ОБРАБОТЧИК ПОИСКА ПОЛУЧАТЕЛЕЙ ПО ТЕЛЕФОНУ
|
||||||
|
if (event.data.type === 'searchRecipients') {
|
||||||
|
const data = {
|
||||||
|
...event.data.payload,
|
||||||
|
idPatientMis: storageData.metaData.patient.idPatientMis
|
||||||
|
};
|
||||||
|
|
||||||
|
// Отправляем запрос в background
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: 'searchRecipients',
|
||||||
|
data: data
|
||||||
|
}, (response) => {
|
||||||
|
// Пересылаем результат обратно в singing.js
|
||||||
|
window.postMessage({
|
||||||
|
source: 'medods-extension',
|
||||||
|
type: 'searchRecipientsResponse',
|
||||||
|
payload: response
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Основной цикл
|
// Основной цикл
|
||||||
|
|||||||
+408
-200
@@ -4,6 +4,7 @@
|
|||||||
// Глобальная переменная для хранения текущего уведомления
|
// Глобальная переменная для хранения текущего уведомления
|
||||||
let currentMessageEl = null;
|
let currentMessageEl = null;
|
||||||
let messageTimeout = null;
|
let messageTimeout = null;
|
||||||
|
let deliveryTypeSettings = {};
|
||||||
|
|
||||||
// Функция для отображения сообщений
|
// Функция для отображения сообщений
|
||||||
function showMessage(message, type = 'success', duration = 3000) {
|
function showMessage(message, type = 'success', duration = 3000) {
|
||||||
@@ -136,45 +137,81 @@
|
|||||||
modalWrapper.className = 'el-dialog__wrapper';
|
modalWrapper.className = 'el-dialog__wrapper';
|
||||||
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
||||||
|
|
||||||
const backdrop = document.createElement('div');
|
// Разделяем статусы на общие и по получателям
|
||||||
backdrop.className = 'v-modal';
|
const commonStatuses = singing.statuses.filter(s => s.idPatientMis === null);
|
||||||
backdrop.style.cssText = 'z-index: 2001;';
|
const recipientStatuses = singing.statuses.filter(s => s.idPatientMis !== null);
|
||||||
backdrop.tabIndex = 0;
|
|
||||||
|
|
||||||
const sortedStatuses = [...singing.statuses].sort((a, b) => a.id - b.id);
|
// Группируем статусы по получателям
|
||||||
|
const statusesByRecipient = {};
|
||||||
|
recipientStatuses.forEach(status => {
|
||||||
|
if (status.patient) {
|
||||||
|
const patientName = status.patient.name || 'Неизвестный получатель';
|
||||||
|
if (!statusesByRecipient[patientName]) {
|
||||||
|
statusesByRecipient[patientName] = [];
|
||||||
|
}
|
||||||
|
statusesByRecipient[patientName].push(status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const statusesHtml = sortedStatuses.map(status => `
|
// Сортируем получателей по имени
|
||||||
<div class="status-history-item" style="padding: 12px; border-bottom: 1px solid #ebeef5; display: flex; align-items: center; gap: 12px;">
|
const sortedRecipients = Object.keys(statusesByRecipient).sort();
|
||||||
<i class="el-icon ${getStatusIcon(status.category)}" style="font-size: 16px; color: ${status.category === 'completed' ? '#67C23A' :
|
|
||||||
|
// Функция для генерации HTML статуса
|
||||||
|
const getStatusHtml = (status) => `
|
||||||
|
<div class="status-history-item" style="padding: 12px; border-bottom: 1px solid #ebeef5; display: flex; align-items: center; gap: 12px;">
|
||||||
|
<i class="el-icon ${getStatusIcon(status.category)}" style="font-size: 16px; color: ${status.category === 'completed' ? '#67C23A' :
|
||||||
status.category === 'processing' ? '#409EFF' :
|
status.category === 'processing' ? '#409EFF' :
|
||||||
status.category === 'error' ? '#F56C6C' : '#909399'
|
status.category === 'error' ? '#F56C6C' : '#909399'
|
||||||
}; width: 20px;"></i>
|
}; width: 20px;"></i>
|
||||||
<div style="flex: 1;">
|
<div style="flex: 1;">
|
||||||
<div style="font-weight: 500; color: #303133;">${status.description}</div>
|
<div style="font-weight: 500; color: #303133;">${status.description}</div>
|
||||||
<div style="font-size: 12px; color: #909399; margin-top: 4px;">${formatDate(status.created_at)}</div>
|
<div style="font-size: 12px; color: #909399; margin-top: 4px;">${formatDate(status.created_at)}</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Генерируем HTML для общих статусов
|
||||||
|
const commonStatusesHtml = commonStatuses
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map(getStatusHtml)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
// Генерируем HTML для статусов получателей
|
||||||
|
const recipientStatusesHtml = sortedRecipients.map(recipientName => {
|
||||||
|
const recipientStatuses = statusesByRecipient[recipientName]
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map(getStatusHtml)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div style="background: #F5F7FA; padding: 8px 12px; font-weight: 500; color: #303133; border-bottom: 1px solid #DCDFE6;">
|
||||||
|
<i class="el-icon el-icon-user" style="margin-right: 6px; color: #409EFF;"></i>
|
||||||
|
${recipientName}
|
||||||
|
</div>
|
||||||
|
${recipientStatuses}
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
modalWrapper.innerHTML = `
|
modalWrapper.innerHTML = `
|
||||||
<div class="el-dialog" style="width: 500px; margin-top: 15vh;">
|
<div class="el-dialog" style="width: 500px; margin-top: 15vh;">
|
||||||
<div class="el-dialog__header">
|
<div class="el-dialog__header">
|
||||||
<span class="el-dialog__title">История статусов</span>
|
<span class="el-dialog__title">История статусов</span>
|
||||||
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
||||||
<i class="el-dialog__close el-icon el-icon-close"></i>
|
<i class="el-dialog__close el-icon el-icon-close"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
<div class="el-dialog__body" style="max-height: 400px; overflow-y: auto; padding: 0;">
|
|
||||||
${statusesHtml}
|
|
||||||
</div>
|
|
||||||
<div class="el-dialog__footer" style="margin-top: 12px; width: 100%; text-align: right;">
|
|
||||||
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon close-btn">
|
|
||||||
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
|
||||||
<span>Закрыть</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
<div class="el-dialog__body" style="max-height: 400px; overflow-y: auto; padding: 0;">
|
||||||
|
${commonStatusesHtml}
|
||||||
|
${recipientStatusesHtml}
|
||||||
|
</div>
|
||||||
|
<div class="el-dialog__footer" style="margin-top: 12px; width: 100%; text-align: right;">
|
||||||
|
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon close-btn">
|
||||||
|
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
||||||
|
<span>Закрыть</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
document.body.appendChild(modalWrapper);
|
document.body.appendChild(modalWrapper);
|
||||||
|
|
||||||
@@ -196,80 +233,13 @@
|
|||||||
document.addEventListener('keydown', escHandler);
|
document.addEventListener('keydown', escHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция создания модального окна подтверждения отзыва
|
// Функция для получения имени получателя по ID
|
||||||
function createRevokeConfirmModal(singing) {
|
function getRecipientNameById(singing, idPatientMis) {
|
||||||
return new Promise((resolve) => {
|
const status = singing.statuses.find(s => s.idPatientMis === idPatientMis && s.patient);
|
||||||
const modalWrapper = document.createElement('div');
|
return status?.patient?.name || 'Неизвестный получатель';
|
||||||
modalWrapper.className = 'el-dialog__wrapper';
|
|
||||||
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
|
||||||
|
|
||||||
const backdrop = document.createElement('div');
|
|
||||||
backdrop.className = 'v-modal';
|
|
||||||
backdrop.style.cssText = 'z-index: 2001;';
|
|
||||||
backdrop.tabIndex = 0;
|
|
||||||
|
|
||||||
modalWrapper.innerHTML = `
|
|
||||||
<div class="el-dialog" style="width: 450px; margin-top: 25vh;">
|
|
||||||
<div class="el-dialog__header">
|
|
||||||
<span class="el-dialog__title">Подтверждение отзыва</span>
|
|
||||||
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
|
||||||
<i class="el-dialog__close el-icon el-icon-close"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="el-dialog__body" style="padding: 20px;">
|
|
||||||
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
|
||||||
<i class="el-icon el-icon-warning" style="font-size: 24px; color: #E6A23C;"></i>
|
|
||||||
<div>
|
|
||||||
<p style="margin: 0 0 10px 0; color: #606266;">Вы действительно хотите отозвать документы из подписания?</p>
|
|
||||||
<div style="background: #f8f8f8; padding: 10px; border-radius: 4px; font-size: 13px; color: #E6A23C; border-left: 3px solid #E6A23C;">
|
|
||||||
<i class="el-icon el-icon-document" style="margin-right: 6px;"></i>
|
|
||||||
<strong>Документы:</strong> ${singing.documents.map(d => `№${d.number} ${d.title}`).join(', ')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="el-dialog__footer" style="display: flex; justify-content: space-between; align-items: center;">
|
|
||||||
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon cancel-btn"
|
|
||||||
style="display: flex; align-items: center;">
|
|
||||||
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
|
||||||
<span>Отмена</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon confirm-btn" style="color: #F56C6C; border-color: #F56C6C; display: flex; align-items: center;">
|
|
||||||
<i class="m-icon fa-ban button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
|
||||||
<span>Отозвать</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
document.body.appendChild(modalWrapper);
|
|
||||||
|
|
||||||
const closeModal = () => {
|
|
||||||
modalWrapper.remove();
|
|
||||||
resolve(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
modalWrapper.querySelector('.el-dialog__headerbtn').addEventListener('click', closeModal);
|
|
||||||
modalWrapper.querySelector('.cancel-btn').addEventListener('click', closeModal);
|
|
||||||
modalWrapper.querySelector('.confirm-btn').addEventListener('click', () => {
|
|
||||||
modalWrapper.remove();
|
|
||||||
resolve(true);
|
|
||||||
});
|
|
||||||
modalWrapper.addEventListener('click', (e) => {
|
|
||||||
if (e.target === modalWrapper) closeModal();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Закрытие по ESC
|
|
||||||
const escHandler = (e) => {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
closeModal();
|
|
||||||
document.removeEventListener('keydown', escHandler);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('keydown', escHandler);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Функция отображения PDF
|
// Функция отображения PDF
|
||||||
async function viewDocument(documentPath, title) {
|
async function viewDocument(documentPath, title) {
|
||||||
try {
|
try {
|
||||||
@@ -364,6 +334,53 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Функция повторной отправки документов
|
||||||
|
async function resendDocuments(singing, modalToClose) {
|
||||||
|
try {
|
||||||
|
// Сразу закрываем окно со списком документов
|
||||||
|
if (modalToClose && modalToClose.parentNode) {
|
||||||
|
modalToClose.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем подтверждение с выбором получателей и способа отправки
|
||||||
|
const result = await createResendConfirmModal(singing);
|
||||||
|
if (!result.confirmed) return;
|
||||||
|
|
||||||
|
// Если получателей нет или не выбраны, показываем ошибку
|
||||||
|
if (result.recipients.length === 0) {
|
||||||
|
showMessage('Не выбраны получатели для повторной отправки', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если не выбран способ отправки, показываем ошибку
|
||||||
|
if (!result.deliveryType) {
|
||||||
|
showMessage('Не выбран способ отправки', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessage('Повторная отправка документов...', 'info');
|
||||||
|
|
||||||
|
// Отправляем запрос на повторную отправку с указанием получателей и способа отправки
|
||||||
|
const response = await sendMessageToContent('resendDocuments', {
|
||||||
|
trackingId: singing.trackingId,
|
||||||
|
idPatientMis: result.recipients,
|
||||||
|
deliveryType: result.deliveryType
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
showMessage('Документы успешно отправлены повторно', 'success');
|
||||||
|
console.log('Документы успешно отправлены повторно');
|
||||||
|
// Обновляем список документов
|
||||||
|
await prepareDocuments();
|
||||||
|
} else {
|
||||||
|
showMessage('Ошибка повторной отправки документов: ' + (response.message || 'Неизвестная ошибка'), 'error');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка повторной отправки документов:', error);
|
||||||
|
showMessage('Ошибка повторной отправки документов', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Функция создания модального окна подтверждения повторной отправки
|
// Функция создания модального окна подтверждения повторной отправки
|
||||||
function createResendConfirmModal(singing) {
|
function createResendConfirmModal(singing) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -371,44 +388,259 @@
|
|||||||
modalWrapper.className = 'el-dialog__wrapper';
|
modalWrapper.className = 'el-dialog__wrapper';
|
||||||
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
||||||
|
|
||||||
const backdrop = document.createElement('div');
|
// Собираем всех получателей (recipients + idPatientMis)
|
||||||
backdrop.className = 'v-modal';
|
const allRecipients = [];
|
||||||
backdrop.style.cssText = 'z-index: 2001;';
|
|
||||||
backdrop.tabIndex = 0;
|
// Добавляем idPatientMis если есть
|
||||||
|
if (singing.idPatientMis) {
|
||||||
|
allRecipients.push({
|
||||||
|
id: singing.idPatientMis,
|
||||||
|
name: getRecipientNameById(singing, singing.idPatientMis)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем recipients
|
||||||
|
if (singing.recipients && singing.recipients.length > 0) {
|
||||||
|
singing.recipients.forEach(id => {
|
||||||
|
// Проверяем, не добавили ли уже этого получателя
|
||||||
|
if (!allRecipients.some(r => r.id === id)) {
|
||||||
|
allRecipients.push({
|
||||||
|
id: id,
|
||||||
|
name: getRecipientNameById(singing, id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRecipients = allRecipients.length > 0;
|
||||||
|
|
||||||
|
// Маппинг типов доставки на отображаемые названия
|
||||||
|
const deliveryTypeLabels = {
|
||||||
|
'sms': 'СМС-сообщение',
|
||||||
|
'max': 'МАХ-сообщение',
|
||||||
|
'mila': 'Mila-сообщение',
|
||||||
|
'goskey': 'Goskey-сообщение'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Доступные типы доставки
|
||||||
|
const deliveryTypes = Object.keys(deliveryTypeSettings).filter(key => deliveryTypeSettings[key] === true);
|
||||||
|
|
||||||
|
// Создаем HTML для списка получателей с чекбоксами
|
||||||
|
const recipientsHtml = hasRecipients ? `
|
||||||
|
<div style="margin-top: 16px;">
|
||||||
|
<div style="font-weight: 500; color: #303133; margin-bottom: 8px;">Получатели:</div>
|
||||||
|
<div style="max-height: 200px; overflow-y: auto; border: 1px solid #DCDFE6; border-radius: 4px; padding: 8px;">
|
||||||
|
${allRecipients.map(recipient => `
|
||||||
|
<div style="display: flex; align-items: center; padding: 6px 8px; border-bottom: 1px solid #EBEEF5;">
|
||||||
|
<label style="display: flex; align-items: center; width: 100%; cursor: pointer;">
|
||||||
|
<span class="el-checkbox" style="margin-right: 10px;">
|
||||||
|
<input type="checkbox" class="recipient-checkbox" value="${recipient.id}" style="width: 16px; height: 16px; cursor: pointer;">
|
||||||
|
</span>
|
||||||
|
<span style="color: #606266;">${recipient.name}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : '';
|
||||||
|
|
||||||
modalWrapper.innerHTML = `
|
modalWrapper.innerHTML = `
|
||||||
<div class="el-dialog" style="width: 450px; margin-top: 25vh;">
|
<div class="el-dialog" style="width: 500px; margin-top: 15vh;">
|
||||||
<div class="el-dialog__header">
|
<div class="el-dialog__header">
|
||||||
<span class="el-dialog__title">Подтверждение повторной отправки</span>
|
<span class="el-dialog__title">Подтверждение повторной отправки</span>
|
||||||
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
||||||
<i class="el-dialog__close el-icon el-icon-close"></i>
|
<i class="el-dialog__close el-icon el-icon-close"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-dialog__body" style="padding: 20px;">
|
<div class="el-dialog__body" style="padding: 20px; max-height: 60vh; overflow-y: auto;">
|
||||||
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
||||||
<i class="el-icon el-icon-warning" style="font-size: 24px; color: #E6A23C;"></i>
|
<i class="el-icon el-icon-warning" style="font-size: 24px; color: #E6A23C;"></i>
|
||||||
<div>
|
<div style="flex: 1;">
|
||||||
<p style="margin: 0 0 10px 0; color: #606266;">Вы действительно хотите повторно отправить документы на подписание?</p>
|
<p style="margin: 0 0 10px 0; color: #606266;">Вы действительно хотите повторно отправить документы на подписание?</p>
|
||||||
<div style="background: #f8f8f8; padding: 10px; border-radius: 4px; font-size: 13px; color: #E6A23C; border-left: 3px solid #E6A23C;">
|
<div style="background: #f8f8f8; padding: 10px; border-radius: 4px; font-size: 13px; color: #E6A23C; border-left: 3px solid #E6A23C; margin-bottom: 10px;">
|
||||||
<i class="el-icon el-icon-document" style="margin-right: 6px;"></i>
|
<i class="el-icon el-icon-document" style="margin-right: 6px;"></i>
|
||||||
<strong>Документы:</strong> ${singing.documents.map(d => `№${d.number} ${d.title}`).join(', ')}
|
<strong>Документы:</strong> ${singing.documents.map(d => `№${d.number} ${d.title}`).join(', ')}
|
||||||
|
</div>
|
||||||
|
${recipientsHtml}
|
||||||
|
|
||||||
|
<!-- Выпадающий список способа отправки -->
|
||||||
|
<div style="margin-top: 16px;">
|
||||||
|
<div style="font-weight: 500; color: #303133; margin-bottom: 8px;">Способ отправки:</div>
|
||||||
|
<div class="delivery-select-wrapper" style="position: relative; width: 100%;">
|
||||||
|
<select class="delivery-select" style="
|
||||||
|
width: 100%;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 24px 0 10px;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: white;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
font-family: inherit;
|
||||||
|
">
|
||||||
|
<option value="" selected disabled>Выберите способ отправки</option>
|
||||||
|
${deliveryTypes.map(type => `
|
||||||
|
<option value="${type}">
|
||||||
|
${deliveryTypeLabels[type]}
|
||||||
|
</option>
|
||||||
|
`).join('')}
|
||||||
|
</select>
|
||||||
|
<span style="
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
pointer-events: none;
|
||||||
|
color: #C0C4CC;
|
||||||
|
font-size: 12px;
|
||||||
|
">▼</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${!hasRecipients ? '<p style="color: #909399; margin: 10px 0 0;">Нет получателей для повторной отправки</p>' : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="el-dialog__footer" style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon cancel-btn"
|
||||||
|
style="display: flex; align-items: center;">
|
||||||
|
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
||||||
|
<span>Отмена</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon confirm-btn"
|
||||||
|
style="color: #67C23A; border-color: #67C23A; display: flex; align-items: center; ${!hasRecipients ? 'opacity: 0.5; pointer-events: none;' : ''}">
|
||||||
|
<i class="m-icon fa-redo-alt button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
||||||
|
<span>Отправить повторно</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(modalWrapper);
|
||||||
|
|
||||||
|
// Получаем элементы
|
||||||
|
const checkboxes = modalWrapper.querySelectorAll('.recipient-checkbox');
|
||||||
|
const confirmBtn = modalWrapper.querySelector('.confirm-btn');
|
||||||
|
const deliverySelect = modalWrapper.querySelector('.delivery-select');
|
||||||
|
let selectedDeliveryType = deliverySelect.value || null;
|
||||||
|
|
||||||
|
// Функция обновления состояния кнопки
|
||||||
|
function updateConfirmButton() {
|
||||||
|
const anyChecked = Array.from(checkboxes).some(cb => cb.checked);
|
||||||
|
const hasDeliveryType = selectedDeliveryType && selectedDeliveryType !== '';
|
||||||
|
|
||||||
|
if (anyChecked && hasDeliveryType) {
|
||||||
|
confirmBtn.style.opacity = '1';
|
||||||
|
confirmBtn.style.pointerEvents = 'auto';
|
||||||
|
} else {
|
||||||
|
confirmBtn.style.opacity = '0.5';
|
||||||
|
confirmBtn.style.pointerEvents = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик изменения выбора в select
|
||||||
|
deliverySelect.addEventListener('change', (e) => {
|
||||||
|
selectedDeliveryType = e.target.value;
|
||||||
|
updateConfirmButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработчики для чекбоксов
|
||||||
|
if (checkboxes.length > 0) {
|
||||||
|
checkboxes.forEach(cb => {
|
||||||
|
cb.addEventListener('change', updateConfirmButton);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функции закрытия
|
||||||
|
const closeModal = () => {
|
||||||
|
modalWrapper.remove();
|
||||||
|
resolve({ confirmed: false, recipients: [], deliveryType: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Обработчик кнопки подтверждения
|
||||||
|
confirmBtn.addEventListener('click', () => {
|
||||||
|
const selectedRecipients = Array.from(checkboxes)
|
||||||
|
.filter(cb => cb.checked)
|
||||||
|
.map(cb => cb.value);
|
||||||
|
|
||||||
|
if (selectedRecipients.length === 0 || !selectedDeliveryType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modalWrapper.remove();
|
||||||
|
resolve({
|
||||||
|
confirmed: true,
|
||||||
|
recipients: selectedRecipients,
|
||||||
|
deliveryType: selectedDeliveryType
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработчики закрытия
|
||||||
|
modalWrapper.querySelector('.el-dialog__headerbtn').addEventListener('click', closeModal);
|
||||||
|
modalWrapper.querySelector('.cancel-btn').addEventListener('click', closeModal);
|
||||||
|
modalWrapper.addEventListener('click', (e) => {
|
||||||
|
if (e.target === modalWrapper) closeModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Закрытие по ESC
|
||||||
|
const escHandler = (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeModal();
|
||||||
|
document.removeEventListener('keydown', escHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', escHandler);
|
||||||
|
|
||||||
|
// Инициализация состояния кнопки
|
||||||
|
updateConfirmButton();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция создания модального окна подтверждения отзыва
|
||||||
|
function createRevokeConfirmModal(singing) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const modalWrapper = document.createElement('div');
|
||||||
|
modalWrapper.className = 'el-dialog__wrapper';
|
||||||
|
modalWrapper.style.cssText = 'z-index: 2001; position: fixed; top: 0; right: 0; bottom: 0; left: 0; overflow: auto;';
|
||||||
|
|
||||||
|
modalWrapper.innerHTML = `
|
||||||
|
<div class="el-dialog" style="width: 450px; margin-top: 25vh;">
|
||||||
|
<div class="el-dialog__header">
|
||||||
|
<span class="el-dialog__title">Подтверждение отзыва</span>
|
||||||
|
<button type="button" class="el-dialog__headerbtn" aria-label="Close">
|
||||||
|
<i class="el-dialog__close el-icon el-icon-close"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="el-dialog__body" style="padding: 20px;">
|
||||||
|
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
||||||
|
<i class="el-icon el-icon-warning" style="font-size: 24px; color: #E6A23C;"></i>
|
||||||
|
<div>
|
||||||
|
<p style="margin: 0 0 10px 0; color: #606266;">Вы действительно хотите отозвать документы из подписания?</p>
|
||||||
|
<div style="background: #f8f8f8; padding: 10px; border-radius: 4px; font-size: 13px; color: #E6A23C; border-left: 3px solid #E6A23C;">
|
||||||
|
<i class="el-icon el-icon-document" style="margin-right: 6px;"></i>
|
||||||
|
<strong>Документы:</strong> ${singing.documents.map(d => `№${d.number} ${d.title}`).join(', ')}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-dialog__footer" style="display: flex; justify-content: space-between; align-items: center;">
|
|
||||||
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon cancel-btn"
|
|
||||||
style="display: flex; align-items: center;">
|
|
||||||
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
|
||||||
<span>Отмена</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon confirm-btn" style="color: #67C23A; border-color: #67C23A; display: flex; align-items: center;">
|
|
||||||
<i class="m-icon fa-redo-alt button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
|
||||||
<span>Отправить повторно</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
<div class="el-dialog__footer" style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon cancel-btn"
|
||||||
|
style="display: flex; align-items: center;">
|
||||||
|
<i class="m-icon fa-times button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
||||||
|
<span>Отмена</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="el-button m-button el-button--small is-plain button-with-icon confirm-btn" style="color: #F56C6C; border-color: #F56C6C; display: flex; align-items: center;">
|
||||||
|
<i class="m-icon fa-ban button-icon fad" style="font-size: 14px; margin-right: 6px;"></i>
|
||||||
|
<span>Отозвать</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
document.body.appendChild(modalWrapper);
|
document.body.appendChild(modalWrapper);
|
||||||
|
|
||||||
@@ -438,43 +670,9 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция повторной отправки документов
|
|
||||||
async function resendDocuments(singing, modalToClose) {
|
|
||||||
try {
|
|
||||||
// Сразу закрываем окно со списком документов
|
|
||||||
if (modalToClose && modalToClose.parentNode) {
|
|
||||||
modalToClose.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Показываем подтверждение
|
|
||||||
const confirmed = await createResendConfirmModal(singing);
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
showMessage('Повторная отправка документов...', 'info');
|
|
||||||
|
|
||||||
// Отправляем запрос на повторную отправку
|
|
||||||
const response = await sendMessageToContent('resendDocuments', {
|
|
||||||
id: singing.id,
|
|
||||||
trackingId: singing.trackingId,
|
|
||||||
idPatientMis: singing.idPatientMis
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
showMessage('Документы успешно отправлены повторно', 'success');
|
|
||||||
console.log('Документы успешно отправлены повторно');
|
|
||||||
// Обновляем список документов
|
|
||||||
await prepareDocuments();
|
|
||||||
} else {
|
|
||||||
showMessage('Ошибка повторной отправки документов: ' + (response.message || 'Неизвестная ошибка'), 'error');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Ошибка повторной отправки документов:', error);
|
|
||||||
showMessage('Ошибка повторной отправки документов', 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Функция создания таблицы документов
|
// Функция создания таблицы документов
|
||||||
function createDocumentsTable(data) {
|
function createDocumentsTable(data) {
|
||||||
|
|
||||||
// Создаем модальное окно
|
// Создаем модальное окно
|
||||||
const modalWrapper = document.createElement('div');
|
const modalWrapper = document.createElement('div');
|
||||||
modalWrapper.className = 'el-dialog__wrapper';
|
modalWrapper.className = 'el-dialog__wrapper';
|
||||||
@@ -509,9 +707,10 @@
|
|||||||
} else {
|
} else {
|
||||||
const tableRows = data.map((singing, index) => {
|
const tableRows = data.map((singing, index) => {
|
||||||
// Определяем последний статус
|
// Определяем последний статус
|
||||||
const lastStatus = singing.statuses.reduce((max, status) =>
|
const commonStatuses = singing.statuses.filter(s => s.idPatientMis === null);
|
||||||
|
const lastStatus = commonStatuses.reduce((max, status) =>
|
||||||
status.id > max.id ? status : max
|
status.id > max.id ? status : max
|
||||||
, singing.statuses[0]);
|
, commonStatuses[0] || singing.statuses[0]);
|
||||||
|
|
||||||
const statusClass = getStatusClass(lastStatus.category);
|
const statusClass = getStatusClass(lastStatus.category);
|
||||||
const statusIcon = getStatusIcon(lastStatus.category);
|
const statusIcon = getStatusIcon(lastStatus.category);
|
||||||
@@ -519,6 +718,14 @@
|
|||||||
lastStatus.category === 'processing' ? '#409EFF' :
|
lastStatus.category === 'processing' ? '#409EFF' :
|
||||||
lastStatus.category === 'error' ? '#F56C6C' : '#909399';
|
lastStatus.category === 'error' ? '#F56C6C' : '#909399';
|
||||||
|
|
||||||
|
// Маппинг типов доставки на отображаемые названия
|
||||||
|
const deliveryTypeLabels = {
|
||||||
|
'sms': 'СМС-сообщение',
|
||||||
|
'max': 'МАХ-сообщение',
|
||||||
|
'mila': 'Mila-сообщение',
|
||||||
|
'goskey': 'Goskey-сообщение'
|
||||||
|
};
|
||||||
|
|
||||||
// Формируем ячейку с документами
|
// Формируем ячейку с документами
|
||||||
const documentsHtml = singing.documents.map(doc => `
|
const documentsHtml = singing.documents.map(doc => `
|
||||||
<div style="display: flex; align-items: flex-start; gap: 8px; margin-bottom: ${singing.documents.length > 1 ? '8px' : '0'}; padding: 4px 0;">
|
<div style="display: flex; align-items: flex-start; gap: 8px; margin-bottom: ${singing.documents.length > 1 ? '8px' : '0'}; padding: 4px 0;">
|
||||||
@@ -550,47 +757,47 @@
|
|||||||
${documentsHtml}
|
${documentsHtml}
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 12px; vertical-align: top;">
|
<td style="padding: 12px; vertical-align: top;">
|
||||||
<div style="display: flex; align-items: center; gap: 12px;">
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
<div style="display: flex; align-items: center; gap: 8px; flex: 1;">
|
<div style="display: flex; align-items: center; gap: 4px; flex: 1;">
|
||||||
<i class="el-icon ${statusIcon}" style="color: ${statusColor}; font-size: 16px;"></i>
|
<i class="el-icon ${statusIcon}" style="color: ${statusColor}; font-size: 16px;"></i>
|
||||||
<div>
|
<div>
|
||||||
<div style="color: ${statusColor};">${lastStatus.description}</div>
|
<div style="color: ${statusColor};">${lastStatus.description}</div>
|
||||||
<div style="font-size: 12px; color: #909399; margin-top: 2px;">${formatDate(lastStatus.created_at)}</div>
|
<div style="font-size: 12px; color: #909399; margin-top: 2px;">${formatDate(lastStatus.created_at)} ✉️ ${deliveryTypeLabels[singing.deliveryType]}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; gap: 8px;">
|
<div style="display: flex; gap: 2px; align-items: center;">
|
||||||
${singing.storagePath ? `
|
${singing.storagePath && singing.storagePath.length > 0
|
||||||
<button class="el-button el-button--text view-main-doc-btn"
|
? singing.storagePath.map((path, index) => `
|
||||||
data-title="${singing.title}"
|
<button class="el-button el-button--text view-main-doc-btn"
|
||||||
data-path="${singing.storagePath}"
|
data-title="${singing.title || `Итоговый документ ${index + 1}`}"
|
||||||
title="Просмотреть основной документ"
|
data-path="${path}"
|
||||||
style="padding: 0; border: none;">
|
title="Просмотреть основной документ ${singing.storagePath.length > 1 ? index + 1 : ''}"
|
||||||
<i class="el-icon el-icon-document" style="color: #409EFF; font-size: 18px;"></i>
|
style="margin: 0; padding: 0; border: none; min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;">
|
||||||
</button>
|
<i class="el-icon el-icon-document" style="color: #409EFF; font-size: 16px;"></i>
|
||||||
` : ''}
|
</button>
|
||||||
|
`).join('')
|
||||||
|
: ''}
|
||||||
${singing.statuses.length > 1 ? `
|
${singing.statuses.length > 1 ? `
|
||||||
<button class="el-button el-button--text view-statuses-btn"
|
<button class="el-button el-button--text view-statuses-btn"
|
||||||
data-index="${index}"
|
data-index="${index}"
|
||||||
title="История статусов"
|
title="История статусов"
|
||||||
style="padding: 0; border: none;">
|
style="margin: 0; padding: 0; border: none; min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;">
|
||||||
<i class="el-icon el-icon-time" style="color: #909399; font-size: 18px;"></i>
|
<i class="el-icon el-icon-time" style="color: #909399; font-size: 16px;"></i>
|
||||||
</button>
|
</button>
|
||||||
` : ''}
|
` : ''}
|
||||||
${lastStatus.category === 'processing' ? `
|
${lastStatus.category === 'processing' ? `
|
||||||
<div style="display: flex; gap: 4px;">
|
<button class="el-button el-button--text resend-btn"
|
||||||
<button class="el-button el-button--text resend-btn"
|
data-index="${index}"
|
||||||
data-index="${index}"
|
title="Повторно отправить документы"
|
||||||
title="Повторно отправить документы"
|
style="margin: 0; padding: 0; border: none; min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;">
|
||||||
style="padding: 0; border: none;">
|
<i class="el-icon el-icon-refresh" style="color: #67C23A; font-size: 16px;"></i>
|
||||||
<i class="el-icon el-icon-refresh" style="color: #67C23A; font-size: 18px;"></i>
|
</button>
|
||||||
</button>
|
<button class="el-button el-button--text revoke-btn"
|
||||||
<button class="el-button el-button--text revoke-btn"
|
data-index="${index}"
|
||||||
data-index="${index}"
|
title="Отозвать документы"
|
||||||
title="Отозвать документы"
|
style="margin: 0; padding: 0; border: none; min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;">
|
||||||
style="padding: 0; border: none;">
|
<i class="el-icon el-icon-circle-close" style="color: #F56C6C; font-size: 16px;"></i>
|
||||||
<i class="el-icon el-icon-circle-close" style="color: #F56C6C; font-size: 18px;"></i>
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -707,7 +914,8 @@
|
|||||||
const response = await sendMessageToContent('prepareDocuments', {});
|
const response = await sendMessageToContent('prepareDocuments', {});
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
createDocumentsTable(response.data);
|
deliveryTypeSettings = response.data.deliveryType;
|
||||||
|
createDocumentsTable(response.data.singings);
|
||||||
} else {
|
} else {
|
||||||
showMessage('Ошибка загрузки документов: ' + (response.message || 'Неизвестная ошибка'), 'error');
|
showMessage('Ошибка загрузки документов: ' + (response.message || 'Неизвестная ошибка'), 'error');
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-8
@@ -37,7 +37,7 @@
|
|||||||
patientPhone = window.gon.specific.client.phone;
|
patientPhone = window.gon.specific.client.phone;
|
||||||
const patientPhoneNormalized = `+7${patientPhone.replace(/[^\d]/g, '').slice(1, 12)}`;
|
const patientPhoneNormalized = `+7${patientPhone.replace(/[^\d]/g, '').slice(1, 12)}`;
|
||||||
|
|
||||||
metaData.patients = [{
|
metaData.patient = {
|
||||||
idPatientMis: window.gon.specific.client.id,
|
idPatientMis: window.gon.specific.client.id,
|
||||||
familyName: window.gon.specific.client.surname,
|
familyName: window.gon.specific.client.surname,
|
||||||
givenName: window.gon.specific.client.name,
|
givenName: window.gon.specific.client.name,
|
||||||
@@ -55,10 +55,10 @@
|
|||||||
documentName: 'СНИЛС',
|
documentName: 'СНИЛС',
|
||||||
idDocumentType: 223
|
idDocumentType: 223
|
||||||
}]
|
}]
|
||||||
}]
|
}
|
||||||
|
|
||||||
if (window.gon.specific.client.email) {
|
if (window.gon.specific.client.email) {
|
||||||
metaData.patients[0].telecom.push({
|
metaData.patient.telecom.push({
|
||||||
system: 'Email',
|
system: 'Email',
|
||||||
value: window.gon.specific.client.email
|
value: window.gon.specific.client.email
|
||||||
});
|
});
|
||||||
@@ -73,11 +73,6 @@
|
|||||||
data: doc.data
|
data: doc.data
|
||||||
}));
|
}));
|
||||||
|
|
||||||
metaData.userData = {
|
|
||||||
id: window.gon.application.current_user.id,
|
|
||||||
login: window.gon.application.current_user.username,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Отправляем только один раз
|
// Отправляем только один раз
|
||||||
window.postMessage(
|
window.postMessage(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -612,7 +612,6 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
hyphens: auto;
|
hyphens: auto;
|
||||||
cursor: help;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: 120px;
|
max-width: 120px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,9 +68,9 @@
|
|||||||
|
|
||||||
function getStatusIcon(category) {
|
function getStatusIcon(category) {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 'completed': return '✓';
|
case 'completed': return '✅';
|
||||||
case 'processing': return '⋯';
|
case 'processing': return '⌛';
|
||||||
case 'error': return '✗';
|
case 'error': return '❌';
|
||||||
default: return '?';
|
default: return '?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,6 +312,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Рендер таблицы
|
||||||
// Рендер таблицы
|
// Рендер таблицы
|
||||||
function renderTable(data) {
|
function renderTable(data) {
|
||||||
if (!data || data.length === 0) {
|
if (!data || data.length === 0) {
|
||||||
@@ -323,56 +324,78 @@
|
|||||||
emptyState.classList.add('hidden');
|
emptyState.classList.add('hidden');
|
||||||
|
|
||||||
const rows = data.map(item => {
|
const rows = data.map(item => {
|
||||||
const lastStatus = item.statuses?.reduce((max, s) => s.id > max.id ? s : max, item.statuses[0]);
|
// Берем только общие статусы (где idPatientMis === null)
|
||||||
const statusClass = getStatusClass(lastStatus?.category);
|
const commonStatuses = item.statuses?.filter(s => s.idPatientMis === null) || [];
|
||||||
const statusIcon = getStatusIcon(lastStatus?.category);
|
|
||||||
|
// Берем последний общий статус
|
||||||
|
const lastStatus = commonStatuses.length > 0
|
||||||
|
? commonStatuses.reduce((max, s) => s.id > max.id ? s : max, commonStatuses[0])
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Если нет общих статусов, используем первый статус из списка как fallback
|
||||||
|
const displayStatus = lastStatus || (item.statuses && item.statuses[0]) || null;
|
||||||
|
|
||||||
|
const statusClass = getStatusClass(displayStatus?.category);
|
||||||
|
const statusIcon = getStatusIcon(displayStatus?.category);
|
||||||
|
|
||||||
|
// Маппинг типов доставки на отображаемые названия
|
||||||
|
const deliveryTypeLabels = {
|
||||||
|
'sms': 'СМС',
|
||||||
|
'max': 'МАХ',
|
||||||
|
'mila': 'Mila',
|
||||||
|
'goskey': 'Goskey'
|
||||||
|
};
|
||||||
|
|
||||||
const documentsHtml = item.documents?.map(doc => {
|
const documentsHtml = item.documents?.map(doc => {
|
||||||
const isClickable = lastStatus?.category !== 'error';
|
// Документы можно просматривать только если статус не error
|
||||||
|
const isClickable = displayStatus?.category !== 'error' && doc.storagePath;
|
||||||
const baseClass = isClickable ? 'doc-item clickable-doc' : 'doc-item';
|
const baseClass = isClickable ? 'doc-item clickable-doc' : 'doc-item';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="${baseClass}"
|
<div class="${baseClass}"
|
||||||
${isClickable ? `data-path="${doc.storagePath}" data-title="${doc.title}"` : ''}
|
${isClickable ? `data-path="${doc.storagePath}" data-title="${doc.title}"` : ''}
|
||||||
style="${isClickable ? 'cursor: pointer;' : ''} display: flex; align-items: center; justify-content: space-between;">
|
style="${isClickable ? 'cursor: pointer;' : ''} display: flex; align-items: center; justify-content: space-between;">
|
||||||
<span style="flex: 1; text-align: left; word-break: break-word;">№${doc.number} ${doc.title?.replace(/\s+/g, ' ')}</span>
|
<span style="flex: 1; text-align: left; word-break: break-word;" title="${doc.title}">№${doc.number} ${doc.title?.replace(/\s+/g, ' ')}</span>
|
||||||
${isClickable ? '<span style="margin-left: 4px;">📄</span>' : ''}
|
${isClickable ? '<span style="margin-left: 4px; color: #409eff;">📄</span>' : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
const hasMainDocument = item.storagePath && !item.storagePath.includes('null');
|
const hasMainDocument = item.storagePath.length > 0;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="document-name">${item.patientName || 'Неизвестно'}</div>
|
<div class="document-name" title="${item.patientName || 'Неизвестно'}">${item.patientName || 'Неизвестно'}</div>
|
||||||
<div class="document-date">${formatDate(item.created_at)}</div>
|
<div class="document-date">${formatDate(item.created_at)}</div>
|
||||||
<div class="doctor-name" title="${item.userName || ''}">
|
<div class="document-date">✉️ ${deliveryTypeLabels[item.deliveryType] || item.deliveryType}</div>
|
||||||
<span>👤 ${item.userName || 'Неизвестно'}</span>
|
<div class="doctor-name" title="${item.userName || ''}">
|
||||||
|
<span>👤 ${item.userName || 'Неизвестно'}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="document-docs">
|
||||||
|
${documentsHtml}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="status-container">
|
||||||
|
<div class="document-status ${statusClass}"
|
||||||
|
title="${displayStatus?.description || ''}">
|
||||||
|
<span style="margin-right: 4px;">${statusIcon}</span>
|
||||||
|
${displayStatus?.name || 'Неизвестно'}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
<div class="status-date">${formatDate(displayStatus?.created_at || item.created_at)}</div>
|
||||||
<td>
|
${hasMainDocument && displayStatus?.category !== 'error'
|
||||||
<div class="document-docs">
|
? item.storagePath.map((path, index) => `
|
||||||
${documentsHtml}
|
<button class="doc-view-btn" data-path="${path}" title="Итоговый документ ${index + 1}">
|
||||||
</div>
|
📄 Файл ${index + 1}
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="status-container">
|
|
||||||
<div class="document-status ${statusClass}"
|
|
||||||
title="${lastStatus?.description || ''}">
|
|
||||||
<span style="margin-right: 4px;">${statusIcon}</span>
|
|
||||||
${lastStatus?.name || 'Неизвестно'}
|
|
||||||
</div>
|
|
||||||
<div class="status-date">${formatDate(lastStatus?.created_at || item.created_at)}</div>
|
|
||||||
${hasMainDocument ? `
|
|
||||||
<button class="doc-view-btn" data-path="${item.storagePath}" data-title="Основной документ">
|
|
||||||
📄 Просмотр
|
|
||||||
</button>
|
</button>
|
||||||
` : ''}
|
`).join('')
|
||||||
</div>
|
: ''}
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</td>
|
||||||
|
</tr>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
|||||||
+16
-4
@@ -94,7 +94,7 @@
|
|||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<!-- Период -->
|
<!-- Период -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label class="form-label small text-uppercase text-muted fw-semibold">Период</label>
|
<label class="form-label small text-uppercase text-muted fw-semibold">Период</label>
|
||||||
<select class="form-select" id="periodSelect">
|
<select class="form-select" id="periodSelect">
|
||||||
<option value="today">Сегодня</option>
|
<option value="today">Сегодня</option>
|
||||||
@@ -106,8 +106,20 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Способ отправки -->
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-uppercase text-muted fw-semibold">Способ отправки</label>
|
||||||
|
<select class="form-select" id="deliveryTypeSelect">
|
||||||
|
<option value="all">Все способы</option>
|
||||||
|
<option value="sms">СМС-сообщение</option>
|
||||||
|
<option value="max">МАХ-сообщение</option>
|
||||||
|
<option value="mila">Mila-сообщение</option>
|
||||||
|
<option value="goskey">Goskey-сообщение</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Статус -->
|
<!-- Статус -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label class="form-label small text-uppercase text-muted fw-semibold">Статус подписания</label>
|
<label class="form-label small text-uppercase text-muted fw-semibold">Статус подписания</label>
|
||||||
<select class="form-select" id="statusSelect">
|
<select class="form-select" id="statusSelect">
|
||||||
<option value="all">Все статусы</option>
|
<option value="all">Все статусы</option>
|
||||||
@@ -118,7 +130,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Тип подписания -->
|
<!-- Тип подписания -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label class="form-label small text-uppercase text-muted fw-semibold">Тип подписания</label>
|
<label class="form-label small text-uppercase text-muted fw-semibold">Тип подписания</label>
|
||||||
<select class="form-select" id="signatureTypeSelect">
|
<select class="form-select" id="signatureTypeSelect">
|
||||||
<option value="all">Все типы</option>
|
<option value="all">Все типы</option>
|
||||||
@@ -194,7 +206,7 @@
|
|||||||
<table class="table table-hover mb-0">
|
<table class="table table-hover mb-0">
|
||||||
<thead class="sticky-top bg-white">
|
<thead class="sticky-top bg-white">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 15%">Дата</th>
|
<th style="width: 15%">Отправлено</th>
|
||||||
<th style="width: 15%">Пациент</th>
|
<th style="width: 15%">Пациент</th>
|
||||||
<th style="width: 35%">Документы</th>
|
<th style="width: 35%">Документы</th>
|
||||||
<th style="width: 20%">Статус</th>
|
<th style="width: 20%">Статус</th>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
dateFrom: null,
|
dateFrom: null,
|
||||||
dateTo: null,
|
dateTo: null,
|
||||||
status: 'all',
|
status: 'all',
|
||||||
|
deliveryType: 'all',
|
||||||
signatureType: 'all',
|
signatureType: 'all',
|
||||||
senderName: '',
|
senderName: '',
|
||||||
patientName: '',
|
patientName: '',
|
||||||
@@ -30,27 +31,6 @@
|
|||||||
// Bootstrap модальное окно
|
// Bootstrap модальное окно
|
||||||
let statusModal = null;
|
let statusModal = null;
|
||||||
|
|
||||||
// Статусы из background.js
|
|
||||||
const statuses = {
|
|
||||||
201: { name: "Создан", description: "Документ создан через API, готов к обработке", category: "processing" },
|
|
||||||
202: { name: "Отправлен на подписание", description: "Документ отправлен получателю", category: "processing" },
|
|
||||||
203: { name: "Просмотрел", description: "Документ просмотрен получателем", category: "processing" },
|
|
||||||
204: { name: "Подписал", description: "Документ подписан получателем", category: "completed" },
|
|
||||||
205: { name: "Отказался", description: "Получатель отказался от подписания", category: "error" },
|
|
||||||
206: { name: "Срок для подписания истек", description: "Срок действия ссылки истек до момента проставления подписи или отказа", category: "error" },
|
|
||||||
207: { name: "Ожидание действий всех получателей", description: "Ожидание действий от всех получателей", category: "processing" },
|
|
||||||
208: { name: "Успешно. Подписан всеми — обработка", description: "Все получатели подписали, документ обрабатывается", category: "processing" },
|
|
||||||
209: { name: "Успешно. Подписан не всеми — обработка", description: "Не все получатели подписали, документ обрабатывается", category: "processing" },
|
|
||||||
210: { name: "Завершено. Подписано всеми", description: "Все получатели подписали, документ сохранен", category: "completed" },
|
|
||||||
211: { name: "Завершено. Подписано не всеми", description: "Не все получатели подписали, документ сохранен", category: "completed" },
|
|
||||||
212: { name: "Отменен для получателя", description: "Подписание отменено для конкретного получателя", category: "error" },
|
|
||||||
213: { name: "Завершено. Отменено для всех", description: "Подписание отменено для всех получателей", category: "completed" },
|
|
||||||
498: { name: "Завершено. Отклонено всеми", description: "Все получатели отказались от подписания", category: "error" },
|
|
||||||
499: { name: "Завершено. Истекло для всех", description: "Срок ссылки истек для всех получателей", category: "error" },
|
|
||||||
500: { name: "Ошибка обработки", description: "Ошибка во время обработки документа", category: "error" },
|
|
||||||
501: { name: "Ошибка доставки получателю", description: "Произошла ошибка при доставке конкретному получателю", category: "error" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// DOM элементы
|
// DOM элементы
|
||||||
const elements = {
|
const elements = {
|
||||||
periodSelect: document.getElementById('periodSelect'),
|
periodSelect: document.getElementById('periodSelect'),
|
||||||
@@ -58,6 +38,7 @@
|
|||||||
dateFrom: document.getElementById('dateFrom'),
|
dateFrom: document.getElementById('dateFrom'),
|
||||||
dateTo: document.getElementById('dateTo'),
|
dateTo: document.getElementById('dateTo'),
|
||||||
statusSelect: document.getElementById('statusSelect'),
|
statusSelect: document.getElementById('statusSelect'),
|
||||||
|
deliveryTypeSelect: document.getElementById('deliveryTypeSelect'),
|
||||||
signatureTypeSelect: document.getElementById('signatureTypeSelect'),
|
signatureTypeSelect: document.getElementById('signatureTypeSelect'),
|
||||||
senderInput: document.getElementById('senderInput'),
|
senderInput: document.getElementById('senderInput'),
|
||||||
patientInput: document.getElementById('patientInput'),
|
patientInput: document.getElementById('patientInput'),
|
||||||
@@ -118,6 +99,7 @@
|
|||||||
// Применяем фильтры к элементам управления
|
// Применяем фильтры к элементам управления
|
||||||
elements.periodSelect.value = state.filters.period;
|
elements.periodSelect.value = state.filters.period;
|
||||||
elements.statusSelect.value = state.filters.status;
|
elements.statusSelect.value = state.filters.status;
|
||||||
|
elements.deliveryTypeSelect.value = state.filters.deliveryType;
|
||||||
elements.signatureTypeSelect.value = state.filters.signatureType;
|
elements.signatureTypeSelect.value = state.filters.signatureType;
|
||||||
elements.senderInput.value = state.filters.senderName || '';
|
elements.senderInput.value = state.filters.senderName || '';
|
||||||
elements.patientInput.value = state.filters.patientName || '';
|
elements.patientInput.value = state.filters.patientName || '';
|
||||||
@@ -148,6 +130,7 @@
|
|||||||
|
|
||||||
// Фильтры
|
// Фильтры
|
||||||
elements.statusSelect.addEventListener('change', updateFilters);
|
elements.statusSelect.addEventListener('change', updateFilters);
|
||||||
|
elements.deliveryTypeSelect.addEventListener('change', updateFilters);
|
||||||
elements.signatureTypeSelect.addEventListener('change', updateFilters);
|
elements.signatureTypeSelect.addEventListener('change', updateFilters);
|
||||||
elements.senderInput.addEventListener('input', debounce(updateFilters, 500));
|
elements.senderInput.addEventListener('input', debounce(updateFilters, 500));
|
||||||
elements.patientInput.addEventListener('input', debounce(updateFilters, 500));
|
elements.patientInput.addEventListener('input', debounce(updateFilters, 500));
|
||||||
@@ -216,18 +199,17 @@
|
|||||||
switch (period) {
|
switch (period) {
|
||||||
case 'today':
|
case 'today':
|
||||||
break;
|
break;
|
||||||
case 'yesterday':
|
case '3days':
|
||||||
from.setDate(from.getDate() - 1);
|
from.setDate(from.getDate() - 3);
|
||||||
today.setDate(today.getDate() - 1);
|
|
||||||
break;
|
break;
|
||||||
case 'week':
|
case '7days':
|
||||||
from.setDate(from.getDate() - 7);
|
from.setDate(from.getDate() - 7);
|
||||||
break;
|
break;
|
||||||
case 'month':
|
case '30days':
|
||||||
from.setMonth(from.getMonth() - 1);
|
from.setDate(from.getDate() - 30);
|
||||||
break;
|
break;
|
||||||
case 'quarter':
|
case '90days':
|
||||||
from.setMonth(from.getMonth() - 3);
|
from.setDate(from.getDate() - 90);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +227,7 @@
|
|||||||
dateFrom: elements.dateFrom.value,
|
dateFrom: elements.dateFrom.value,
|
||||||
dateTo: elements.dateTo.value,
|
dateTo: elements.dateTo.value,
|
||||||
status: elements.statusSelect.value,
|
status: elements.statusSelect.value,
|
||||||
|
deliveryType: elements.deliveryTypeSelect.value,
|
||||||
signatureType: elements.signatureTypeSelect.value,
|
signatureType: elements.signatureTypeSelect.value,
|
||||||
senderName: elements.senderInput.value.trim(),
|
senderName: elements.senderInput.value.trim(),
|
||||||
patientName: elements.patientInput.value.trim(),
|
patientName: elements.patientInput.value.trim(),
|
||||||
@@ -280,6 +263,7 @@
|
|||||||
elements.periodSelect.value = 'today';
|
elements.periodSelect.value = 'today';
|
||||||
elements.customDateRange.style.display = 'none';
|
elements.customDateRange.style.display = 'none';
|
||||||
elements.statusSelect.value = 'all';
|
elements.statusSelect.value = 'all';
|
||||||
|
elements.deliveryTypeSelect.value = 'all';
|
||||||
elements.signatureTypeSelect.value = 'all';
|
elements.signatureTypeSelect.value = 'all';
|
||||||
elements.senderInput.value = '';
|
elements.senderInput.value = '';
|
||||||
elements.patientInput.value = '';
|
elements.patientInput.value = '';
|
||||||
@@ -311,8 +295,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
// Обогащаем статусы
|
state.results = response.data || [];
|
||||||
state.results = enrichStatuses(response.data || []);
|
|
||||||
state.pagination.totalItems = state.results.length;
|
state.pagination.totalItems = state.results.length;
|
||||||
state.pagination.totalPages = Math.ceil(state.pagination.totalItems / state.pagination.itemsPerPage);
|
state.pagination.totalPages = Math.ceil(state.pagination.totalItems / state.pagination.itemsPerPage);
|
||||||
state.pagination.currentPage = 1;
|
state.pagination.currentPage = 1;
|
||||||
@@ -329,31 +312,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обогащение статусов
|
|
||||||
function enrichStatuses(data) {
|
|
||||||
if (!Array.isArray(data)) return data;
|
|
||||||
|
|
||||||
data.forEach(item => {
|
|
||||||
if (Array.isArray(item.statuses)) {
|
|
||||||
item.statuses.forEach(status => {
|
|
||||||
const statusInfo = statuses[status.status] || {
|
|
||||||
name: `Статус ${status.status}`,
|
|
||||||
description: `Неизвестный статус ${status.status}`,
|
|
||||||
category: "error"
|
|
||||||
};
|
|
||||||
status.name = statusInfo.name;
|
|
||||||
status.description = statusInfo.description;
|
|
||||||
status.category = statusInfo.category;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Сортируем статусы по id для хронологии
|
|
||||||
item.statuses.sort((a, b) => a.id - b.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Определение типа подписания
|
// Определение типа подписания
|
||||||
function getSignatureType(item) {
|
function getSignatureType(item) {
|
||||||
return item.esiaAuth === true ? 'esia' : 'mchd';
|
return item.esiaAuth === true ? 'esia' : 'mchd';
|
||||||
@@ -440,65 +398,116 @@
|
|||||||
|
|
||||||
// Создание строки таблицы
|
// Создание строки таблицы
|
||||||
function createTableRow(item) {
|
function createTableRow(item) {
|
||||||
const lastStatus = item.statuses?.length > 0 ? item.statuses[item.statuses.length - 1] : null;
|
// Берем только общие статусы (где idPatientMis === null)
|
||||||
const statusClass = lastStatus?.category || 'warning';
|
const commonStatuses = item.statuses?.filter(s => s.idPatientMis === null) || [];
|
||||||
|
|
||||||
|
let lastCommonStatus = null;
|
||||||
|
if (commonStatuses.length > 0) {
|
||||||
|
lastCommonStatus = commonStatuses.reduce((last, current) => current.id > last.id ? current : last);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если нет общих статусов, используем первый статус из списка как fallback
|
||||||
|
const displayStatus = lastCommonStatus || (item.statuses && item.statuses[0]) || null;
|
||||||
|
|
||||||
const date = formatDateTime(item.created_at);
|
const date = formatDateTime(item.created_at);
|
||||||
|
|
||||||
// Документы
|
// Маппинг типов доставки на отображаемые названия
|
||||||
|
const deliveryTypeLabels = {
|
||||||
|
'sms': 'СМС',
|
||||||
|
'max': 'МАХ',
|
||||||
|
'mila': 'Mila',
|
||||||
|
'goskey': 'Goskey'
|
||||||
|
};
|
||||||
|
const deliveryType = item.deliveryType && deliveryTypeLabels[item.deliveryType] || item.deliveryType || '—';
|
||||||
|
|
||||||
|
// Получаем уникальных получателей из статусов (исключая самого пациента)
|
||||||
|
const recipients = new Set();
|
||||||
|
if (item.statuses && Array.isArray(item.statuses)) {
|
||||||
|
item.statuses.forEach(status => {
|
||||||
|
// Проверяем, что это статус получателя (есть patient) и это не сам пациент
|
||||||
|
if (status.patient && status.patient.name &&
|
||||||
|
status.idPatientMis !== item.idPatientMis) {
|
||||||
|
recipients.add(status.patient.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Преобразуем Set в массив и сортируем
|
||||||
|
const recipientsList = Array.from(recipients).sort();
|
||||||
|
|
||||||
|
// Формируем HTML для получателей
|
||||||
|
const recipientsHtml = recipientsList.length > 0 ? `
|
||||||
|
<div class="recipients-list small text-muted mt-1" style="font-size: 10px; line-height: 1.3;">
|
||||||
|
<i class="bi bi-people me-1"></i>
|
||||||
|
${recipientsList.join(', ')}
|
||||||
|
</div>
|
||||||
|
` : '';
|
||||||
|
|
||||||
|
// Документы - теперь название отображается полностью, без обрезания
|
||||||
const documentsHtml = item.documents?.map(doc => {
|
const documentsHtml = item.documents?.map(doc => {
|
||||||
const canView = lastStatus?.category !== 'completed';
|
// Документы можно просматривать только если статус не error
|
||||||
|
const canView = displayStatus?.category !== 'error' && doc.storagePath && doc.storagePath.length > 0;
|
||||||
return `
|
return `
|
||||||
<div class="document-item p-2 mb-1 bg-light rounded ${canView ? 'text-primary' : 'text-muted'}"
|
<div class="document-item p-2 mb-1 bg-light rounded ${canView ? 'text-primary' : 'text-muted'}"
|
||||||
data-doc-path="${doc.storagePath || ''}"
|
data-doc-path="${doc.storagePath || ''}"
|
||||||
data-doc-title="${doc.title}"
|
data-doc-title="${doc.title}"
|
||||||
data-can-view="${canView}"
|
data-can-view="${canView}"
|
||||||
style="cursor: ${canView ? 'pointer' : 'default'};">
|
style="cursor: ${canView ? 'pointer' : 'default'};">
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<span class="fw-semibold">№${doc.number}</span>
|
<span class="fw-semibold flex-shrink-0">№${doc.number}</span>
|
||||||
<span class="small text-truncate flex-grow-1">${doc.title}</span>
|
<span class="small flex-grow-1" style="white-space: normal; word-break: break-word;" title="${doc.title}">${doc.title}</span>
|
||||||
${canView ? '<i class="bi bi-eye"></i>' : ''}
|
${canView ? '<i class="bi bi-eye flex-shrink-0"></i>' : ''}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
</div>
|
||||||
|
`;
|
||||||
}).join('') || '<span class="text-muted small">—</span>';
|
}).join('') || '<span class="text-muted small">—</span>';
|
||||||
|
|
||||||
// Статус
|
// Статус
|
||||||
const statusHtml = lastStatus ? `
|
const statusHtml = displayStatus ? `
|
||||||
<div>
|
<div>
|
||||||
<span class="badge ${getStatusBadgeClass(lastStatus.category)} status-badge ${item.statuses?.length > 1 ? '' : ''}"
|
<span class="badge ${getStatusBadgeClass(displayStatus.category)} status-badge ${item.statuses?.length > 1 ? '' : ''}"
|
||||||
data-status-history='${JSON.stringify(item.statuses)}'>
|
data-status-history='${JSON.stringify(item.statuses)}'>
|
||||||
<i class="bi ${getStatusIcon(lastStatus.category)} me-1"></i>
|
<i class="bi ${getStatusIcon(displayStatus.category)} me-1"></i>
|
||||||
${lastStatus.name || 'Неизвестно'}
|
${displayStatus.name || displayStatus.description || 'Неизвестно'}
|
||||||
</span>
|
</span>
|
||||||
<div class="small text-muted mt-1">${formatDateTime(lastStatus.created_at)}</div>
|
<div class="small text-muted mt-1">${formatDateTime(displayStatus.created_at)}</div>
|
||||||
</div>
|
</div>
|
||||||
` : '<span class="text-muted small">—</span>';
|
` : '<span class="text-muted small">—</span>';
|
||||||
|
|
||||||
// Тип и кнопка
|
// Тип подписания
|
||||||
const signatureTypeClass = getSignatureTypeClass(item);
|
const signatureTypeClass = getSignatureTypeClass(item);
|
||||||
const finalAction = lastStatus?.category === 'completed' && item.storagePath ? `
|
|
||||||
<button class="btn btn-sm btn-outline-primary mt-1 view-final-btn" data-path="${item.storagePath}" data-title="Итоговый документ">
|
// Кнопка просмотра итогового документа
|
||||||
|
const finalAction = displayStatus?.category === 'completed' && item.storagePath && item.storagePath.length > 0
|
||||||
|
? item.storagePath.map((path, index) => `
|
||||||
|
<button class="btn btn-sm btn-outline-primary mt-1 view-final-btn" data-path="${path}" title="Итоговый документ ${index + 1}">
|
||||||
<i class="bi bi-file-pdf"></i>
|
<i class="bi bi-file-pdf"></i>
|
||||||
</button>
|
</button>
|
||||||
` : '';
|
`).join('')
|
||||||
|
: '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr data-id="${item.id || ''}">
|
<tr data-id="${item.id || ''}">
|
||||||
<td class="align-middle"><span class="small">${date}</span></td>
|
<td class="align-middle"><span class="small">${date}<br>✉️ ${deliveryType}</span></td>
|
||||||
<td class="align-middle"><span class="small">${item.patientName || 'Неизвестно'}</span></td>
|
<td class="align-middle">
|
||||||
<td class="align-middle" style="max-width: 350px;">
|
<div>
|
||||||
<div class="documents-list" style="max-height: 100px; overflow-y: auto;">
|
<span class="small fw-semibold" title="${item.patientName || 'Неизвестно'}">${item.patientName || 'Неизвестно'}</span>
|
||||||
${documentsHtml}
|
${recipientsHtml}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">${statusHtml}</td>
|
<td class="align-middle" style="max-width: 350px;">
|
||||||
<td class="align-middle"><span class="small">${item.userName || '—'}</span></td>
|
<div class="documents-list" style="max-height: 100px; overflow-y: auto;">
|
||||||
<td class="align-middle">
|
${documentsHtml}
|
||||||
<span class="badge ${signatureTypeClass}">${getSignatureTypeText(item)}</span>
|
</div>
|
||||||
${finalAction}
|
</td>
|
||||||
</td>
|
<td class="align-middle">${statusHtml}</td>
|
||||||
</tr>
|
<td class="align-middle"><span class="small" title="${item.userName || ''}">${item.userName || '—'}</span></td>
|
||||||
`;
|
<td class="align-middle">
|
||||||
|
<span class="badge ${signatureTypeClass}">${getSignatureTypeText(item)}</span>
|
||||||
|
${finalAction}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap классы для статусов
|
// Bootstrap классы для статусов
|
||||||
@@ -620,30 +629,88 @@
|
|||||||
|
|
||||||
// Показать историю статусов (Bootstrap модалка)
|
// Показать историю статусов (Bootstrap модалка)
|
||||||
function showStatusHistory(statuses) {
|
function showStatusHistory(statuses) {
|
||||||
const statusItems = statuses.map(status => {
|
if (!statuses || statuses.length === 0) {
|
||||||
const statusInfo = status || {
|
document.getElementById('statusHistoryBody').innerHTML = '<p class="text-muted text-center">Нет истории статусов</p>';
|
||||||
name: `Статус ${status.status}`,
|
if (statusModal) statusModal.show();
|
||||||
description: '',
|
return;
|
||||||
category: 'warning'
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
// Разделяем статусы на общие и по получателям
|
||||||
|
const commonStatuses = statuses.filter(s => s.idPatientMis === null);
|
||||||
|
const recipientStatuses = statuses.filter(s => s.idPatientMis !== null);
|
||||||
|
|
||||||
|
// Группируем статусы по получателям
|
||||||
|
const statusesByRecipient = {};
|
||||||
|
recipientStatuses.forEach(status => {
|
||||||
|
if (status.patient) {
|
||||||
|
const patientName = status.patient.name || 'Неизвестный получатель';
|
||||||
|
if (!statusesByRecipient[patientName]) {
|
||||||
|
statusesByRecipient[patientName] = [];
|
||||||
|
}
|
||||||
|
statusesByRecipient[patientName].push(status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Сортируем получателей по имени
|
||||||
|
const sortedRecipients = Object.keys(statusesByRecipient).sort();
|
||||||
|
|
||||||
|
// Функция для создания HTML статуса
|
||||||
|
const createStatusHtml = (status) => {
|
||||||
return `
|
return `
|
||||||
<div class="d-flex gap-3 mb-3 pb-2 border-bottom">
|
<div class="d-flex gap-3 mb-3 pb-2 border-bottom">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<span class="badge ${getStatusBadgeClass(statusInfo.category)} p-2">
|
<span class="badge ${getStatusBadgeClass(status.category)} p-2">
|
||||||
<i class="bi ${getStatusIcon(statusInfo.category)}"></i>
|
<i class="bi ${getStatusIcon(status.category)}"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<div class="fw-semibold">${statusInfo.name}</div>
|
<div class="fw-semibold">${status.name || status.description || 'Неизвестно'}</div>
|
||||||
<div class="small text-muted mb-1">${statusInfo.description || 'Нет описания'}</div>
|
<div class="small text-muted mb-1">${status.description || ''}</div>
|
||||||
<div class="small text-muted">${formatDateTime(status.created_at)}</div>
|
<div class="small text-muted">${formatDateTime(status.created_at)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Генерируем HTML для общих статусов (сортируем по id для хронологии)
|
||||||
|
const commonStatusesHtml = commonStatuses
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map(createStatusHtml)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
// Генерируем HTML для статусов получателей
|
||||||
|
const recipientStatusesHtml = sortedRecipients.map(recipientName => {
|
||||||
|
const recipientStatusesList = statusesByRecipient[recipientName]
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map(createStatusHtml)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="mt-3 mb-2">
|
||||||
|
<div class="bg-light p-2 rounded">
|
||||||
|
<i class="bi bi-person-circle me-1 text-primary"></i>
|
||||||
|
<span class="fw-semibold">${recipientName}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
${recipientStatusesList}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
document.getElementById('statusHistoryBody').innerHTML = statusItems || '<p class="text-muted text-center">Нет истории статусов</p>';
|
const fullHtml = `
|
||||||
|
<div class="status-history">
|
||||||
|
${commonStatusesHtml}
|
||||||
|
${recipientStatusesHtml ? `
|
||||||
|
<div class="mt-3 pt-2 border-top">
|
||||||
|
<h6 class="mb-3">Статусы получателей</h6>
|
||||||
|
${recipientStatusesHtml}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.getElementById('statusHistoryBody').innerHTML = fullHtml;
|
||||||
|
|
||||||
if (statusModal) {
|
if (statusModal) {
|
||||||
statusModal.show();
|
statusModal.show();
|
||||||
@@ -663,8 +730,12 @@
|
|||||||
|
|
||||||
// Создаем тост
|
// Создаем тост
|
||||||
const toastId = 'toast-' + Date.now();
|
const toastId = 'toast-' + Date.now();
|
||||||
|
const bgClass = type === 'success' ? 'bg-success' :
|
||||||
|
type === 'danger' ? 'bg-danger' :
|
||||||
|
type === 'warning' ? 'bg-warning' : 'bg-info';
|
||||||
|
|
||||||
const toastHtml = `
|
const toastHtml = `
|
||||||
<div id="${toastId}" class="toast align-items-center text-white bg-${type} border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
<div id="${toastId}" class="toast align-items-center text-white ${bgClass} border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="toast-body">
|
<div class="toast-body">
|
||||||
${message}
|
${message}
|
||||||
@@ -677,7 +748,7 @@
|
|||||||
toastContainer.insertAdjacentHTML('beforeend', toastHtml);
|
toastContainer.insertAdjacentHTML('beforeend', toastHtml);
|
||||||
|
|
||||||
const toastElement = document.getElementById(toastId);
|
const toastElement = document.getElementById(toastId);
|
||||||
const toast = new bootstrap.Toast(toastElement, { autohide: true, delay: 5000 });
|
const toast = new bootstrap.Toast(toastElement, { autohide: true, delay: 3000 });
|
||||||
toast.show();
|
toast.show();
|
||||||
|
|
||||||
// Удаляем после скрытия
|
// Удаляем после скрытия
|
||||||
|
|||||||
+389
-23
@@ -197,6 +197,19 @@
|
|||||||
const inProgress = preSingingData.inProgress || [];
|
const inProgress = preSingingData.inProgress || [];
|
||||||
const complete = preSingingData.complete || [];
|
const complete = preSingingData.complete || [];
|
||||||
const daysRemainingControl = preSingingData.daysRemainingControl || 30;
|
const daysRemainingControl = preSingingData.daysRemainingControl || 30;
|
||||||
|
const deliveryType = preSingingData.deliveryType || ["sms"];
|
||||||
|
const multipleSending = preSingingData.multipleSending || false;
|
||||||
|
|
||||||
|
// Массив получателей (только если multipleSending = true)
|
||||||
|
let recipients = [];
|
||||||
|
|
||||||
|
// Маппинг типов доставки на отображаемые названия
|
||||||
|
const deliveryTypeLabels = {
|
||||||
|
'sms': 'СМС-сообщение',
|
||||||
|
'max': 'МАХ-сообщение',
|
||||||
|
'mila': 'Mila-сообщение',
|
||||||
|
'goskey': 'Goskey-сообщение'
|
||||||
|
};
|
||||||
|
|
||||||
// Определяем тип документов
|
// Определяем тип документов
|
||||||
const hasIds = documents.some(doc => doc.title.includes('ИДС'));
|
const hasIds = documents.some(doc => doc.title.includes('ИДС'));
|
||||||
@@ -309,7 +322,7 @@
|
|||||||
|
|
||||||
const dialog = document.createElement('div');
|
const dialog = document.createElement('div');
|
||||||
dialog.className = 'el-dialog';
|
dialog.className = 'el-dialog';
|
||||||
dialog.style.cssText = 'margin-top: 15vh; width: 700px; z-index: 2002; position: relative; margin: 15vh auto 50px; background: #fff; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);';
|
dialog.style.cssText = 'margin-top: 15vh; width: 750px; z-index: 2002; position: relative; margin: 15vh auto 50px; background: #fff; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);';
|
||||||
|
|
||||||
// Создаем заголовок
|
// Создаем заголовок
|
||||||
const dialogHeader = document.createElement('div');
|
const dialogHeader = document.createElement('div');
|
||||||
@@ -335,7 +348,7 @@
|
|||||||
// Создаем тело диалога
|
// Создаем тело диалога
|
||||||
const dialogBody = document.createElement('div');
|
const dialogBody = document.createElement('div');
|
||||||
dialogBody.className = 'el-dialog__body';
|
dialogBody.className = 'el-dialog__body';
|
||||||
dialogBody.style.cssText = 'padding: 15px; color: #606266; font-size: 14px;';
|
dialogBody.style.cssText = 'padding: 15px; padding-bottom: 0; color: #606266; font-size: 14px;';
|
||||||
|
|
||||||
// Создаем контент
|
// Создаем контент
|
||||||
const dialogContent = document.createElement('div');
|
const dialogContent = document.createElement('div');
|
||||||
@@ -492,12 +505,275 @@
|
|||||||
documentsSection.appendChild(documentsList);
|
documentsSection.appendChild(documentsList);
|
||||||
|
|
||||||
dialogContent.appendChild(documentsSection);
|
dialogContent.appendChild(documentsSection);
|
||||||
|
|
||||||
|
// ========== НАЧАЛО: Блок дополнительных получателей (только при multipleSending=true) ==========
|
||||||
|
if (multipleSending) {
|
||||||
|
// Функция рендеринга блока получателей (будет вызываться при изменениях)
|
||||||
|
function renderRecipientsBlock() {
|
||||||
|
// Удаляем старый контейнер, если он есть
|
||||||
|
const oldContainer = dialogContent.querySelector('.recipients-container');
|
||||||
|
if (oldContainer) {
|
||||||
|
oldContainer.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если получателей нет - не отображаем блок
|
||||||
|
if (recipients.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipientsContainer = document.createElement('div');
|
||||||
|
recipientsContainer.className = 'recipients-container';
|
||||||
|
recipientsContainer.style.cssText = 'margin-top: 15px; margin-bottom: 0px;';
|
||||||
|
|
||||||
|
// Заголовок с количеством получателей
|
||||||
|
const recipientsHeader = document.createElement('div');
|
||||||
|
recipientsHeader.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const recipientsTitle = document.createElement('h4');
|
||||||
|
recipientsTitle.style.cssText = 'margin: 0; color: #303133; font-size: 14px; font-weight: 500;';
|
||||||
|
recipientsTitle.textContent = 'Дополнительные получатели:';
|
||||||
|
|
||||||
|
const recipientsCount = document.createElement('span');
|
||||||
|
recipientsCount.className = 'el-tag el-tag--info el-tag--mini';
|
||||||
|
recipientsCount.style.cssText = 'margin-left: 6px;';
|
||||||
|
recipientsCount.textContent = recipients.length;
|
||||||
|
|
||||||
|
const titleWrapper = document.createElement('div');
|
||||||
|
titleWrapper.style.cssText = 'display: flex; align-items: center;';
|
||||||
|
titleWrapper.appendChild(recipientsTitle);
|
||||||
|
titleWrapper.appendChild(recipientsCount);
|
||||||
|
|
||||||
|
recipientsHeader.appendChild(titleWrapper);
|
||||||
|
|
||||||
|
// Компактный список получателей
|
||||||
|
const recipientsList = document.createElement('div');
|
||||||
|
recipientsList.className = 'recipients-list';
|
||||||
|
recipientsList.style.cssText = 'display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px;';
|
||||||
|
|
||||||
|
recipients.forEach((recipient, index) => {
|
||||||
|
const recipientTag = document.createElement('span');
|
||||||
|
recipientTag.className = 'el-tag el-tag--info el-tag--small';
|
||||||
|
recipientTag.style.cssText = 'display: inline-flex; align-items: center; height: 24px; line-height: 22px; padding: 0 8px; margin-right: 4px; margin-bottom: 4px;';
|
||||||
|
|
||||||
|
const nameSpan = document.createElement('span');
|
||||||
|
nameSpan.textContent = `${recipient.surname} ${recipient.name.charAt(0)}. ${recipient.secondName ? recipient.secondName.charAt(0) + '.' : ''}`;
|
||||||
|
|
||||||
|
const closeIcon = document.createElement('i');
|
||||||
|
closeIcon.className = 'el-icon-close';
|
||||||
|
closeIcon.style.cssText = 'margin-left: 4px; cursor: pointer; font-size: 12px;';
|
||||||
|
closeIcon.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (window.confirm(`Удалить получателя ${recipient.surname} ${recipient.name}?`)) {
|
||||||
|
recipients.splice(index, 1);
|
||||||
|
renderRecipientsBlock(); // Перерисовываем блок
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recipientTag.appendChild(nameSpan);
|
||||||
|
recipientTag.appendChild(closeIcon);
|
||||||
|
recipientsList.appendChild(recipientTag);
|
||||||
|
});
|
||||||
|
|
||||||
|
recipientsContainer.appendChild(recipientsHeader);
|
||||||
|
recipientsContainer.appendChild(recipientsList);
|
||||||
|
|
||||||
|
// Вставляем после списка документов
|
||||||
|
dialogContent.insertBefore(recipientsContainer, documentsSection.nextSibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Кнопка добавления получателя
|
||||||
|
const addButtonContainer = document.createElement('div');
|
||||||
|
addButtonContainer.style.cssText = 'margin: 10px 0;';
|
||||||
|
|
||||||
|
const addRecipientBtn = document.createElement('button');
|
||||||
|
addRecipientBtn.type = 'button';
|
||||||
|
addRecipientBtn.className = 'el-button m-button el-button--success el-button--small is-plain button-with-icon';
|
||||||
|
if (!canSend) {
|
||||||
|
addRecipientBtn.classList.add('is-disabled');
|
||||||
|
addRecipientBtn.disabled = true;
|
||||||
|
}
|
||||||
|
addRecipientBtn.innerHTML = '<i class="m-icon fa-plus button-icon fad fa-fw" style="font-size: 17px;"></i> Добавить получателя';
|
||||||
|
|
||||||
|
addButtonContainer.appendChild(addRecipientBtn);
|
||||||
|
dialogContent.appendChild(addButtonContainer);
|
||||||
|
|
||||||
|
// Контейнер для аккордеона (поиск получателей)
|
||||||
|
const searchAccordion = document.createElement('div');
|
||||||
|
searchAccordion.className = 'search-accordion';
|
||||||
|
searchAccordion.style.cssText = 'margin-top: 10px; display: none;';
|
||||||
|
|
||||||
|
const searchCard = document.createElement('div');
|
||||||
|
searchCard.className = 'el-card';
|
||||||
|
searchCard.style.cssText = 'border: 1px solid #EBEEF5; border-radius: 4px;';
|
||||||
|
|
||||||
|
const searchBody = document.createElement('div');
|
||||||
|
searchBody.className = 'el-card__body';
|
||||||
|
searchBody.style.cssText = 'padding: 12px;';
|
||||||
|
|
||||||
|
// Поле ввода номера телефона и кнопка поиска
|
||||||
|
const searchRow = document.createElement('div');
|
||||||
|
searchRow.style.cssText = 'display: flex; gap: 8px; margin-bottom: 10px;';
|
||||||
|
|
||||||
|
const phoneInput = document.createElement('input');
|
||||||
|
phoneInput.type = 'text';
|
||||||
|
phoneInput.placeholder = 'Введите номер телефона';
|
||||||
|
phoneInput.className = 'el-input__inner';
|
||||||
|
phoneInput.style.cssText = 'flex: 1; height: 28px; line-height: 28px; border: 1px solid #DCDFE6; border-radius: 4px; padding: 0 8px; font-size: 12px;';
|
||||||
|
|
||||||
|
const searchBtn = document.createElement('button');
|
||||||
|
searchBtn.type = 'button';
|
||||||
|
searchBtn.className = 'el-button m-button el-button--primary el-button--small is-plain button-with-icon';
|
||||||
|
searchBtn.innerHTML = '<i class="m-icon fa-search button-icon fad fa-fw" style="font-size: 17px;"></i> Найти';
|
||||||
|
searchBtn.style.cssText = 'height: 28px;';
|
||||||
|
|
||||||
|
searchRow.appendChild(phoneInput);
|
||||||
|
searchRow.appendChild(searchBtn);
|
||||||
|
|
||||||
|
// Контейнер для результатов поиска
|
||||||
|
const searchResults = document.createElement('div');
|
||||||
|
searchResults.className = 'search-results';
|
||||||
|
searchResults.style.cssText = 'max-height: 150px; overflow-y: auto; font-size: 12px;';
|
||||||
|
|
||||||
|
// Кнопка отмены
|
||||||
|
const cancelSearchBtn = document.createElement('button');
|
||||||
|
cancelSearchBtn.type = 'button';
|
||||||
|
cancelSearchBtn.className = 'el-button m-button el-button--small is-plain button-with-icon cancel-button';
|
||||||
|
|
||||||
|
const cancelSearchIcon = document.createElement('i');
|
||||||
|
cancelSearchIcon.className = 'm-icon fa-times button-icon fad';
|
||||||
|
cancelSearchIcon.style.cssText = 'font-size: 14px; margin-right: 6px;';
|
||||||
|
|
||||||
|
const cancelSearchText = document.createElement('span');
|
||||||
|
cancelSearchText.textContent = 'Отмена';
|
||||||
|
|
||||||
|
cancelSearchBtn.appendChild(cancelSearchIcon);
|
||||||
|
cancelSearchBtn.appendChild(cancelSearchText);
|
||||||
|
|
||||||
|
searchBody.appendChild(searchRow);
|
||||||
|
searchBody.appendChild(searchResults);
|
||||||
|
searchBody.appendChild(cancelSearchBtn);
|
||||||
|
searchCard.appendChild(searchBody);
|
||||||
|
searchAccordion.appendChild(searchCard);
|
||||||
|
|
||||||
|
dialogContent.appendChild(searchAccordion);
|
||||||
|
|
||||||
|
// Функция поиска получателей по номеру телефона
|
||||||
|
async function searchRecipients(phone) {
|
||||||
|
if (!phone || phone.trim() === '') {
|
||||||
|
showMessage('Введите номер телефона', 'info');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем загрузку
|
||||||
|
searchResults.innerHTML = '<div style="text-align: center; padding: 15px;"><i class="el-icon-loading" style="font-size: 18px;"></i><p style="margin: 5px 0 0; color: #909399;">Поиск...</p></div>';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await sendMessageToContent('searchRecipients', {
|
||||||
|
phone: phone.trim()
|
||||||
|
});
|
||||||
|
|
||||||
|
searchResults.innerHTML = '';
|
||||||
|
|
||||||
|
if (result && result.success && result.data && result.data.length > 0) {
|
||||||
|
result.data.forEach(person => {
|
||||||
|
const personItem = document.createElement('div');
|
||||||
|
personItem.style.cssText = 'display: flex; justify-content: space-between; align-items: center; padding: 6px 0; border-bottom: 1px solid #F0F0F0;';
|
||||||
|
|
||||||
|
const personInfo = document.createElement('div');
|
||||||
|
personInfo.style.cssText = 'flex: 1;';
|
||||||
|
|
||||||
|
const fullName = document.createElement('span');
|
||||||
|
fullName.style.cssText = 'font-size: 12px; color: #606266;';
|
||||||
|
fullName.textContent = `${person.surname} ${person.name} ${person.secondName || ''}`.trim();
|
||||||
|
|
||||||
|
const birthdate = document.createElement('span');
|
||||||
|
birthdate.style.cssText = 'font-size: 11px; color: #909399; margin-left: 6px;';
|
||||||
|
birthdate.textContent = person.birthDate ? `(${person.birthDate})` : '';
|
||||||
|
|
||||||
|
personInfo.appendChild(fullName);
|
||||||
|
personInfo.appendChild(birthdate);
|
||||||
|
|
||||||
|
const addBtn = document.createElement('button');
|
||||||
|
addBtn.type = 'button';
|
||||||
|
addBtn.className = 'el-button el-button--primary el-button--mini';
|
||||||
|
addBtn.innerHTML = 'Добавить';
|
||||||
|
addBtn.style.cssText = 'height: 24px; padding: 0 8px;';
|
||||||
|
|
||||||
|
// Проверяем, не добавлен ли уже этот получатель
|
||||||
|
const alreadyAdded = recipients.some(r => r.id === person.id);
|
||||||
|
if (alreadyAdded) {
|
||||||
|
addBtn.disabled = true;
|
||||||
|
addBtn.classList.add('is-disabled');
|
||||||
|
addBtn.innerHTML = 'Добавлен';
|
||||||
|
}
|
||||||
|
|
||||||
|
addBtn.addEventListener('click', () => {
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
recipients.push(person);
|
||||||
|
renderRecipientsBlock(); // Обновляем отображение блока получателей
|
||||||
|
// Закрываем аккордеон
|
||||||
|
searchAccordion.style.display = 'none';
|
||||||
|
// Очищаем поле ввода и результаты
|
||||||
|
phoneInput.value = '';
|
||||||
|
searchResults.innerHTML = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
personItem.appendChild(personInfo);
|
||||||
|
personItem.appendChild(addBtn);
|
||||||
|
searchResults.appendChild(personItem);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
searchResults.innerHTML = '<div style="text-align: center; padding: 15px; color: #909399;">Ничего не найдено</div>';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка поиска получателей:', error);
|
||||||
|
searchResults.innerHTML = '<div class="el-alert el-alert--error" style="margin: 5px 0;"><div class="el-alert__content"><span class="el-alert__title">Ошибка поиска</span><p class="el-alert__description">' + error.message + '</p></div></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик кнопки добавления получателя
|
||||||
|
addRecipientBtn.addEventListener('click', () => {
|
||||||
|
if (searchAccordion.style.display === 'none' || searchAccordion.style.display === '') {
|
||||||
|
searchAccordion.style.display = 'block';
|
||||||
|
phoneInput.value = '';
|
||||||
|
searchResults.innerHTML = '';
|
||||||
|
phoneInput.focus();
|
||||||
|
} else {
|
||||||
|
searchAccordion.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработчик кнопки поиска
|
||||||
|
searchBtn.addEventListener('click', () => {
|
||||||
|
searchRecipients(phoneInput.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Поиск при нажатии Enter
|
||||||
|
phoneInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
searchRecipients(phoneInput.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработчик кнопки отмены
|
||||||
|
cancelSearchBtn.addEventListener('click', () => {
|
||||||
|
searchAccordion.style.display = 'none';
|
||||||
|
phoneInput.value = '';
|
||||||
|
searchResults.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Инициализация - рендерим блок (если есть получатели)
|
||||||
|
renderRecipientsBlock();
|
||||||
|
}
|
||||||
|
// ========== КОНЕЦ: Блок дополнительных получателей ==========
|
||||||
|
|
||||||
dialogBody.appendChild(dialogContent);
|
dialogBody.appendChild(dialogContent);
|
||||||
|
|
||||||
// Создаем футер
|
// Создаем футер
|
||||||
const dialogFooter = document.createElement('div');
|
const dialogFooter = document.createElement('div');
|
||||||
dialogFooter.className = 'el-dialog__footer';
|
dialogFooter.className = 'el-dialog__footer';
|
||||||
dialogFooter.style.cssText = 'display: flex; justify-content: space-between; align-items: center;';
|
dialogFooter.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; padding: 15px; padding-top: 10px;';
|
||||||
|
|
||||||
// Левая часть футера (информация о сроке действия разрешения на подпись)
|
// Левая часть футера (информация о сроке действия разрешения на подпись)
|
||||||
const footerLeft = document.createElement('div');
|
const footerLeft = document.createElement('div');
|
||||||
@@ -506,7 +782,7 @@
|
|||||||
if (signature.expiration && signature.type) {
|
if (signature.expiration && signature.type) {
|
||||||
// Тип разрешения
|
// Тип разрешения
|
||||||
const typeContainer = document.createElement('div');
|
const typeContainer = document.createElement('div');
|
||||||
typeContainer.style.cssText = 'margin-bottom: 5px; margin-top: 0px;';
|
typeContainer.style.cssText = 'margin-bottom: 5px; margin-top: 10px;';
|
||||||
|
|
||||||
const typeText = document.createElement('span');
|
const typeText = document.createElement('span');
|
||||||
typeText.style.cssText = 'font-size: 12px; font-weight: 500; color: #606266;';
|
typeText.style.cssText = 'font-size: 12px; font-weight: 500; color: #606266;';
|
||||||
@@ -534,8 +810,8 @@
|
|||||||
expirationContainer.appendChild(expirationLabel);
|
expirationContainer.appendChild(expirationLabel);
|
||||||
expirationContainer.appendChild(expirationDate);
|
expirationContainer.appendChild(expirationDate);
|
||||||
|
|
||||||
// Остаточный срок (показываем справа от даты если меньше 30 дней)
|
// Остаточный срок (показываем справа от даты если недостаточно дней)
|
||||||
if (daysRemaining >= 0 && daysRemaining < 30) {
|
if (daysRemaining >= 0 && daysRemaining < daysRemainingControl) {
|
||||||
const warningIcon = document.createElement('i');
|
const warningIcon = document.createElement('i');
|
||||||
warningIcon.className = 'el-icon-warning';
|
warningIcon.className = 'el-icon-warning';
|
||||||
warningIcon.style.cssText = 'font-size: 14px; color: #e6a23c; margin-left: 4px; margin-right: 4px;';
|
warningIcon.style.cssText = 'font-size: 14px; color: #e6a23c; margin-left: 4px; margin-right: 4px;';
|
||||||
@@ -570,10 +846,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Правая часть футера (кнопки)
|
// Правая часть футера (выбор способа доставки и кнопки)
|
||||||
const footerRight = document.createElement('div');
|
const footerRight = document.createElement('div');
|
||||||
footerRight.className = 'dialog-footer';
|
footerRight.style.cssText = 'display: flex; flex-direction: column; align-items: flex-end;';
|
||||||
footerRight.style.cssText = 'display: flex; align-items: center; padding-top: 10px;';
|
|
||||||
|
const deliveryBlock = document.createElement('div');
|
||||||
|
deliveryBlock.style.cssText = 'margin-bottom: 10px; width: 210px;';
|
||||||
|
|
||||||
|
const selectWrapper = document.createElement('div');
|
||||||
|
selectWrapper.style.cssText = `
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: ${canSend ? 'white' : '#f5f7fa'};
|
||||||
|
transition: all 0.2s;
|
||||||
|
width: 100%;
|
||||||
|
opacity: ${canSend ? '1' : '0.6'};
|
||||||
|
pointer-events: ${canSend ? 'auto' : 'none'};
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Создаем select элемент
|
||||||
|
const deliverySelect = document.createElement('select');
|
||||||
|
deliverySelect.style.cssText = `
|
||||||
|
width: 100%;
|
||||||
|
height: 25px;
|
||||||
|
padding: 3px 24px 3px 8px;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${canSend ? '#606266' : '#c0c4cc'};
|
||||||
|
outline: none;
|
||||||
|
cursor: ${canSend ? 'pointer' : 'not-allowed'};
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = null;
|
||||||
|
option.textContent = "Способ отправки";
|
||||||
|
option.selected = true;
|
||||||
|
option.disabled = true;
|
||||||
|
deliverySelect.appendChild(option);
|
||||||
|
|
||||||
|
// Добавляем опции выбора на основе доступных типов доставки
|
||||||
|
deliveryType.forEach(type => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = type;
|
||||||
|
option.textContent = deliveryTypeLabels[type] || type;
|
||||||
|
deliverySelect.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Сохраняем выбранное значение
|
||||||
|
let selectedDeliveryType = null;
|
||||||
|
|
||||||
|
// Обработчик изменения выбора
|
||||||
|
deliverySelect.addEventListener('change', (e) => {
|
||||||
|
selectedDeliveryType = e.target.value;
|
||||||
|
updateSendButtonState();
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectArrow = document.createElement('span');
|
||||||
|
selectArrow.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
pointer-events: none;
|
||||||
|
color: ${canSend ? '#c0c4cc' : '#dcdfe6'};
|
||||||
|
font-size: 12px;
|
||||||
|
`;
|
||||||
|
selectArrow.textContent = '▼';
|
||||||
|
|
||||||
|
selectWrapper.appendChild(deliverySelect);
|
||||||
|
selectWrapper.appendChild(selectArrow);
|
||||||
|
|
||||||
|
deliveryBlock.appendChild(selectWrapper);
|
||||||
|
|
||||||
|
// Блок кнопок
|
||||||
|
const buttonsBlock = document.createElement('div');
|
||||||
|
buttonsBlock.className = 'dialog-footer';
|
||||||
|
buttonsBlock.style.cssText = 'display: flex; align-items: center; gap: 5px;';
|
||||||
|
|
||||||
// Кнопка "Отмена" - стиль как у кнопки на главной странице
|
// Кнопка "Отмена" - стиль как у кнопки на главной странице
|
||||||
const cancelBtn = document.createElement('button');
|
const cancelBtn = document.createElement('button');
|
||||||
@@ -594,10 +948,19 @@
|
|||||||
const sendBtn = document.createElement('button');
|
const sendBtn = document.createElement('button');
|
||||||
sendBtn.type = 'button';
|
sendBtn.type = 'button';
|
||||||
|
|
||||||
if (canSend) {
|
// Функция обновления состояния кнопки отправки
|
||||||
sendBtn.className = 'el-button m-button el-button--small is-plain send-button button-with-icon';
|
function updateSendButtonState() {
|
||||||
} else {
|
const canSendWithDelivery = canSend && selectedDeliveryType !== null;
|
||||||
sendBtn.className = 'el-button m-button el-button--small is-plain send-button button-with-icon is-disabled';
|
|
||||||
|
if (canSendWithDelivery) {
|
||||||
|
sendBtn.className = 'el-button m-button el-button--small is-plain send-button button-with-icon';
|
||||||
|
sendBtn.disabled = false;
|
||||||
|
sendBtn.classList.remove('is-disabled');
|
||||||
|
} else {
|
||||||
|
sendBtn.className = 'el-button m-button el-button--small is-plain send-button button-with-icon is-disabled';
|
||||||
|
sendBtn.disabled = true;
|
||||||
|
sendBtn.classList.add('is-disabled');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendIcon = document.createElement('i');
|
const sendIcon = document.createElement('i');
|
||||||
@@ -610,10 +973,14 @@
|
|||||||
sendBtn.appendChild(sendIcon);
|
sendBtn.appendChild(sendIcon);
|
||||||
sendBtn.appendChild(sendText);
|
sendBtn.appendChild(sendText);
|
||||||
|
|
||||||
sendBtn.disabled = !canSend;
|
// Устанавливаем начальное состояние кнопки
|
||||||
|
updateSendButtonState();
|
||||||
|
|
||||||
footerRight.appendChild(cancelBtn);
|
buttonsBlock.appendChild(cancelBtn);
|
||||||
footerRight.appendChild(sendBtn);
|
buttonsBlock.appendChild(sendBtn);
|
||||||
|
|
||||||
|
footerRight.appendChild(deliveryBlock);
|
||||||
|
footerRight.appendChild(buttonsBlock);
|
||||||
|
|
||||||
dialogFooter.appendChild(footerLeft);
|
dialogFooter.appendChild(footerLeft);
|
||||||
dialogFooter.appendChild(footerRight);
|
dialogFooter.appendChild(footerRight);
|
||||||
@@ -630,16 +997,18 @@
|
|||||||
|
|
||||||
// Обработчик отправки
|
// Обработчик отправки
|
||||||
async function handleSend() {
|
async function handleSend() {
|
||||||
if (!canSend) return;
|
if (!canSend || selectedDeliveryType === null) return;
|
||||||
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
// Отправляем документы на подписание
|
// Отправляем документы на подписание с выбранным типом доставки
|
||||||
try {
|
try {
|
||||||
const docNumbers = documents.map(doc => parseInt(doc.number, 10));
|
const docNumbers = documents.map(doc => parseInt(doc.number, 10));
|
||||||
|
|
||||||
const result = await sendMessageToContent('sendDocuments', {
|
const result = await sendMessageToContent('sendDocuments', {
|
||||||
docNumbers: docNumbers
|
docNumbers: docNumbers,
|
||||||
|
deliveryType: selectedDeliveryType,
|
||||||
|
recipients: recipients
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result && result.response) {
|
if (result && result.response) {
|
||||||
@@ -664,9 +1033,7 @@
|
|||||||
cancelBtn.addEventListener('click', closeModal);
|
cancelBtn.addEventListener('click', closeModal);
|
||||||
backdrop.addEventListener('click', closeModal);
|
backdrop.addEventListener('click', closeModal);
|
||||||
|
|
||||||
if (canSend) {
|
sendBtn.addEventListener('click', handleSend);
|
||||||
sendBtn.addEventListener('click', handleSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Закрытие по ESC
|
// Закрытие по ESC
|
||||||
const escHandler = (e) => {
|
const escHandler = (e) => {
|
||||||
@@ -724,7 +1091,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Функция добавления кнопки
|
// Функция добавления кнопки
|
||||||
function addSendBtn() {
|
function addSendBtn() {
|
||||||
const sendBtn = document.createElement('button');
|
const sendBtn = document.createElement('button');
|
||||||
|
|||||||
Reference in New Issue
Block a user