323 lines
18 KiB
HTML
323 lines
18 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Главная{% endblock %}
|
||
|
||
{% block content %}
|
||
<style>
|
||
.select2-container {
|
||
width: 100% !important;
|
||
}
|
||
</style>
|
||
<style>
|
||
.filter-link {
|
||
font-size: 18px; /* Увеличиваем размер шрифта */
|
||
font-weight: bold; /* Делаем текст жирным */
|
||
padding: 10px 20px; /* Добавляем отступы для лучшего кликабельности */
|
||
background-color: #7a61fe; /* Добавляем зелёный фон */
|
||
color: white; /* Текст белый */
|
||
border-radius: 5px; /* Слегка скругляем углы */
|
||
text-align: center; /* Выравнивание по центру */
|
||
cursor: pointer; /* Курсор в виде указателя при наведении */
|
||
transition: background-color 0.3s ease, transform 0.2s ease; /* Плавные анимации */
|
||
}
|
||
|
||
.filter-link:hover {
|
||
background-color: #7a61fe; /* Темнее при наведении */
|
||
transform: scale(1.002); /* Немного увеличиваем размер при наведении */
|
||
}
|
||
</style>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="p-5" id="boxed-accordion">
|
||
<div class="preview">
|
||
<div class="accordion">
|
||
<div class="accordion__pane border border-gray-200 p-4 mt-3">
|
||
<a href="javascript:;" class="accordion__pane__toggle filter-link font-medium block">Filter</a>
|
||
|
||
<div class="accordion__pane__content mt-3 text-gray-800 leading-relaxed">
|
||
<div class="dropdown-box__content box p-5">
|
||
<form method="POST" action="/productf">
|
||
<!-- Дата-фильтры (Requested, Posted, Applied) -->
|
||
<div class="flex gap-4">
|
||
<!-- Requested on -->
|
||
<div class="w-1/2">
|
||
<div class="text-xs">Requested on</div>
|
||
<select id="date_requested" class="input w-full border mt-2 flex-1" name="date_requested">
|
||
<option value=""></option>
|
||
<option value="Today">Today</option>
|
||
<option value="Last 7 days">Last 7 days</option>
|
||
<option value="For all time">For all time</option>
|
||
<option value="custom_date_requested">from date to date</option>
|
||
</select>
|
||
<div id="date-requested-range-wrapper" class="p-5 grid grid-cols-12 gap-4 row-gap-3 mt-4" style="display: none;">
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>From</label>
|
||
<input type="date" id="date-requested-from" class="input w-full border mt-2" name="date_requested_from">
|
||
</div>
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>To</label>
|
||
<input type="date" id="date-requested-to" class="input w-full border mt-2" name="date_requested_to">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Posted on -->
|
||
<div class="w-1/2">
|
||
<div class="text-xs">Posted on</div>
|
||
<select id="date_posted" class="input w-full border mt-2 flex-1" name="date_posted">
|
||
<option value=""></option>
|
||
<option value="Today">Today</option>
|
||
<option value="Last 7 days">Last 7 days</option>
|
||
<option value="For all time">For all time</option>
|
||
<option value="custom_date_posted">from date to date</option>
|
||
</select>
|
||
<div id="date-posted-range-wrapper" class="p-5 grid grid-cols-12 gap-4 row-gap-3 mt-4" style="display: none;">
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>From</label>
|
||
<input type="date" id="date-posted-from" class="input w-full border mt-2" name="date_posted_from">
|
||
</div>
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>To</label>
|
||
<input type="date" id="date-posted-to" class="input w-full border mt-2" name="date_posted_to">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- Applied on -->
|
||
<div class="w-1/2">
|
||
<div class="text-xs">Applied on</div>
|
||
<select id="date_applied" class="input w-full border mt-2 flex-1" name="date_applied">
|
||
<option value=""></option>
|
||
<option value="Today">Today</option>
|
||
<option value="Last 7 days">Last 7 days</option>
|
||
<option value="For all time">For all time</option>
|
||
<option value="custom_date_applied">from date to date</option>
|
||
</select>
|
||
<div id="date-applied-range-wrapper" class="p-5 grid grid-cols-12 gap-4 row-gap-3 mt-4" style="display: none;">
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>From</label>
|
||
<input type="date" id="date-applied-from" class="input w-full border mt-2" name="date_applied_from">
|
||
</div>
|
||
<div class="col-span-12 sm:col-span-6">
|
||
<label>To</label>
|
||
<input type="date" id="date-applied-to" class="input w-full border mt-2" name="date_applied_to">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-nowrap gap-4 mt-4"> <!-- flex-nowrap запрещает перенос на новую строку -->
|
||
<!-- Clients (50% ширины) -->
|
||
<div class="flex-1 min-w-0"> <!-- flex-1 + min-w-0 предотвращает "расползание" -->
|
||
<label class="block mb-1 text-sm">Clients</label>
|
||
<select id="clients-multiselect1" class="select2 w-full" multiple="multiple" data-placeholder="Select Clients" name="client">
|
||
{% set seen_ids = [] %}
|
||
{% for job in jobs %}
|
||
{% if job.client.id not in seen_ids %}
|
||
<option value="{{ job.client.id }}">{{ job.client.user_nicename }}</option>
|
||
{% set _ = seen_ids.append(job.client.id) %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<!-- Assignee (50% ширины) -->
|
||
<div class="flex-1 min-w-0"> <!-- flex-1 дает равную ширину -->
|
||
<label class="block mb-1 text-sm">Assignee</label>
|
||
<select id="assignee-multiselect" class="select2 w-full" multiple="multiple" data-placeholder="Select Assignee" name="assignee">
|
||
<option value="">— Not selected —</option>
|
||
{% for user in users %}
|
||
<option value="{{ user.id }}" {% if user.id in assigned_users_ids %}selected{% endif %}>{{ user.username }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
|
||
<!-- Status и кнопка Apply Filters -->
|
||
<div class="flex-1 min-w-0">
|
||
<label>Status</label>
|
||
<div class="mt-2">
|
||
<select data-placeholder="Select Status" class="select2 w-full" multiple name="status">
|
||
<option value="Scheduled">Scheduled</option>
|
||
<option value="Requested">Requested</option>
|
||
<option value="In-Progress">In-Progress</option>
|
||
<option value="Paused">Paused</option>
|
||
<option value="Applied">Applied</option>
|
||
<option value="Issues Applying">Issues Applying</option>
|
||
<option value="Cancelled">Cancelled</option>
|
||
</select>
|
||
</div>
|
||
<button type="submit" class="button bg-theme-1 text-white mt-5">Apply Filters</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Функция для настройки обработчиков событий для каждого селекта
|
||
function setupDateSelect(selectId, wrapperId, customValue) {
|
||
const select = document.getElementById(selectId);
|
||
const dateRangeWrapper = document.getElementById(wrapperId);
|
||
|
||
select.addEventListener('change', function() {
|
||
if (this.value === customValue) {
|
||
dateRangeWrapper.style.display = 'grid';
|
||
} else {
|
||
dateRangeWrapper.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// Инициализация при загрузке страницы
|
||
if (select.value === customValue) {
|
||
dateRangeWrapper.style.display = 'grid';
|
||
}
|
||
}
|
||
|
||
// Настройка всех трех селектов
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
setupDateSelect('date_requested', 'date-requested-range-wrapper', 'custom_date_requested');
|
||
setupDateSelect('date_posted', 'date-posted-range-wrapper', 'custom_date_posted');
|
||
setupDateSelect('date_applied', 'date-applied-range-wrapper', 'custom_date_applied');
|
||
});
|
||
</script>
|
||
<!-- BEGIN: Datatable -->
|
||
|
||
|
||
|
||
<div class="intro-y datatable-wrapper box p-5 mt-5">
|
||
<table class="table table-report table-report--bordered display datatable w-full">
|
||
<thead>
|
||
<tr>
|
||
<th class="border-b-2 whitespace-no-wrap">TITLE ⨈</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">COMPANY ⨈</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">CLIENT ⨈</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">Requested on ⨈</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">Posted on ⨈</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">STATUS</th>
|
||
<th class="border-b-2 text-center whitespace-no-wrap">Assignee</th>
|
||
|
||
|
||
<th class="border-b-2 text-center whitespace-no-wrap">Applied on</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for job in jobs %}
|
||
<tr>
|
||
<td class="border-b">
|
||
<a href="{{ job.job.link }}" target="_blank" class="font-medium whitespace-no-wrap">{{ job.job.job_title [:50] }}</a>
|
||
<div class="text-gray-600 text-xs whitespace-no-wrap">{{ job.job.job_id }}</div>
|
||
</td>
|
||
<td class="text-center border-b">{{job.job.job_company}}</td>
|
||
<td class="text-center border-b">
|
||
|
||
<a href="#" class="client-link text-blue-500" data-client-id="{{ job.client.id }}">{{ job.client.user_nicename }}</a>
|
||
|
||
</td>
|
||
|
||
<td class="text-center border-b">{{job.job.data_requested}}</td>
|
||
<td class="text-center border-b">{{job.job.date_posted}}</td>
|
||
<td class="text-center border-b">
|
||
<select class="select2" onchange="updateStatus(this, '{{ job.id }}')">
|
||
<option value="" {% if job.status is none %}selected{% endif %}>— Not selected —</option>
|
||
<option value="Scheduled" {% if job.status == "Scheduled" %}selected{% endif %}>Scheduled</option>
|
||
<option value="Requested" {% if job.status == "Requested" %}selected{% endif %}>Requested</option>
|
||
<option value="In-Progress" {% if job.status == "In-Progress" %}selected{% endif %}>In-Progress</option>
|
||
<option value="Paused" {% if job.status == "Paused" %}selected{% endif %}>Paused</option>
|
||
<option value="Applied" {% if job.status == "Applied" %}selected{% endif %}>Applied</option>
|
||
<option value="Issues Applying" {% if job.status == "Issues Applying" %}selected{% endif %}>Issues Applying</option>
|
||
<option value="Cancelled" {% if job.status == "Cancelled" %}selected{% endif %}>Cancelled</option>
|
||
</select>
|
||
|
||
</td>
|
||
<td class="text-center border-b">
|
||
<select class="select2" onchange="updateAssignee(this, '{{ job.id }}')">
|
||
<option value="" {% if job.assignee is none %}selected{% endif %}>— Not selected —</option>
|
||
{% for user in users %}
|
||
<option value="{{ user.id }}" {% if job.assignee == user.id %}selected{% endif %}>
|
||
{{ user.username }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</td>
|
||
<td class="text-center border-b">-</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- END: Datatable -->
|
||
<!-- Включаем модалку -->
|
||
<!-- Модальное окно -->
|
||
{% include "modal.html" %}
|
||
<script src="/static/dist/js/prod.js"></script>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Инициализация Select2
|
||
$('#clients-multiselect').select2();
|
||
|
||
// Получение выбранных ID при изменении
|
||
$('#clients-multiselect').on('change', function() {
|
||
const selectedIds = $(this).val(); // Массив выбранных ID
|
||
console.log("Selected Client IDs:", selectedIds);
|
||
|
||
// Отправка на сервер (пример)
|
||
fetch('/update-selected-clients', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRFToken': '{{ csrf_token }}'
|
||
},
|
||
body: JSON.stringify({client_ids: selectedIds})
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => console.log(data));
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Инициализация всех select2
|
||
$('.select2').select2();
|
||
|
||
// Обработчик кнопки Search
|
||
$('.button.bg-theme-1').on('click', function() {
|
||
// Собираем все данные фильтров
|
||
const filters = {
|
||
clients: $('#clients-multiselect').val() || [],
|
||
assignees: $('select[name="assignee"]').val() || [],
|
||
statuses: $('select[placeholder="Select categories"]').val() || [],
|
||
requested: $('#applied-select:eq(0)').val(),
|
||
posted: $('#applied-select:eq(1)').val(),
|
||
applied: $('#applied-select:eq(2)').val(),
|
||
date_range: $('#date-range-input').val()
|
||
};
|
||
|
||
// Переходим на /productf с параметрами
|
||
const queryString = new URLSearchParams();
|
||
|
||
if (filters.clients.length) queryString.append('clients', filters.clients.join(','));
|
||
if (filters.assignees.length) queryString.append('assignees', filters.assignees.join(','));
|
||
if (filters.statuses.length) queryString.append('statuses', filters.statuses.join(','));
|
||
if (filters.requested) queryString.append('requested', filters.requested);
|
||
if (filters.posted) queryString.append('posted', filters.posted);
|
||
if (filters.applied) queryString.append('applied', filters.applied);
|
||
if (filters.date_range) queryString.append('date_range', filters.date_range);
|
||
|
||
window.location.href = `/productf?${queryString.toString()}`;
|
||
});
|
||
});
|
||
</script>
|
||
|
||
{% endblock %} |