1021 lines
30 KiB
HTML
1021 lines
30 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Клиент внешнего API - Управление задачами</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
background: #f5f7fa;
|
||
color: #2c3e50;
|
||
line-height: 1.6;
|
||
padding: 20px;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30px;
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 10px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.header h1 i {
|
||
color: #3498db;
|
||
}
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
}
|
||
|
||
.user-info span {
|
||
font-weight: 500;
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
.logout-btn {
|
||
background: #e74c3c;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 16px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
transition: background 0.3s;
|
||
}
|
||
|
||
.logout-btn:hover {
|
||
background: #c0392b;
|
||
}
|
||
|
||
.connection-panel {
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
margin-bottom: 30px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.panel-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.panel-title i {
|
||
color: #3498db;
|
||
}
|
||
|
||
.connection-form {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr auto;
|
||
gap: 15px;
|
||
align-items: end;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 5px;
|
||
}
|
||
|
||
.form-group label {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
.form-group input, .form-group select, .form-group textarea {
|
||
padding: 10px 12px;
|
||
border: 1px solid #dce4ec;
|
||
border-radius: 5px;
|
||
font-size: 14px;
|
||
transition: border-color 0.3s;
|
||
}
|
||
|
||
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
|
||
outline: none;
|
||
border-color: #3498db;
|
||
}
|
||
|
||
.form-group input.error {
|
||
border-color: #e74c3c;
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
border: none;
|
||
border-radius: 5px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: #3498db;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #2980b9;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: #95a5a6;
|
||
color: white;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: #7f8c8d;
|
||
}
|
||
|
||
.btn-success {
|
||
background: #27ae60;
|
||
color: white;
|
||
}
|
||
|
||
.btn-success:hover {
|
||
background: #229954;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: #e74c3c;
|
||
color: white;
|
||
}
|
||
|
||
.btn-danger:hover {
|
||
background: #c0392b;
|
||
}
|
||
|
||
.btn-warning {
|
||
background: #f39c12;
|
||
color: white;
|
||
}
|
||
|
||
.btn-warning:hover {
|
||
background: #e67e22;
|
||
}
|
||
|
||
.btn:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.saved-connections {
|
||
margin-top: 20px;
|
||
border-top: 1px solid #ecf0f1;
|
||
padding-top: 20px;
|
||
}
|
||
|
||
.connections-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.connection-item {
|
||
background: #ecf0f1;
|
||
padding: 10px 15px;
|
||
border-radius: 5px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
cursor: pointer;
|
||
transition: background 0.3s;
|
||
}
|
||
|
||
.connection-item:hover {
|
||
background: #d5dbdb;
|
||
}
|
||
|
||
.connection-item.active {
|
||
background: #3498db;
|
||
color: white;
|
||
}
|
||
|
||
.connection-item .remove-conn {
|
||
color: #e74c3c;
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
padding: 0 5px;
|
||
}
|
||
|
||
.connection-item .remove-conn:hover {
|
||
color: #c0392b;
|
||
}
|
||
|
||
.filter-panel {
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
margin-bottom: 30px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr auto;
|
||
gap: 15px;
|
||
align-items: end;
|
||
}
|
||
|
||
.tasks-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.tasks-header h2 {
|
||
font-size: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.tasks-header h2 i {
|
||
color: #3498db;
|
||
}
|
||
|
||
.tasks-count {
|
||
background: #3498db;
|
||
color: white;
|
||
padding: 5px 10px;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.tasks-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
||
gap: 20px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.task-card {
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
transition: transform 0.3s, box-shadow 0.3s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.task-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 5px 20px rgba(0,0,0,0.15);
|
||
}
|
||
|
||
.task-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: start;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.task-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #2c3e50;
|
||
flex: 1;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.task-status {
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.status-assigned { background: #3498db; color: white; }
|
||
.status-in_progress { background: #f39c12; color: white; }
|
||
.status-completed { background: #27ae60; color: white; }
|
||
.status-overdue { background: #e74c3c; color: white; }
|
||
.status-rework { background: #9b59b6; color: white; }
|
||
.status-default { background: #95a5a6; color: white; }
|
||
|
||
.task-description {
|
||
color: #7f8c8d;
|
||
font-size: 14px;
|
||
margin-bottom: 15px;
|
||
max-height: 100px;
|
||
overflow-y: auto;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.task-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-bottom: 15px;
|
||
font-size: 12px;
|
||
color: #95a5a6;
|
||
}
|
||
|
||
.task-meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.task-files {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.files-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.files-list {
|
||
list-style: none;
|
||
max-height: 150px;
|
||
overflow-y: auto;
|
||
border: 1px solid #ecf0f1;
|
||
border-radius: 5px;
|
||
padding: 5px;
|
||
}
|
||
|
||
.file-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 5px;
|
||
border-bottom: 1px solid #ecf0f1;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.file-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.file-icon {
|
||
color: #3498db;
|
||
}
|
||
|
||
.file-name {
|
||
flex: 1;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.file-size {
|
||
color: #95a5a6;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.file-download {
|
||
color: #27ae60;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.file-download:hover {
|
||
color: #229954;
|
||
}
|
||
|
||
.task-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-top: auto;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.task-action-btn {
|
||
flex: 1;
|
||
padding: 8px;
|
||
border: none;
|
||
border-radius: 5px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background 0.3s;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 5px;
|
||
min-width: 80px;
|
||
}
|
||
|
||
.action-progress {
|
||
background: #f39c12;
|
||
color: white;
|
||
}
|
||
|
||
.action-progress:hover {
|
||
background: #e67e22;
|
||
}
|
||
|
||
.action-complete {
|
||
background: #27ae60;
|
||
color: white;
|
||
}
|
||
|
||
.action-complete:hover {
|
||
background: #229954;
|
||
}
|
||
|
||
.action-upload {
|
||
background: #3498db;
|
||
color: white;
|
||
}
|
||
|
||
.action-upload:hover {
|
||
background: #2980b9;
|
||
}
|
||
|
||
.action-sync {
|
||
background: #9b59b6;
|
||
color: white;
|
||
}
|
||
|
||
.action-sync:hover {
|
||
background: #8e44ad;
|
||
}
|
||
|
||
.pagination {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
margin-top: 30px;
|
||
}
|
||
|
||
.pagination-btn {
|
||
padding: 8px 12px;
|
||
border: 1px solid #dce4ec;
|
||
background: white;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.pagination-btn:hover:not(:disabled) {
|
||
background: #3498db;
|
||
color: white;
|
||
border-color: #3498db;
|
||
}
|
||
|
||
.pagination-btn:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.pagination-info {
|
||
padding: 8px 12px;
|
||
background: #ecf0f1;
|
||
border-radius: 5px;
|
||
}
|
||
|
||
.loading {
|
||
text-align: center;
|
||
padding: 50px;
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
.loading i {
|
||
animation: spin 1s linear infinite;
|
||
font-size: 30px;
|
||
color: #3498db;
|
||
}
|
||
|
||
.loading-small {
|
||
text-align: center;
|
||
padding: 10px;
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
.no-tasks {
|
||
text-align: center;
|
||
padding: 50px;
|
||
color: #7f8c8d;
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.modal {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0,0,0,0.5);
|
||
z-index: 1000;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal.active {
|
||
display: flex;
|
||
}
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 30px;
|
||
max-width: 600px;
|
||
width: 90%;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.modal-header h3 {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.modal-close {
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
.modal-close:hover {
|
||
color: #2c3e50;
|
||
}
|
||
|
||
.upload-area {
|
||
border: 2px dashed #dce4ec;
|
||
border-radius: 5px;
|
||
padding: 30px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: border-color 0.3s;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.upload-area:hover {
|
||
border-color: #3498db;
|
||
}
|
||
|
||
.upload-area i {
|
||
font-size: 40px;
|
||
color: #3498db;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.upload-area p {
|
||
color: #7f8c8d;
|
||
}
|
||
|
||
.file-input {
|
||
display: none;
|
||
}
|
||
|
||
.selected-files {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.selected-file {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 8px;
|
||
background: #ecf0f1;
|
||
border-radius: 5px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.selected-file .file-name {
|
||
flex: 1;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.selected-file .file-size {
|
||
color: #7f8c8d;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.selected-file .remove-file {
|
||
color: #e74c3c;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.upload-progress, .sync-progress {
|
||
margin-top: 15px;
|
||
padding: 10px;
|
||
background: #ecf0f1;
|
||
border-radius: 5px;
|
||
}
|
||
|
||
.progress-bar {
|
||
height: 10px;
|
||
background: #dce4ec;
|
||
border-radius: 5px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: #27ae60;
|
||
width: 0%;
|
||
transition: width 0.3s;
|
||
}
|
||
|
||
.sync-status {
|
||
margin-top: 10px;
|
||
padding: 10px;
|
||
background: #ecf0f1;
|
||
border-radius: 5px;
|
||
font-size: 13px;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.alert {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
padding: 15px 20px;
|
||
border-radius: 5px;
|
||
margin-bottom: 20px;
|
||
display: none;
|
||
z-index: 2000;
|
||
max-width: 400px;
|
||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||
}
|
||
|
||
.alert.show {
|
||
display: block;
|
||
animation: slideIn 0.3s ease;
|
||
}
|
||
|
||
@keyframes slideIn {
|
||
from {
|
||
transform: translateX(100%);
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
transform: translateX(0);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.alert-success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
|
||
.alert-danger {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
border: 1px solid #f5c6cb;
|
||
}
|
||
|
||
.alert-warning {
|
||
background: #fff3cd;
|
||
color: #856404;
|
||
border: 1px solid #ffeeba;
|
||
}
|
||
|
||
.server-info {
|
||
margin-top: 15px;
|
||
padding: 10px;
|
||
background: #ecf0f1;
|
||
border-radius: 5px;
|
||
font-size: 13px;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
.refresh-btn {
|
||
background: #3498db;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 16px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.refresh-btn:hover {
|
||
background: #2980b9;
|
||
}
|
||
|
||
.badge {
|
||
padding: 3px 8px;
|
||
border-radius: 12px;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.badge-success {
|
||
background: #27ae60;
|
||
color: white;
|
||
}
|
||
|
||
.badge-warning {
|
||
background: #f39c12;
|
||
color: white;
|
||
}
|
||
|
||
.badge-info {
|
||
background: #3498db;
|
||
color: white;
|
||
}
|
||
|
||
small {
|
||
color: #95a5a6;
|
||
font-size: 12px;
|
||
margin-top: 3px;
|
||
}
|
||
</style>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<!-- Шапка -->
|
||
<div class="header">
|
||
<h1>
|
||
<i class="fas fa-cloud-upload-alt"></i>
|
||
Клиент внешнего API
|
||
</h1>
|
||
<div class="user-info">
|
||
<span id="userName">Загрузка...</span>
|
||
<button class="logout-btn" onclick="logout()">
|
||
<i class="fas fa-sign-out-alt"></i> Выход
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Подключение к серверу -->
|
||
<div class="connection-panel">
|
||
<div class="panel-title">
|
||
<i class="fas fa-plug"></i>
|
||
Подключение к внешнему сервису https://minicrm.it25.su 940b4570dc4f43280b038b4417aac4cbb2133dbd98f22303d5c47a947f479a13
|
||
</div>
|
||
|
||
<div class="connection-form">
|
||
<div class="form-group">
|
||
<label>URL сервиса</label>
|
||
<input type="url" id="apiUrl" placeholder="https://example.com" value="">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>API ключ</label>
|
||
<input type="text" id="apiKey" placeholder="Введите API ключ">
|
||
</div>
|
||
<button class="btn btn-primary" onclick="connect()" id="connectBtn">
|
||
<i class="fas fa-link"></i> Подключиться
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Сохраненные подключения -->
|
||
<div class="saved-connections">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||
<span style="font-weight: 500;">Сохраненные подключения:</span>
|
||
<button class="btn btn-secondary" onclick="loadSavedConnections()" style="padding: 5px 10px;">
|
||
<i class="fas fa-sync-alt"></i> Обновить
|
||
</button>
|
||
</div>
|
||
<div class="connections-list" id="connectionsList">
|
||
<div class="loading-small">Загрузка...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Информация о сервере -->
|
||
<div id="serverInfo" class="server-info" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- Фильтры -->
|
||
<div class="filter-panel">
|
||
<div class="form-group">
|
||
<label>Статус задач</label>
|
||
<select id="statusFilter">
|
||
<option value="">Все</option>
|
||
<option value="assigned">Назначена</option>
|
||
<option value="in_progress">В работе</option>
|
||
<option value="completed">Выполнена</option>
|
||
<option value="overdue">Просрочена</option>
|
||
<option value="rework">На доработке</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Поиск</label>
|
||
<input type="text" id="searchFilter" placeholder="Поиск по названию и описанию">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Лимит</label>
|
||
<select id="limitFilter">
|
||
<option value="20">20 задач</option>
|
||
<option value="50" selected>50 задач</option>
|
||
<option value="100">100 задач</option>
|
||
<option value="200">200 задач</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn btn-primary" onclick="loadTasks()" id="loadTasksBtn" disabled>
|
||
<i class="fas fa-search"></i> Загрузить задачи
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Заголовок задач -->
|
||
<div class="tasks-header">
|
||
<h2>
|
||
<i class="fas fa-tasks"></i>
|
||
Задачи из внешнего сервиса
|
||
</h2>
|
||
<div style="display: flex; gap: 15px; align-items: center;">
|
||
<span class="tasks-count" id="tasksCount">0</span>
|
||
<button class="refresh-btn" onclick="loadTasks()" id="refreshTasksBtn" disabled>
|
||
<i class="fas fa-sync-alt"></i> Обновить
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Список задач -->
|
||
<div id="tasksContainer" class="tasks-grid">
|
||
<div class="loading">
|
||
<i class="fas fa-circle-notch"></i>
|
||
<p>Подключитесь к серверу для загрузки задач</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Пагинация -->
|
||
<div class="pagination" id="pagination" style="display: none;">
|
||
<button class="pagination-btn" id="prevPage" onclick="changePage(-1)" disabled>
|
||
<i class="fas fa-chevron-left"></i> Предыдущая
|
||
</button>
|
||
<span class="pagination-info" id="pageInfo">Страница 1 из 1</span>
|
||
<button class="pagination-btn" id="nextPage" onclick="changePage(1)" disabled>
|
||
Следующая <i class="fas fa-chevron-right"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Модальное окно загрузки файлов -->
|
||
<div class="modal" id="uploadModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h3>Загрузка файлов</h3>
|
||
<span class="modal-close" onclick="closeUploadModal()">×</span>
|
||
</div>
|
||
|
||
<div class="upload-area" onclick="document.getElementById('fileInput').click()">
|
||
<i class="fas fa-cloud-upload-alt"></i>
|
||
<p>Нажмите для выбора файлов или перетащите их сюда</p>
|
||
<p style="font-size: 12px; color: #95a5a6;">Максимум 15 файлов</p>
|
||
</div>
|
||
|
||
<input type="file" id="fileInput" class="file-input" multiple onchange="handleFileSelect()">
|
||
|
||
<div class="selected-files" id="selectedFiles" style="display: none;">
|
||
<div style="font-weight: 500; margin-bottom: 10px;">Выбранные файлы:</div>
|
||
<div id="filesList"></div>
|
||
</div>
|
||
|
||
<div class="upload-progress" id="uploadProgress" style="display: none;">
|
||
<div style="margin-bottom: 5px;">Загрузка: <span id="progressPercent">0%</span></div>
|
||
<div class="progress-bar">
|
||
<div class="progress-fill" id="progressBar" style="width: 0%;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 10px; justify-content: flex-end;">
|
||
<button class="btn btn-secondary" onclick="closeUploadModal()">Отмена</button>
|
||
<button class="btn btn-success" onclick="uploadFiles()" id="uploadBtn" disabled>
|
||
<i class="fas fa-upload"></i> Загрузить
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Модальное окно синхронизации задачи -->
|
||
<div class="modal" id="syncModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h3>Синхронизация задачи</h3>
|
||
<span class="modal-close" onclick="closeSyncModal()">×</span>
|
||
</div>
|
||
|
||
<div style="margin-bottom: 20px;">
|
||
<p>Вы синхронизируете задачу: <strong id="syncTaskTitle"></strong></p>
|
||
<p style="font-size: 14px; color: #7f8c8d; margin-top: 5px;">
|
||
<i class="fas fa-info-circle"></i> Исполнители будут сохранены как в исходной задаче
|
||
</p>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 15px;">
|
||
<label>Целевой сервис <span style="color: #e74c3c;">*</span></label>
|
||
<select id="targetService" onchange="toggleTargetServiceInput()">
|
||
<option value="">-- Выберите сервис --</option>
|
||
<optgroup label="Сохраненные подключения" id="savedTargetConnections"></optgroup>
|
||
<option value="new">Указать новый сервис</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div id="newServiceInputs" style="display: none;">
|
||
<div class="form-group" style="margin-bottom: 15px;">
|
||
<label>URL сервиса</label>
|
||
<input type="url" id="targetApiUrl" placeholder="https://example.com">
|
||
</div>
|
||
<div class="form-group" style="margin-bottom: 15px;">
|
||
<label>API ключ</label>
|
||
<input type="text" id="targetApiKey" placeholder="Введите API ключ">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label style="display: flex; align-items: center; gap: 10px;">
|
||
<input type="checkbox" id="syncFiles" checked>
|
||
<span>Синхронизировать файлы</span>
|
||
</label>
|
||
<small style="display: block; margin-top: 5px; color: #7f8c8d;">
|
||
<i class="fas fa-exchange-alt"></i> При синхронизации задача будет обновлена в целевой системе,
|
||
если она там уже существует, или создана новая.
|
||
</small>
|
||
</div>
|
||
|
||
<div id="syncProgress" style="display: none;">
|
||
<div style="margin-bottom: 5px;">Синхронизация: <span id="syncPercent">0%</span></div>
|
||
<div class="progress-bar">
|
||
<div class="progress-fill" id="syncProgressBar" style="width: 0%;"></div>
|
||
</div>
|
||
<div id="syncStatus" class="sync-status"></div>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 10px; justify-content: flex-end;">
|
||
<button class="btn btn-secondary" onclick="closeSyncModal()">Отмена</button>
|
||
<button class="btn btn-success" onclick="syncTask()" id="syncBtn">
|
||
<i class="fas fa-sync-alt"></i> Синхронизировать задачу
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Уведомления -->
|
||
<div id="alert" class="alert"></div>
|
||
<!-- Модальное окно импорта задачи -->
|
||
<div class="modal" id="import-task-modal">
|
||
<div class="modal-content" style="max-width: 600px;">
|
||
<div class="modal-header">
|
||
<h3>Копирование задачи в локальную CRM</h3>
|
||
<span class="modal-close" onclick="closeImportModal()">×</span>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p><strong>Задача:</strong> <span id="import-task-title"></span></p>
|
||
<p><strong>Описание:</strong> <span id="import-task-description"></span></p>
|
||
|
||
<div class="form-group">
|
||
<label for="import-due-date">Дата выполнения:</label>
|
||
<input type="datetime-local" id="import-due-date" class="form-control" required>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Выберите исполнителей (локальные пользователи):</label>
|
||
<div class="users-checklist" id="import-users-checklist" style="max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;"></div>
|
||
</div>
|
||
|
||
<div class="modal-footer" style="margin-top: 20px;">
|
||
<button class="btn btn-secondary" onclick="closeImportModal()">Отмена</button>
|
||
<button class="btn btn-success" onclick="confirmImport()">✅ Импортировать</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script src="client.js"></script>
|
||
</body>
|
||
</html> |