БЫЛО: Каждая из 14 страниц имела своё собственное вшитое меню
с разным набором кнопок (от 4 до 10 пунктов)
СТАЛО: Все 14 страниц наследуют base.html с единым меню из 14 пунктов
в 4 разделах: Пользователи / Коммуникации / Контент / Система
Убрано 1949 строк дублирующегося кода, добавлено 1323 строки чистого контента.
Экономия: -626 строк (32% сокращение).
Переписанные страницы:
- dashboard.html, users.html, verification.html
- phones.html, polls.html, events.html
- schedules.html, ads.html, scheduled_posts.html, export.html
Результат: На ЛЮБОЙ странице пользователь видит ВСЕ 14 пунктов меню.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
104 lines
4.7 KiB
HTML
104 lines
4.7 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Расписания - Домовой Бот{% endblock %}
|
|
|
|
{% block nav_schedules %}active{% endblock %}
|
|
|
|
{% block content %}
|
|
<h2 class="mb-4"><i class="bi bi-clock"></i> Расписания отключений</h2>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header bg-primary text-white">
|
|
<h5 class="mb-0"><i class="bi bi-plus-lg"></i> Добавить расписание</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="addScheduleForm" class="row g-3">
|
|
<div class="col-md-3">
|
|
<input type="text" class="form-control" id="scheduleTitle" placeholder="Название" required>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select" id="scheduleType">
|
|
<option value="water">💧 Вода</option>
|
|
<option value="electricity">⚡ Электричество</option>
|
|
<option value="heating">🔥 Отопление</option>
|
|
<option value="gas">🔶 Газ</option>
|
|
<option value="elevator">🛗 Лифт</option>
|
|
<option value="general">📋 Общее</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<input type="datetime-local" class="form-control" id="scheduleStart" required>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<input type="datetime-local" class="form-control" id="scheduleEnd">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button type="submit" class="btn btn-primary w-100">Добавить</button>
|
|
</div>
|
|
<div class="col-md-12">
|
|
<textarea class="form-control" id="scheduleDesc" placeholder="Описание" rows="2"></textarea>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr><th>Тип</th><th>Название</th><th>Начало</th><th>Конец</th><th>Описание</th><th>Действия</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for schedule in schedules %}
|
|
<tr>
|
|
<td>
|
|
{% if schedule.schedule_type == 'water' %}💧
|
|
{% elif schedule.schedule_type == 'electricity' %}⚡
|
|
{% elif schedule.schedule_type == 'heating' %}🔥
|
|
{% elif schedule.schedule_type == 'gas' %}🔶
|
|
{% elif schedule.schedule_type == 'elevator' %}🛗
|
|
{% else %}📋{% endif %}
|
|
</td>
|
|
<td>{{ schedule.title }}</td>
|
|
<td>{{ schedule.start_time.strftime('%d.%m.%Y %H:%M') if schedule.start_time else '—' }}</td>
|
|
<td>{{ schedule.end_time.strftime('%d.%m.%Y %H:%M') if schedule.end_time else '—' }}</td>
|
|
<td>{{ schedule.description or '—' }}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-danger" onclick="deleteSchedule({{ schedule.schedule_id }})">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_script %}
|
|
<script>
|
|
document.getElementById('addScheduleForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const data = {
|
|
title: document.getElementById('scheduleTitle').value,
|
|
schedule_type: document.getElementById('scheduleType').value,
|
|
start_time: new Date(document.getElementById('scheduleStart').value).toISOString(),
|
|
end_time: document.getElementById('scheduleEnd').value ? new Date(document.getElementById('scheduleEnd').value).toISOString() : null,
|
|
description: document.getElementById('scheduleDesc').value,
|
|
is_active: true
|
|
};
|
|
const r = await fetch('/api/schedule/add', {
|
|
method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)
|
|
});
|
|
const result = await r.json();
|
|
if (result.success) { alert('✅ Расписание добавлено'); location.reload(); }
|
|
});
|
|
async function deleteSchedule(id) {
|
|
if (!confirm('Удалить расписание?')) return;
|
|
const r = await fetch(`/api/schedule/${id}/delete`, { method: 'POST' });
|
|
const result = await r.json();
|
|
if (result.success) { alert('✅ Удалено'); location.reload(); }
|
|
}
|
|
</script>
|
|
{% endblock %}
|