8de1ffaa34
- Шаблон chat.html → русская база с {% trans %}/{% blocktrans %}
- JS-строки chat.js → gettext() + JavaScriptCatalog (/jsi18n/), подключён
в index.html; защитный fallback если каталог не загрузился
- Переводы uk/en для обоих доменов (django + djangojs), скомпилированы
- makemessages заодно извлёк непереведённые строки прошлых фич (2FA,
nextcloud, документы) — оставлены пустыми (рендерятся на базовом ru)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
745 lines
45 KiB
HTML
745 lines
45 KiB
HTML
{% load common_tags %}
|
|
{% load static %}
|
|
{% load i18n %}
|
|
<!DOCTYPE html>
|
|
<html lang="{{ LANGUAGE_CODE }}">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title>АКС — Корпоративний Портал</title>
|
|
<link rel="stylesheet" href="{% static 'assets/css/main.css' %}">
|
|
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
|
<script>htmx.config.allowEval = false;</script>
|
|
<script src="{% static 'tinymce/tinymce.min.js' %}"></script>
|
|
<script>
|
|
// HTMX собирает данные формы ДО configRequest — дописываем актуальное
|
|
// содержимое редакторов прямо в параметры запроса
|
|
document.addEventListener('htmx:configRequest', function(evt) {
|
|
if (!window.tinymce || !evt.detail || !evt.detail.parameters) return;
|
|
tinymce.get().forEach(function(editor) {
|
|
var el = editor.getElement();
|
|
if (!el || !el.name) return;
|
|
var params = evt.detail.parameters;
|
|
if (typeof params.set === 'function') {
|
|
params.set(el.name, editor.getContent());
|
|
} else {
|
|
params[el.name] = editor.getContent();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<script>(function(){var t=localStorage.getItem('theme')||'light';if(t!=='light')document.documentElement.setAttribute('data-theme',t);})();</script>
|
|
<script src="{% url 'javascript-catalog' %}"></script>
|
|
<script src="{% static 'assets/js/pagination.js' %}"></script>
|
|
<script src="{% static 'assets/js/pharmacies.js' %}"></script>
|
|
<script src="{% static 'assets/js/employees.js' %}"></script>
|
|
<script src="{% static 'assets/js/timetrack.js' %}"></script>
|
|
<script src="{% static 'assets/js/people-picker.js' %}"></script>
|
|
<script src="{% static 'assets/js/searchable-select.js' %}"></script>
|
|
<script src="{% static 'assets/js/hr-portal.js' %}"></script>
|
|
<script src="{% static 'assets/js/it-manager.js' %}"></script>
|
|
<script src="{% static 'assets/js/directory-quick-add.js' %}"></script>
|
|
<script src="{% static 'assets/js/chat.js' %}"></script>
|
|
</head>
|
|
<body>
|
|
|
|
<script>
|
|
function isMobile() { return window.innerWidth < 768; }
|
|
|
|
function toggleSidebar() {
|
|
const s = document.getElementById('sidebar');
|
|
if (isMobile()) {
|
|
const backdrop = document.getElementById('sidebar-backdrop');
|
|
const opening = !s.classList.contains('mobile-open');
|
|
s.classList.toggle('mobile-open');
|
|
backdrop.classList.toggle('active');
|
|
document.body.style.overflow = opening ? 'hidden' : '';
|
|
} else {
|
|
s.classList.toggle('collapsed');
|
|
}
|
|
}
|
|
|
|
function closeSidebar() {
|
|
const s = document.getElementById('sidebar');
|
|
const backdrop = document.getElementById('sidebar-backdrop');
|
|
s.classList.remove('mobile-open');
|
|
backdrop.classList.remove('active');
|
|
document.body.style.overflow = '';
|
|
}
|
|
|
|
function setActive(el) {
|
|
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
|
|
el.classList.add('active');
|
|
const hxGet = el.getAttribute('hx-get') || '';
|
|
syncBottomNav(hxGet);
|
|
if (isMobile()) closeSidebar();
|
|
}
|
|
|
|
function syncBottomNav(hxGet) {
|
|
document.querySelectorAll('.bottom-nav-item[hx-get]').forEach(i => {
|
|
i.classList.toggle('active', i.getAttribute('hx-get') === hxGet);
|
|
});
|
|
}
|
|
|
|
function bottomNavClick(el) {
|
|
document.querySelectorAll('.bottom-nav-item').forEach(i => i.classList.remove('active'));
|
|
el.classList.add('active');
|
|
const hxGet = el.getAttribute('hx-get') || '';
|
|
const sidebarItem = document.querySelector(`.nav-item[hx-get="${hxGet}"]`);
|
|
if (sidebarItem) {
|
|
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
|
|
sidebarItem.classList.add('active');
|
|
}
|
|
}
|
|
|
|
function toggleUserMenu() {
|
|
const d = document.getElementById('user-dropdown');
|
|
d.style.display = d.style.display === 'none' ? 'block' : 'none';
|
|
}
|
|
function closeUserMenu() {
|
|
document.getElementById('user-dropdown').style.display = 'none';
|
|
}
|
|
|
|
function applyTheme(theme) {
|
|
const html = document.documentElement;
|
|
if (theme === 'light') {
|
|
html.removeAttribute('data-theme');
|
|
} else {
|
|
html.setAttribute('data-theme', theme);
|
|
}
|
|
localStorage.setItem('theme', theme);
|
|
document.querySelectorAll('.theme-option').forEach(function(btn) {
|
|
btn.classList.toggle('active', btn.getAttribute('data-theme-value') === theme);
|
|
});
|
|
}
|
|
|
|
function toggleThemeSwitcher() {
|
|
const d = document.getElementById('theme-dropdown');
|
|
const isOpen = d.style.display !== 'none';
|
|
if (!isOpen) closeUserMenu();
|
|
d.style.display = isOpen ? 'none' : 'block';
|
|
}
|
|
|
|
function closeThemeSwitcher() {
|
|
const d = document.getElementById('theme-dropdown');
|
|
if (d) d.style.display = 'none';
|
|
}
|
|
|
|
function handleBgFile(input) {
|
|
const file = input.files[0];
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
const dataUrl = e.target.result;
|
|
const opacity = parseFloat(localStorage.getItem('bg-opacity') || '0.88');
|
|
try { localStorage.setItem('bg-image', dataUrl); } catch(err) { /* image too large to persist */ }
|
|
applyBgImage(dataUrl, opacity);
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
|
|
function applyBgImage(url, opacity) {
|
|
const wp = document.getElementById('bg-wallpaper');
|
|
const ov = document.getElementById('bg-overlay');
|
|
wp.style.backgroundImage = 'url("' + url + '")';
|
|
wp.style.display = 'block';
|
|
ov.style.display = 'block';
|
|
ov.style.opacity = opacity;
|
|
document.getElementById('main-content').style.background = 'transparent';
|
|
document.body.style.background = 'transparent';
|
|
const slider = document.getElementById('bg-opacity-slider');
|
|
if (slider) slider.value = Math.round(opacity * 100);
|
|
const opRow = document.getElementById('bg-opacity-row');
|
|
if (opRow) opRow.style.display = 'flex';
|
|
const clearBtn = document.getElementById('bg-clear-btn');
|
|
if (clearBtn) clearBtn.style.display = 'flex';
|
|
}
|
|
|
|
function clearBgImage() {
|
|
document.getElementById('bg-wallpaper').style.display = 'none';
|
|
document.getElementById('bg-overlay').style.display = 'none';
|
|
document.getElementById('main-content').style.background = '';
|
|
document.body.style.background = '';
|
|
localStorage.removeItem('bg-image');
|
|
const opRow = document.getElementById('bg-opacity-row');
|
|
if (opRow) opRow.style.display = 'none';
|
|
const clearBtn = document.getElementById('bg-clear-btn');
|
|
if (clearBtn) clearBtn.style.display = 'none';
|
|
const fi = document.getElementById('bg-file-input');
|
|
if (fi) fi.value = '';
|
|
}
|
|
|
|
function setBgOpacity(val) {
|
|
const opacity = val / 100;
|
|
const ov = document.getElementById('bg-overlay');
|
|
if (ov) ov.style.opacity = opacity;
|
|
localStorage.setItem('bg-opacity', opacity);
|
|
}
|
|
|
|
document.addEventListener('click', function(e) {
|
|
const userWrapper = document.getElementById('user-menu-wrapper');
|
|
if (userWrapper && !userWrapper.contains(e.target)) closeUserMenu();
|
|
const themeWrapper = document.getElementById('theme-switcher-wrapper');
|
|
if (themeWrapper && !themeWrapper.contains(e.target)) closeThemeSwitcher();
|
|
});
|
|
window.addEventListener('resize', function() {
|
|
if (!isMobile()) closeSidebar();
|
|
});
|
|
</script>
|
|
|
|
<!-- Background wallpaper layers -->
|
|
<div id="bg-wallpaper" style="display:none; position:fixed; inset:0; z-index:-2; background-size:cover; background-position:center; background-repeat:no-repeat;"></div>
|
|
<div id="bg-overlay" style="display:none; position:fixed; inset:0; z-index:-1; background-color:var(--color-background); transition:opacity 200ms;"></div>
|
|
|
|
<!-- Loader bar (HTMX) -->
|
|
<div class="loader-bar htmx-indicator" id="loader"></div>
|
|
|
|
<div style="display:flex; height:100dvh; overflow:hidden;">
|
|
|
|
<!-- Backdrop (mobile overlay) -->
|
|
<div id="sidebar-backdrop" class="sidebar-backdrop" onclick="closeSidebar()"></div>
|
|
|
|
<!-- ══════════════════ SIDEBAR ══════════════════ -->
|
|
<aside id="sidebar" class="sidebar">
|
|
|
|
<!-- Шапка -->
|
|
<div class="sidebar-header">
|
|
<div class="sidebar-logo">
|
|
<img src="{% static 'assets/img/logosm.svg' %}" alt="АКС" style="width:100%; height:100%; object-fit:contain;">
|
|
</div>
|
|
<div class="sidebar-logo-text">
|
|
<div style="color:var(--color-sidebar-accent-foreground); font-size:0.8125rem; font-weight:700; line-height:1.2; letter-spacing:0.01em;">{% trans "Сеть аптек" %}</div>
|
|
<div style="color:var(--color-sidebar-foreground); font-size:0.625rem; opacity:0.6;">{% trans "Портал пользователя" %}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Навигация -->
|
|
<nav style="flex:1; overflow-y:auto; overflow-x:hidden; padding:0.5rem; display:flex; flex-direction:column; gap:1rem;">
|
|
|
|
<!-- Головне меню -->
|
|
<div>
|
|
<div class="nav-section-label">{% trans "Главное меню" %}</div>
|
|
<div style="display:flex; flex-direction:column; gap:2px;">
|
|
|
|
<a href="/dashboard/" class="nav-item"
|
|
hx-get="/dashboard/" hx-target="#main-content" hx-push-url="/dashboard/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Главная" %}</span>
|
|
</a>
|
|
|
|
<a href="/news/" class="nav-item"
|
|
hx-get="/news/" hx-target="#main-content" hx-push-url="/news/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/>
|
|
<path d="M18 14h-8M15 18h-5M10 6h8v4h-8V6Z"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Новости" %}</span>
|
|
</a>
|
|
|
|
<a href="/employees/" class="nav-item"
|
|
hx-get="/employees/" hx-target="#main-content" hx-push-url="/employees/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Сотрудники" %}</span>
|
|
</a>
|
|
|
|
<a href="/tasks/" class="nav-item"
|
|
hx-get="/tasks/" hx-target="#main-content" hx-push-url="/tasks/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
|
|
<path d="m9 14 2 2 4-4"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Задачи" %}</span>
|
|
</a>
|
|
<a href="/dislocation/" class="nav-item"
|
|
hx-get="/dislocation/" hx-target="#main-content" hx-push-url="/dislocation/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Дислокация" %}</span>
|
|
</a>
|
|
<a href="/documents/" class="nav-item"
|
|
hx-get="/documents/" hx-target="#main-content" hx-push-url="/documents/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
|
|
<path d="M14 2v4a2 2 0 0 0 2 2h4M10 9H8M16 13H8M16 17H8"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Документы" %}</span>
|
|
</a>
|
|
|
|
<a href="/email/" class="nav-item"
|
|
hx-get="/email/" hx-target="#main-content" hx-push-url="/email/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="20" height="16" x="2" y="4" rx="2"/>
|
|
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Электронная почта" %}</span>
|
|
</a>
|
|
|
|
<a href="/chat/" class="nav-item"
|
|
hx-get="/chat/" hx-target="#main-content" hx-push-url="/chat/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Чат" %}</span>
|
|
</a>
|
|
|
|
<a href="/calendar/" class="nav-item"
|
|
hx-get="/calendar/" hx-target="#main-content" hx-push-url="/calendar/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="18" height="18" x="3" y="4" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Календарь" %}</span>
|
|
</a>
|
|
|
|
<a href="/databases/" class="nav-item"
|
|
hx-get="/databases/" hx-target="#main-content" hx-push-url="/databases/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Базы данных" %}</span>
|
|
</a>
|
|
|
|
<a href="/reports/" class="nav-item"
|
|
hx-get="/reports/" hx-target="#main-content" hx-push-url="/reports/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Отчёты" %}</span>
|
|
</a>
|
|
|
|
<a href="/purchases/" class="nav-item"
|
|
hx-get="/purchases/" hx-target="#main-content" hx-push-url="/purchases/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="8" cy="21" r="1"/><circle cx="19" cy="21" r="1"/>
|
|
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Закупки" %}</span>
|
|
</a>
|
|
|
|
<a href="/hr-portal/" class="nav-item"
|
|
hx-get="/hr-portal/" hx-target="#main-content" hx-push-url="/hr-portal/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="20" height="14" x="2" y="7" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "HR портал" %}</span>
|
|
</a>
|
|
|
|
<a href="/settings/" class="nav-item"
|
|
hx-get="/settings/" hx-target="#main-content" hx-push-url="/settings/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/>
|
|
<circle cx="12" cy="12" r="3"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Настройки" %}</span>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Управління -->
|
|
<div>
|
|
<div class="nav-section-label">{% trans "Управление" %}</div>
|
|
<div style="display:flex; flex-direction:column; gap:2px;">
|
|
|
|
|
|
|
|
<a href="/structure/" class="nav-item"
|
|
hx-get="/structure/" hx-target="#main-content" hx-push-url="/structure/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
<path d="M2 4h12M2 8h8M2 12h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Структура" %}</span>
|
|
</a>
|
|
|
|
<a href="/pharmacies/" class="nav-item"
|
|
hx-get="/pharmacies/" hx-target="#main-content" hx-push-url="/pharmacies/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z"/>
|
|
<path d="M15 5.764v15"/><path d="M9 3.236v15"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Аптеки" %}</span>
|
|
</a>
|
|
|
|
<a href="/utilities/" class="nav-item"
|
|
hx-get="/utilities/" hx-target="#main-content" hx-push-url="/utilities/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Коммунальные услуги" %}</span>
|
|
</a>
|
|
|
|
<a href="/recruiting/" class="nav-item"
|
|
hx-get="/recruiting/" hx-target="#main-content" hx-push-url="/recruiting/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<line x1="19" x2="19" y1="8" y2="14"/><line x1="22" x2="16" y1="11" y2="11"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Рекрутинг" %}</span>
|
|
</a>
|
|
|
|
<a href="/timetrack/" class="nav-item"
|
|
hx-get="/timetrack/" hx-target="#main-content" hx-push-url="/timetrack/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Учёт рабочего времени" %}</span>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Підтримка -->
|
|
<div>
|
|
<div class="nav-section-label">{% trans "Поддержка" %}</div>
|
|
<div style="display:flex; flex-direction:column; gap:2px;">
|
|
|
|
<a href="/help/" class="nav-item"
|
|
hx-get="/help/" hx-target="#main-content" hx-push-url="/help/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Справка" %}</span>
|
|
</a>
|
|
|
|
<a href="/it-support/" class="nav-item"
|
|
hx-get="/it-support/" hx-target="#main-content" hx-push-url="/it-support/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 18v-6a9 9 0 0 1 18 0v6"/>
|
|
<path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Поддержка IT" %}</span>
|
|
</a>
|
|
|
|
{% if request.user|is_it_staff %}
|
|
<a href="/it-manager/" class="nav-item"
|
|
hx-get="/it-manager/" hx-target="#main-content" hx-push-url="/it-manager/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "IT-отдел" %}</span>
|
|
</a>
|
|
{% endif %}
|
|
|
|
{% if request.user.is_staff %}
|
|
<a href="/ad-mapping/" class="nav-item"
|
|
hx-get="/ad-mapping/" hx-target="#main-content" hx-push-url="/ad-mapping/"
|
|
hx-indicator="#loader" onclick="setActive(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="8" height="8" x="2" y="2" rx="2"/><rect width="8" height="8" x="14" y="14" rx="2"/>
|
|
<path d="M10 6h4a2 2 0 0 1 2 2v2M14 18h-4a2 2 0 0 1-2-2v-2"/>
|
|
</svg>
|
|
<span class="nav-label-text">{% trans "Active Directory" %}</span>
|
|
</a>
|
|
{% endif %}
|
|
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Футер сайдбара -->
|
|
<div class="sidebar-footer" style="justify-content:center; padding:0.75rem;">
|
|
<span class="sidebar-logo-text" style="font-size:0.625rem; color:var(--color-sidebar-foreground); opacity:0.4; white-space:nowrap;">© 2026 АКС Корпоративний Портал | v1.0</span>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- ══════════════════ MAIN ══════════════════ -->
|
|
<div style="flex:1; display:flex; flex-direction:column; min-width:0; height:100vh;">
|
|
|
|
<!-- Header -->
|
|
<header style="height:56px; display:flex; align-items:center; justify-content:space-between; border-bottom:1px solid var(--color-border); background:var(--color-card); padding:0 1.25rem; flex-shrink:0; gap:1rem;">
|
|
|
|
<div style="display:flex; align-items:center; gap:0.75rem; flex:1;">
|
|
<!-- Кнопка сворачивания -->
|
|
<button onclick="toggleSidebar()" class="btn btn-ghost btn-icon" title="Згорнути меню">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Поиск -->
|
|
<div class="header-search" style="display:flex; align-items:center; gap:0.5rem; background:var(--color-muted); border:1px solid var(--color-border); border-radius:var(--radius); padding:0.4375rem 0.75rem; width:18rem;">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--color-muted-foreground); flex-shrink:0;">
|
|
<circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
|
|
</svg>
|
|
<input type="text"
|
|
placeholder="{% trans 'Поиск...' %}"
|
|
class="input"
|
|
style="border:none; background:transparent; padding:0; box-shadow:none;"
|
|
hx-get="/api/search"
|
|
hx-trigger="keyup changed delay:300ms"
|
|
hx-target="#search-results"
|
|
name="q">
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display:flex; align-items:center; gap:0.5rem;">
|
|
|
|
<!-- Language switcher -->
|
|
{% get_current_language as CUR_LANG %}
|
|
<form action="{% url 'set_language' %}" method="post" style="margin:0;">
|
|
{% csrf_token %}
|
|
<input type="hidden" name="next" value="/">
|
|
<select name="language" onchange="this.form.next.value = window.location.pathname; this.form.submit();" title="{% trans 'Язык' %}"
|
|
class="input" style="height:2rem; padding:0 0.5rem; font-size:0.75rem; width:auto; cursor:pointer;">
|
|
{% for code, name in LANGUAGES %}
|
|
<option value="{{ code }}" {% if code == CUR_LANG %}selected{% endif %}>{{ name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</form>
|
|
|
|
<!-- Theme switcher -->
|
|
<div style="position:relative;" id="theme-switcher-wrapper">
|
|
<button onclick="toggleThemeSwitcher()" class="btn btn-ghost btn-icon" title="Тема інтерфейсу">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<path d="M12 2a10 10 0 0 1 0 20V2z" fill="currentColor" stroke="none"/>
|
|
</svg>
|
|
</button>
|
|
<div id="theme-dropdown" style="display:none; position:absolute; top:calc(100% + 8px); right:0; background:var(--color-card); border:1px solid var(--color-border); border-radius:var(--radius); box-shadow:0 8px 24px rgba(0,0,0,0.15); z-index:1000; padding:0.375rem; min-width:160px;">
|
|
<div style="padding:0.25rem 0.625rem 0.375rem; font-size:0.625rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em;">Тема</div>
|
|
<button class="theme-option" data-theme-value="light" onclick="applyTheme('light')">
|
|
<span class="theme-dot" style="background:hsl(224.8,81%,60.8%);"></span>
|
|
Light Blue
|
|
<span class="theme-check">✓</span>
|
|
</button>
|
|
<button class="theme-option" data-theme-value="dark" onclick="applyTheme('dark')">
|
|
<span class="theme-dot" style="background:hsl(215,25%,10%); border-color:hsl(215,25%,30%);"></span>
|
|
Dark
|
|
<span class="theme-check">✓</span>
|
|
</button>
|
|
<button class="theme-option" data-theme-value="slate" onclick="applyTheme('slate')">
|
|
<span class="theme-dot" style="background:hsl(215,30%,14%); border-color:hsl(215,25%,30%);"></span>
|
|
Slate
|
|
<span class="theme-check">✓</span>
|
|
</button>
|
|
<button class="theme-option" data-theme-value="emerald" onclick="applyTheme('emerald')">
|
|
<span class="theme-dot" style="background:hsl(152,58%,38%);"></span>
|
|
Emerald
|
|
<span class="theme-check">✓</span>
|
|
</button>
|
|
|
|
<div style="height:1px; background:var(--color-border); margin:0.375rem 0;"></div>
|
|
<div style="padding:0.25rem 0.625rem 0.375rem; font-size:0.625rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em;">Фон</div>
|
|
|
|
<label class="theme-option" style="cursor:pointer;">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>
|
|
</svg>
|
|
Обрати фото
|
|
<input type="file" id="bg-file-input" accept="image/*" style="display:none" onchange="handleBgFile(this)">
|
|
</label>
|
|
|
|
<div id="bg-opacity-row" style="display:none; padding:0.25rem 0.625rem 0.375rem; align-items:center; gap:0.5rem;">
|
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--color-muted-foreground); flex-shrink:0;">
|
|
<circle cx="12" cy="12" r="10"/><path d="M12 2a10 10 0 0 1 0 20V2z" fill="currentColor" stroke="none"/>
|
|
</svg>
|
|
<input type="range" id="bg-opacity-slider" min="40" max="98" value="88" style="flex:1; accent-color:var(--color-primary); cursor:pointer;" oninput="setBgOpacity(this.value)">
|
|
</div>
|
|
|
|
<button class="theme-option" id="bg-clear-btn" style="display:none;" onclick="clearBgImage()">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M18 6 6 18M6 6l12 12"/>
|
|
</svg>
|
|
Без фону
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Уведомления -->
|
|
<button class="btn btn-ghost btn-icon" style="position:relative;">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/>
|
|
<path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/>
|
|
</svg>
|
|
<span style="position:absolute; top:4px; right:4px; width:7px; height:7px; background:var(--color-destructive); border-radius:50%;"></span>
|
|
</button>
|
|
|
|
<!-- Аватар пользователя + дропдаун -->
|
|
<div style="position:relative;" id="user-menu-wrapper">
|
|
<div onclick="toggleUserMenu()" style="width:2rem; height:2rem; border-radius:50%; cursor:pointer; flex-shrink:0; user-select:none; overflow:hidden;
|
|
{% if not request.user.photo %}background:var(--color-accent); color:var(--color-accent-foreground); display:flex; align-items:center; justify-content:center; font-size:0.6875rem; font-weight:700;{% endif %}">
|
|
{% if request.user.photo %}
|
|
<img src="{{ request.user.photo.url }}" alt="" style="width:100%; height:100%; object-fit:cover; display:block;">
|
|
{% else %}
|
|
{{ request.user|initials }}
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div id="user-dropdown" style="display:none; position:absolute; top:calc(100% + 8px); right:0; min-width:200px; background:var(--color-card); border:1px solid var(--color-border); border-radius:var(--radius); box-shadow:0 8px 24px rgba(0,0,0,0.18); z-index:1000; overflow:hidden;">
|
|
<!-- Имя пользователя -->
|
|
<div style="padding:0.75rem 1rem 0.625rem; border-bottom:1px solid var(--color-border);">
|
|
<div style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground);">{{ request.user.get_full_name|default:request.user.username }}</div>
|
|
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ request.user.email }}</div>
|
|
</div>
|
|
<!-- Пункты меню -->
|
|
<div style="padding:0.25rem 0;">
|
|
<a href="/profile/" hx-get="/profile/" hx-target="#main-content" hx-push-url="/profile/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
|
{% trans "Профиль" %}
|
|
</a>
|
|
<a href="/settings/" hx-get="/settings/" hx-target="#main-content" hx-push-url="/settings/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
{% trans "Настройки" %}
|
|
</a>
|
|
<a href="/help/" hx-get="/help/" hx-target="#main-content" hx-push-url="/help/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>
|
|
{% trans "Помощь" %}
|
|
</a>
|
|
<div style="height:1px; background:var(--color-border); margin:0.25rem 0;"></div>
|
|
<form method="post" action="{% url 'logout' %}" style="margin:0;">
|
|
{% csrf_token %}
|
|
<button type="submit" style="width:100%; display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-destructive); background:none; border:none; cursor:pointer; text-align:left; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
|
{% trans "Выход" %}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Контент (HTMX заменяет содержимое) -->
|
|
<main id="main-content" style="flex:1; overflow-y:auto; background:var(--color-background); padding:1.5rem;">
|
|
{% if page_template %}
|
|
{% include page_template %}
|
|
{% else %}
|
|
<div id="page-loader" style="padding:2rem;color:var(--color-muted-foreground);font-size:0.875rem;">{% trans "Загрузка..." %}</div>
|
|
{% endif %}
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Контейнер модалок -->
|
|
<div id="modal-container"></div>
|
|
|
|
<!-- ══════════════════ BOTTOM NAV (mobile) ══════════════════ -->
|
|
<nav class="bottom-nav" id="bottom-nav">
|
|
|
|
<a href="/dashboard/" class="bottom-nav-item"
|
|
hx-get="/dashboard/" hx-target="#main-content" hx-push-url="/dashboard/" hx-indicator="#loader"
|
|
onclick="bottomNavClick(this)">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>
|
|
</svg>
|
|
<span>{% trans "Главная" %}</span>
|
|
</a>
|
|
|
|
<a href="/tasks/" class="bottom-nav-item"
|
|
hx-get="/tasks/" hx-target="#main-content" hx-push-url="/tasks/" hx-indicator="#loader"
|
|
onclick="bottomNavClick(this)">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
|
|
<path d="m9 14 2 2 4-4"/>
|
|
</svg>
|
|
<span>{% trans "Задачи" %}</span>
|
|
</a>
|
|
|
|
<a href="/employees/" class="bottom-nav-item"
|
|
hx-get="/employees/" hx-target="#main-content" hx-push-url="/employees/" hx-indicator="#loader"
|
|
onclick="bottomNavClick(this)">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
|
</svg>
|
|
<span>{% trans "Люди" %}</span>
|
|
</a>
|
|
|
|
<a href="/chat/" class="bottom-nav-item"
|
|
hx-get="/chat/" hx-target="#main-content" hx-push-url="/chat/" hx-indicator="#loader"
|
|
onclick="bottomNavClick(this)">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>
|
|
</svg>
|
|
<span>{% trans "Чат" %}</span>
|
|
</a>
|
|
|
|
<button class="bottom-nav-item" onclick="toggleSidebar()">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
|
|
</svg>
|
|
<span>{% trans "Меню" %}</span>
|
|
</button>
|
|
|
|
</nav>
|
|
</div>
|
|
|
|
<script>
|
|
// Активный пункт меню по текущему URL
|
|
function setActiveNavItem() {
|
|
const currentPath = window.location.pathname;
|
|
document.querySelectorAll('.nav-item').forEach(item => {
|
|
const hxGet = item.getAttribute('hx-get');
|
|
item.classList.toggle('active', !!hxGet && hxGet === currentPath);
|
|
});
|
|
syncBottomNav(currentPath);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const mainContent = document.getElementById('main-content');
|
|
// Плейсхолдер определяем по элементу, а не по тексту (текст переводится)
|
|
const isPlaceholder = !!mainContent.querySelector('#page-loader');
|
|
|
|
// Если сервер не отдал страницу — грузим по URL
|
|
if (isPlaceholder) {
|
|
const currentPath = window.location.pathname;
|
|
const pageUrl = currentPath === '/' ? '/dashboard/' : currentPath;
|
|
htmx.ajax('GET', pageUrl, {target:'#main-content', swap:'innerHTML'});
|
|
}
|
|
setActiveNavItem();
|
|
|
|
// Восстановление темы и фона
|
|
var savedTheme = localStorage.getItem('theme') || 'light';
|
|
document.querySelectorAll('.theme-option').forEach(function(btn) {
|
|
btn.classList.toggle('active', btn.getAttribute('data-theme-value') === savedTheme);
|
|
});
|
|
var savedBg = localStorage.getItem('bg-image');
|
|
if (savedBg) {
|
|
var savedOpacity = parseFloat(localStorage.getItem('bg-opacity') || '0.88');
|
|
applyBgImage(savedBg, savedOpacity);
|
|
}
|
|
});
|
|
|
|
// После загрузки фрагмента — активный пункт и init страницы
|
|
document.body.addEventListener('htmx:afterSwap', function(e) {
|
|
if (e.detail.target.id !== 'main-content') return;
|
|
setActiveNavItem();
|
|
if (typeof pharmaInit === 'function') pharmaInit();
|
|
if (typeof empInit === 'function') empInit();
|
|
if (typeof ttInit === 'function') ttInit();
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|