календарь для документов
This commit is contained in:
@@ -89,7 +89,7 @@ function showMainInterface() {
|
||||
|
||||
// Функция для перезагрузки всех скриптов
|
||||
function reloadAllScripts() {
|
||||
console.log('🔄 Перезагрузка всех скриптов после авторизации...');
|
||||
//console.log('🔄 Перезагрузка всех скриптов после авторизации...');
|
||||
|
||||
// Список скриптов для перезагрузки (в правильном порядке)
|
||||
const scriptsToReload = [
|
||||
@@ -134,7 +134,7 @@ function loadScriptsSequentially(scripts, index) {
|
||||
const script = document.createElement('script');
|
||||
script.src = scripts[index];
|
||||
script.onload = () => {
|
||||
console.log(`✅ Загружен: ${scripts[index]}`);
|
||||
// console.log(`✅ Загружен: ${scripts[index]}`);
|
||||
loadScriptsSequentially(scripts, index + 1);
|
||||
};
|
||||
script.onerror = (error) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// document-fields.js - Скрипт для управления полями документа в задачах
|
||||
// Показывает кнопку "Реквизиты" только для задач с типом "document" и только когда задача раскрыта
|
||||
// Показывает кнопку "Реквизиты" только для задач с типом "document",
|
||||
// только когда задача раскрыта и только для пользователей из групп "Подписант" или "Секретарь"
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
@@ -7,6 +8,10 @@
|
||||
// Конфигурация
|
||||
const CONFIG = {
|
||||
modalId: 'documentFieldsModal',
|
||||
signerGroup: 'Подписант',
|
||||
secretaryGroup: 'Секретарь',
|
||||
apiEndpoint: '/api2/idusers',
|
||||
usersEndpoint: '/api/users',
|
||||
modalStyles: `
|
||||
<style>
|
||||
.document-fields-modal {
|
||||
@@ -81,6 +86,7 @@
|
||||
|
||||
.document-field-group {
|
||||
margin-bottom: 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.document-field-group label {
|
||||
@@ -111,6 +117,150 @@
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Стили для поля с календарем */
|
||||
.date-input-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date-input-wrapper input {
|
||||
padding-right: 40px;
|
||||
}
|
||||
|
||||
.calendar-icon {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: background-color 0.2s;
|
||||
user-select: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.calendar-icon:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
/* Календарь */
|
||||
.inline-calendar {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
z-index: 1000;
|
||||
margin-top: 5px;
|
||||
padding: 10px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.calendar-month-year {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.calendar-nav {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.calendar-nav button {
|
||||
background: none;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.calendar-nav button:hover {
|
||||
background-color: #f0f0f0;
|
||||
border-color: #999;
|
||||
}
|
||||
|
||||
.calendar-weekdays {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.calendar-weekday {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.calendar-days {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.calendar-day {
|
||||
aspect-ratio: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.calendar-day:hover {
|
||||
background-color: #e8f5e9;
|
||||
}
|
||||
|
||||
.calendar-day.selected {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-day.today {
|
||||
border: 1px solid #4CAF50;
|
||||
}
|
||||
|
||||
.calendar-day.empty {
|
||||
cursor: default;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.calendar-day.empty:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.document-fields-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
@@ -257,6 +407,9 @@
|
||||
// Текущий пользователь
|
||||
let currentUser = null;
|
||||
|
||||
// Группы пользователя (все группы из разных источников)
|
||||
let userGroups = [];
|
||||
|
||||
// Кэш для типов задач
|
||||
const taskTypeCache = new Map();
|
||||
|
||||
@@ -272,6 +425,14 @@
|
||||
'.task-content.expanded'
|
||||
];
|
||||
|
||||
// Состояние календаря
|
||||
let calendarState = {
|
||||
currentDate: new Date(),
|
||||
selectedDate: null,
|
||||
isOpen: false,
|
||||
inputElement: null
|
||||
};
|
||||
|
||||
// Получение текущего пользователя
|
||||
async function getCurrentUser() {
|
||||
try {
|
||||
@@ -283,6 +444,9 @@
|
||||
if (data.user) {
|
||||
currentUser = data.user;
|
||||
console.log('✅ DocumentFields: текущий пользователь', currentUser.login);
|
||||
|
||||
// Получаем все группы пользователя
|
||||
await getAllUserGroups(currentUser.login || currentUser.id);
|
||||
}
|
||||
return currentUser;
|
||||
} catch (error) {
|
||||
@@ -291,6 +455,291 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Получение ВСЕХ групп пользователя из разных источников
|
||||
async function getAllUserGroups(userLogin) {
|
||||
const allGroups = new Set();
|
||||
|
||||
try {
|
||||
// 1. Пробуем получить через API /api2/idusers
|
||||
await fetchGroupsFromApi2(userLogin, allGroups);
|
||||
|
||||
// 2. Пробуем получить через API /api/users
|
||||
await fetchGroupsFromUsersApi(userLogin, allGroups);
|
||||
|
||||
// 3. Проверяем, есть ли группы в currentUser
|
||||
if (currentUser) {
|
||||
addGroupsFromCurrentUser(allGroups);
|
||||
}
|
||||
|
||||
// Преобразуем Set в массив и сохраняем
|
||||
userGroups = Array.from(allGroups);
|
||||
|
||||
console.log('✅ DocumentFields: ВСЕ группы пользователя:', userGroups);
|
||||
|
||||
// Детальный вывод для отладки
|
||||
console.log('🔍 Проверка доступа:');
|
||||
console.log(' - Группы:', userGroups);
|
||||
console.log(' - Ищем "Подписант":', userGroups.some(g =>
|
||||
g.toLowerCase().includes(CONFIG.signerGroup.toLowerCase())));
|
||||
console.log(' - Ищем "Секретарь":', userGroups.some(g =>
|
||||
g.toLowerCase().includes(CONFIG.secretaryGroup.toLowerCase())));
|
||||
|
||||
return userGroups;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ DocumentFields: ошибка получения групп', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Получение групп из /api2/idusers
|
||||
async function fetchGroupsFromApi2(userLogin, groupsSet) {
|
||||
try {
|
||||
const response = await fetch(`${CONFIG.apiEndpoint}?login=${userLogin}`);
|
||||
if (!response.ok) {
|
||||
console.warn('⚠️ DocumentFields: API /api2/idusers вернул ошибку', response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('📦 Данные из /api2/idusers:', data);
|
||||
|
||||
// Обрабатываем массив пользователей
|
||||
if (Array.isArray(data)) {
|
||||
const userData = data.find(u =>
|
||||
u.login === userLogin ||
|
||||
u.user_login === userLogin ||
|
||||
u.name === userLogin ||
|
||||
u.user_name === userLogin
|
||||
);
|
||||
|
||||
if (userData) {
|
||||
extractGroupsFromUserData(userData, groupsSet);
|
||||
}
|
||||
}
|
||||
// Обрабатываем объект пользователя
|
||||
else if (data && typeof data === 'object') {
|
||||
extractGroupsFromUserData(data, groupsSet);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ DocumentFields: ошибка fetchGroupsFromApi2', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Получение групп из /api/users
|
||||
async function fetchGroupsFromUsersApi(userLogin, groupsSet) {
|
||||
try {
|
||||
const response = await fetch(`${CONFIG.usersEndpoint}?login=${userLogin}`);
|
||||
if (!response.ok) {
|
||||
console.warn('⚠️ DocumentFields: API /api/users вернул ошибку', response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('📦 Данные из /api/users:', data);
|
||||
|
||||
// Обрабатываем данные в зависимости от формата
|
||||
if (Array.isArray(data)) {
|
||||
const userData = data.find(u =>
|
||||
u.login === userLogin ||
|
||||
u.username === userLogin ||
|
||||
u.email === userLogin
|
||||
);
|
||||
|
||||
if (userData) {
|
||||
extractGroupsFromUserData(userData, groupsSet);
|
||||
}
|
||||
} else if (data && typeof data === 'object') {
|
||||
extractGroupsFromUserData(data, groupsSet);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ DocumentFields: ошибка fetchGroupsFromUsersApi', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Извлечение групп из данных пользователя
|
||||
function extractGroupsFromUserData(userData, groupsSet) {
|
||||
if (!userData) return;
|
||||
|
||||
console.log('🔍 Извлекаем группы из:', userData);
|
||||
|
||||
// 1. Проверяем group_name (может быть строкой или массивом)
|
||||
if (userData.group_name) {
|
||||
if (Array.isArray(userData.group_name)) {
|
||||
userData.group_name.forEach(g => {
|
||||
if (g) groupsSet.add(String(g).trim());
|
||||
});
|
||||
} else if (typeof userData.group_name === 'string') {
|
||||
// Может быть строкой с разделителями
|
||||
const groups = userData.group_name.split(/[,;|]/).map(g => g.trim());
|
||||
groups.forEach(g => {
|
||||
if (g) groupsSet.add(g);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Проверяем ldap_group
|
||||
if (userData.ldap_group) {
|
||||
if (Array.isArray(userData.ldap_group)) {
|
||||
userData.ldap_group.forEach(g => {
|
||||
if (g) groupsSet.add(String(g).trim());
|
||||
});
|
||||
} else if (typeof userData.ldap_group === 'string') {
|
||||
groupsSet.add(userData.ldap_group.trim());
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Проверяем metadata.groups
|
||||
if (userData.metadata?.groups) {
|
||||
if (Array.isArray(userData.metadata.groups)) {
|
||||
userData.metadata.groups.forEach(g => {
|
||||
if (g) groupsSet.add(String(g).trim());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Проверяем просто groups (если есть)
|
||||
if (userData.groups) {
|
||||
if (Array.isArray(userData.groups)) {
|
||||
userData.groups.forEach(g => {
|
||||
if (g) groupsSet.add(String(g).trim());
|
||||
});
|
||||
} else if (typeof userData.groups === 'string') {
|
||||
const groups = userData.groups.split(/[,;|]/).map(g => g.trim());
|
||||
groups.forEach(g => {
|
||||
if (g) groupsSet.add(g);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Проверяем roles (если есть)
|
||||
if (userData.roles) {
|
||||
if (Array.isArray(userData.roles)) {
|
||||
userData.roles.forEach(r => {
|
||||
if (r) groupsSet.add(String(r).trim());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Проверяем department (может содержать группу)
|
||||
if (userData.department) {
|
||||
groupsSet.add(String(userData.department).trim());
|
||||
}
|
||||
|
||||
// 7. Проверяем position (может содержать группу)
|
||||
if (userData.position) {
|
||||
groupsSet.add(String(userData.position).trim());
|
||||
}
|
||||
}
|
||||
|
||||
// Добавление групп из currentUser
|
||||
function addGroupsFromCurrentUser(groupsSet) {
|
||||
if (!currentUser) return;
|
||||
|
||||
// Проверяем различные поля в currentUser
|
||||
const fieldsToCheck = [
|
||||
'group',
|
||||
'groups',
|
||||
'role',
|
||||
'roles',
|
||||
'department',
|
||||
'position',
|
||||
'user_group',
|
||||
'user_groups'
|
||||
];
|
||||
|
||||
fieldsToCheck.forEach(field => {
|
||||
if (currentUser[field]) {
|
||||
if (Array.isArray(currentUser[field])) {
|
||||
currentUser[field].forEach(g => {
|
||||
if (g) groupsSet.add(String(g).trim());
|
||||
});
|
||||
} else if (typeof currentUser[field] === 'string') {
|
||||
groupsSet.add(currentUser[field].trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Проверка, имеет ли пользователь доступ (Подписант или Секретарь)
|
||||
function hasUserAccess() {
|
||||
if (!userGroups || userGroups.length === 0) {
|
||||
console.log('❌ DocumentFields: у пользователя нет групп');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Приводим искомые группы к нижнему регистру
|
||||
const signerGroupLower = CONFIG.signerGroup.toLowerCase();
|
||||
const secretaryGroupLower = CONFIG.secretaryGroup.toLowerCase();
|
||||
|
||||
// Проверяем КАЖДУЮ группу пользователя
|
||||
for (const group of userGroups) {
|
||||
if (!group) continue;
|
||||
|
||||
const groupLower = String(group).toLowerCase().trim();
|
||||
|
||||
// Точное совпадение
|
||||
if (groupLower === signerGroupLower || groupLower === secretaryGroupLower) {
|
||||
console.log(`✅ Найдено точное совпадение: "${group}"`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Частичное совпадение (содержит подстроку)
|
||||
if (groupLower.includes(signerGroupLower) || groupLower.includes(secretaryGroupLower)) {
|
||||
console.log(`✅ Найдено частичное совпадение: "${group}" содержит искомую группу`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Совпадение по словам (если группа состоит из нескольких слов)
|
||||
const groupWords = groupLower.split(/[\s\-_]/);
|
||||
const signerWords = signerGroupLower.split(/[\s\-_]/);
|
||||
const secretaryWords = secretaryGroupLower.split(/[\s\-_]/);
|
||||
|
||||
// Проверяем, содержит ли группа все слова из искомой группы
|
||||
const matchesSigner = signerWords.every(word =>
|
||||
groupLower.includes(word) || groupWords.some(gw => gw.includes(word))
|
||||
);
|
||||
|
||||
const matchesSecretary = secretaryWords.every(word =>
|
||||
groupLower.includes(word) || groupWords.some(gw => gw.includes(word))
|
||||
);
|
||||
|
||||
if (matchesSigner || matchesSecretary) {
|
||||
console.log(`✅ Найдено совпадение по словам: "${group}"`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('❌ DocumentFields: пользователь НЕ имеет доступа');
|
||||
console.log(' Группы пользователя:', userGroups);
|
||||
console.log(' Нужные группы:', [CONFIG.signerGroup, CONFIG.secretaryGroup]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Функция для отладки - показывает все группы пользователя
|
||||
function debugUserGroups() {
|
||||
console.log('=== ОТЛАДКА ГРУПП ПОЛЬЗОВАТЕЛЯ ===');
|
||||
console.log('Текущий пользователь:', currentUser);
|
||||
console.log('Все группы:', userGroups);
|
||||
console.log('Ищем "Подписант":', userGroups.filter(g =>
|
||||
g.toLowerCase().includes(CONFIG.signerGroup.toLowerCase())
|
||||
));
|
||||
console.log('Ищем "Секретарь":', userGroups.filter(g =>
|
||||
g.toLowerCase().includes(CONFIG.secretaryGroup.toLowerCase())
|
||||
));
|
||||
console.log('Доступ:', hasUserAccess());
|
||||
console.log('================================');
|
||||
|
||||
return {
|
||||
user: currentUser,
|
||||
groups: userGroups,
|
||||
hasAccess: hasUserAccess()
|
||||
};
|
||||
}
|
||||
|
||||
// Получение типа задачи по ID
|
||||
async function getTaskType(taskId) {
|
||||
// Проверяем кэш
|
||||
@@ -371,6 +820,153 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
// Функции для работы с календарем
|
||||
function formatDate(date) {
|
||||
if (!date) return '';
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
return `${day}.${month}.${year}`;
|
||||
}
|
||||
|
||||
function parseDate(dateStr) {
|
||||
if (!dateStr) return null;
|
||||
const parts = dateStr.split('.');
|
||||
if (parts.length === 3) {
|
||||
const day = parseInt(parts[0], 10);
|
||||
const month = parseInt(parts[1], 10) - 1;
|
||||
const year = parseInt(parts[2], 10);
|
||||
return new Date(year, month, day);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getMonthName(month, year) {
|
||||
const date = new Date(year, month, 1);
|
||||
return date.toLocaleString('ru-RU', { month: 'long' });
|
||||
}
|
||||
|
||||
function generateCalendar(year, month, selectedDate) {
|
||||
const firstDay = new Date(year, month, 1).getDay();
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
// Корректировка первого дня (0 - воскресенье, делаем понедельник первым)
|
||||
let startOffset = firstDay === 0 ? 6 : firstDay - 1;
|
||||
|
||||
const today = new Date();
|
||||
const todayStr = formatDate(today);
|
||||
|
||||
let html = '';
|
||||
let dayCount = 1;
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if (i === 0 && j < startOffset) {
|
||||
html += '<div class="calendar-day empty"></div>';
|
||||
} else if (dayCount <= daysInMonth) {
|
||||
const currentDate = new Date(year, month, dayCount);
|
||||
const dateStr = formatDate(currentDate);
|
||||
const isSelected = selectedDate && dateStr === formatDate(selectedDate);
|
||||
const isToday = dateStr === todayStr;
|
||||
|
||||
html += `<div class="calendar-day ${isSelected ? 'selected' : ''} ${isToday ? 'today' : ''}" onclick="documentFields.selectDate('${dateStr}')">${dayCount}</div>`;
|
||||
dayCount++;
|
||||
} else {
|
||||
html += '<div class="calendar-day empty"></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderCalendar() {
|
||||
const calendar = document.getElementById('inlineCalendar');
|
||||
if (!calendar) return;
|
||||
|
||||
const year = calendarState.currentDate.getFullYear();
|
||||
const month = calendarState.currentDate.getMonth();
|
||||
|
||||
const monthName = getMonthName(month, year);
|
||||
|
||||
let html = `
|
||||
<div class="calendar-header">
|
||||
<div class="calendar-month-year">${monthName} ${year}</div>
|
||||
<div class="calendar-nav">
|
||||
<button onclick="documentFields.prevMonth()">←</button>
|
||||
<button onclick="documentFields.nextMonth()">→</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-weekdays">
|
||||
<div class="calendar-weekday">Пн</div>
|
||||
<div class="calendar-weekday">Вт</div>
|
||||
<div class="calendar-weekday">Ср</div>
|
||||
<div class="calendar-weekday">Чт</div>
|
||||
<div class="calendar-weekday">Пт</div>
|
||||
<div class="calendar-weekday">Сб</div>
|
||||
<div class="calendar-weekday">Вс</div>
|
||||
</div>
|
||||
<div class="calendar-days">
|
||||
${generateCalendar(year, month, calendarState.selectedDate)}
|
||||
</div>
|
||||
`;
|
||||
|
||||
calendar.innerHTML = html;
|
||||
}
|
||||
|
||||
function toggleCalendar() {
|
||||
if (calendarState.isOpen) {
|
||||
closeCalendar();
|
||||
} else {
|
||||
openCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
function openCalendar() {
|
||||
const calendar = document.getElementById('inlineCalendar');
|
||||
if (!calendar) return;
|
||||
|
||||
const dateInput = document.getElementById('documentDate');
|
||||
if (dateInput && dateInput.value) {
|
||||
const parsedDate = parseDate(dateInput.value);
|
||||
if (parsedDate && !isNaN(parsedDate.getTime())) {
|
||||
calendarState.selectedDate = parsedDate;
|
||||
calendarState.currentDate = new Date(parsedDate);
|
||||
}
|
||||
}
|
||||
|
||||
calendarState.isOpen = true;
|
||||
calendar.style.display = 'block';
|
||||
renderCalendar();
|
||||
}
|
||||
|
||||
function closeCalendar() {
|
||||
const calendar = document.getElementById('inlineCalendar');
|
||||
if (calendar) {
|
||||
calendar.style.display = 'none';
|
||||
}
|
||||
calendarState.isOpen = false;
|
||||
}
|
||||
|
||||
function selectDate(dateStr) {
|
||||
const dateInput = document.getElementById('documentDate');
|
||||
if (dateInput) {
|
||||
dateInput.value = dateStr;
|
||||
calendarState.selectedDate = parseDate(dateStr);
|
||||
}
|
||||
closeCalendar();
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
calendarState.currentDate.setMonth(calendarState.currentDate.getMonth() - 1);
|
||||
renderCalendar();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
calendarState.currentDate.setMonth(calendarState.currentDate.getMonth() + 1);
|
||||
renderCalendar();
|
||||
}
|
||||
|
||||
// Создание модального окна
|
||||
function createModal() {
|
||||
if (!document.getElementById('document-fields-styles')) {
|
||||
@@ -411,7 +1007,11 @@
|
||||
|
||||
<div class="document-field-group">
|
||||
<label for="documentDate">Дата документа:</label>
|
||||
<input type="text" id="documentDate" placeholder="ДД.ММ.ГГГГ" maxlength="10">
|
||||
<div class="date-input-wrapper">
|
||||
<input type="text" id="documentDate" placeholder="ДД.ММ.ГГГГ" maxlength="10" readonly>
|
||||
<div class="calendar-icon" onclick="documentFields.toggleCalendar()">📅</div>
|
||||
<div id="inlineCalendar" class="inline-calendar" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document-field-group">
|
||||
@@ -430,6 +1030,18 @@
|
||||
`;
|
||||
|
||||
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
||||
|
||||
// Добавляем обработчик клика вне календаря для его закрытия
|
||||
document.addEventListener('click', function(event) {
|
||||
const calendar = document.getElementById('inlineCalendar');
|
||||
const calendarIcon = document.querySelector('.calendar-icon');
|
||||
|
||||
if (calendar && calendarState.isOpen) {
|
||||
if (!calendar.contains(event.target) && !calendarIcon.contains(event.target)) {
|
||||
closeCalendar();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Открытие модального окна
|
||||
@@ -482,7 +1094,21 @@
|
||||
const dateInput = document.getElementById('documentDate');
|
||||
|
||||
if (numberInput) numberInput.value = result.data.document_n || '';
|
||||
if (dateInput) dateInput.value = result.data.document_d || '';
|
||||
if (dateInput) {
|
||||
dateInput.value = result.data.document_d || '';
|
||||
|
||||
// Устанавливаем выбранную дату в календарь
|
||||
if (result.data.document_d) {
|
||||
const parsedDate = parseDate(result.data.document_d);
|
||||
if (parsedDate && !isNaN(parsedDate.getTime())) {
|
||||
calendarState.selectedDate = parsedDate;
|
||||
calendarState.currentDate = new Date(parsedDate);
|
||||
}
|
||||
} else {
|
||||
calendarState.selectedDate = null;
|
||||
calendarState.currentDate = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
if (result.data.document_a && authorInput && !authorInput.value) {
|
||||
authorInput.value = result.data.document_a;
|
||||
@@ -510,6 +1136,17 @@
|
||||
if (numberInput) numberInput.value = '';
|
||||
if (dateInput) dateInput.value = '';
|
||||
if (authorInput) authorInput.value = '';
|
||||
|
||||
// Закрываем календарь
|
||||
closeCalendar();
|
||||
|
||||
// Сбрасываем состояние календаря
|
||||
calendarState = {
|
||||
currentDate: new Date(),
|
||||
selectedDate: null,
|
||||
isOpen: false,
|
||||
inputElement: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,6 +1300,11 @@
|
||||
async function addButtonToExpandedTask(taskCard) {
|
||||
if (!currentUser) return;
|
||||
|
||||
// Проверяем, имеет ли пользователь доступ (Подписант или Секретарь)
|
||||
if (!hasUserAccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const taskId = taskCard.dataset.taskId;
|
||||
if (!taskId) return;
|
||||
|
||||
@@ -772,16 +1414,34 @@
|
||||
console.log('🗑️ Кэш типов задач очищен');
|
||||
}
|
||||
|
||||
// Функция для ручного обновления групп пользователя
|
||||
async function refreshUserGroups() {
|
||||
if (currentUser) {
|
||||
await getAllUserGroups(currentUser.login || currentUser.id);
|
||||
return hasUserAccess();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
async function init() {
|
||||
console.log('🔄 DocumentFields module initializing...');
|
||||
|
||||
try {
|
||||
await getCurrentUser();
|
||||
|
||||
// Проверяем доступ пользователя
|
||||
if (hasUserAccess()) {
|
||||
createModal();
|
||||
observeDOM();
|
||||
console.log('✅ DocumentFields module loaded (with access)');
|
||||
|
||||
console.log('✅ DocumentFields module loaded');
|
||||
// Для отладки показываем группы
|
||||
setTimeout(debugUserGroups, 1000);
|
||||
} else {
|
||||
console.log('ℹ️ DocumentFields module loaded (no access - user is not Signer or Secretary)');
|
||||
debugUserGroups(); // Показываем отладку даже при отсутствии доступа
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка инициализации:', error);
|
||||
}
|
||||
@@ -796,7 +1456,16 @@
|
||||
clearCache,
|
||||
init,
|
||||
addButtonToExpandedTask,
|
||||
isTaskExpanded
|
||||
isTaskExpanded,
|
||||
hasUserAccess,
|
||||
getAllUserGroups,
|
||||
refreshUserGroups,
|
||||
debugUserGroups,
|
||||
// Функции календаря
|
||||
toggleCalendar,
|
||||
selectDate,
|
||||
prevMonth,
|
||||
nextMonth
|
||||
};
|
||||
|
||||
// Запускаем инициализацию
|
||||
|
||||
@@ -82,15 +82,6 @@ navButtons.push(
|
||||
id: "create-task-btn"
|
||||
}
|
||||
);
|
||||
if (currentUser && navbar_checkUserGroup('1Секретарь') || currentUser && currentUser.role === 'admin') {
|
||||
navButtons.push({
|
||||
onclick: "TasksType.show('document')",
|
||||
className: "nav-btn tasks",
|
||||
icon: "fas fa-list",
|
||||
text: "Согласование",
|
||||
id: "create-task-btn"
|
||||
});
|
||||
}
|
||||
navButtons.push(
|
||||
{
|
||||
onclick: "showKanbanSection()",
|
||||
|
||||
Reference in New Issue
Block a user