logic.php — Конструктор правил автоматизацииЭтот файл реализует веб-интерфейс для создания и управления умными правилами в системе IoT-автоматизации. Вы можете задавать условия срабатывания по MQTT-топикам, времени суток или дням недели — и указывать, какое действие должно последовать.
Поддерживаемые сценарии:
sensor.temp > 24 && sensor.humidity < 60.Все правила хранятся в таблице automations с поддержкой задержек, повторных попыток, ограничений по времени и флагом persistent для повторяющихся задач. Интерфейс позволяет редактировать, включать/выключать и удалять правила прямо из браузера.
<?php
session_start();
if (!isset($_SESSION['iot_admin'])) {
header('Location: /admin/sensors.php');
exit;
}
try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=iot_db;charset=utf8mb4", "iot_user", "123456");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Ошибка подключения: " . $e->getMessage());
}
$pdo->exec("
CREATE TABLE IF NOT EXISTS automations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL COMMENT 'Название правила',
trigger_topic VARCHAR(255) NOT NULL COMMENT 'Топик-триггер',
condition_operator ENUM('>', '<', '==', '!=', '>=', '<=') NOT NULL DEFAULT '==',
condition_value VARCHAR(50) NOT NULL COMMENT 'Значение для условия',
condition_duration INT DEFAULT 0 COMMENT 'Условие должно соблюдаться N секунд (0 = мгновенно)',
action_topic VARCHAR(255) NOT NULL COMMENT 'Топик для действия',
action_payload TEXT NOT NULL COMMENT 'Payload для отправки',
confirmation_topic VARCHAR(255) NULL COMMENT 'Топик для подтверждения выполнения',
confirmation_timeout INT DEFAULT 30 COMMENT 'Таймаут ожидания подтверждения (сек)',
max_retries INT DEFAULT 3 COMMENT 'Максимум попыток отправки, если нет подтверждения',
retry_delay INT DEFAULT 5 COMMENT 'Задержка между попытками (сек)',
delay_seconds INT DEFAULT 0 COMMENT 'Задержка перед первым действием',
schedule_type ENUM('none', 'daily', 'weekly', 'sunrise', 'sunset') DEFAULT 'none' COMMENT 'Тип расписания',
schedule_time TIME NULL COMMENT 'Время срабатывания',
schedule_days SET('mon','tue','wed','thu','fri','sat','sun') DEFAULT NULL COMMENT 'Дни недели',
time_restriction_start TIME NULL COMMENT 'Ограничение: не раньше этого времени',
time_restriction_end TIME NULL COMMENT 'Ограничение: не позже этого времени',
dependency_topic VARCHAR(255) NULL COMMENT 'Топик-зависимость (например, окно открыто?)',
dependency_value VARCHAR(50) NULL COMMENT 'Значение зависимости (например, closed)',
enabled TINYINT(1) DEFAULT 1 COMMENT 'Активно ли правило',
persistent TINYINT(1) DEFAULT 0 COMMENT 'Не удалять после выполнения (для повторяющихся задач)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_triggered TIMESTAMP NULL COMMENT 'Когда последний раз сработало',
last_confirmed TIMESTAMP NULL COMMENT 'Когда последний раз подтвердилось',
failure_count INT DEFAULT 0 COMMENT 'Сколько раз не подтвердилось'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
$error = '';
$success = '';
// ========== БЕЗОПАСНЫЙ ИНТЕРПРЕТАТОР СКРИПТОВ ==========
function evaluateScriptCondition($script, $sensorData) {
// Заменяем sensor.xxx на массив
$script = preg_replace('/\bsensor\.([a-zA-Z0-9_]+)\b/', '$sensorData[\'$1\']', $script);
$script = preg_replace('/\bsensor\[([\'"])([a-zA-Z0-9_]+)\1\]/', '$sensorData[\'$2\']', $script);
$script = str_replace('data', '$data', $script);
// Проверка на допустимые символы (защита от инъекций)
if (!preg_match('/^[a-zA-Z0-9_\[\]\.\(\)\+\-\*\/\!\&\|\s\=\>\<\,\{\}\'\"]+$/', $script)) {
throw new Exception("Недопустимые символы в выражении");
}
// Запрещённые слова
$forbidden = ['eval', 'exec', 'system', 'shell_exec', 'passthru', 'assert', 'include', 'require'];
foreach ($forbidden as $word) {
if (stripos($script, $word) !== false) {
throw new Exception("Запрещённая функция: " . $word);
}
}
// Создаём временный файл для безопасного выполнения
$tmpFile = sys_get_temp_dir() . '/eval_' . uniqid() . '.php';
file_put_contents($tmpFile, "<?php return (" . $script . ");");
$result = null;
try {
$result = include $tmpFile; // Это не eval() — это подключение файла
} catch (Exception $e) {
unlink($tmpFile);
throw new Exception("Ошибка в выражении: " . $e->getMessage());
}
unlink($tmpFile); // Автоматическое удаление!
return (bool)$result;
}
// ========== КОНЕЦ ФУНКЦИИ ==========
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save'])) {
$name = trim($_POST['name'] ?? '');
$condition_type = $_POST['condition_type'] ?? 'simple';
$trigger_topic = trim($_POST['trigger_topic'] ?? '');
$action_topic = trim($_POST['action_topic'] ?? '');
$action_payload = trim($_POST['action_payload'] ?? '');
$condition_script = null;
$condition_operator = null;
$condition_value = null;
// 👇 ДОБАВЛЯЕМ ЭТИ ПЕРЕМЕННЫЕ — ИХ НЕТ В КОДЕ!
$delay_seconds = (int)($_POST['delay_seconds'] ?? 0);
$schedule_type = $_POST['schedule_type'] ?? 'none';
$schedule_time = $_POST['schedule_time'] ?: null;
$schedule_days = isset($_POST['schedule_days']) ? implode(',', $_POST['schedule_days']) : null;
$condition_duration = (int)($_POST['condition_duration'] ?? 0);
$enabled = isset($_POST['enabled']) ? 1 : 0;
$persistent = isset($_POST['persistent']) ? 1 : 0;
// 👇 Проверяем условие ТОЛЬКО если активация по триггеру (не по расписанию)
// Проверяем условие ТОЛЬКО если:
// - активация по триггеру (schedule_type === 'none') — тогда условие ОБЯЗАТЕЛЬНО
// - или если активация по расписанию, но условие задано — тогда валидируем его (но не требуем!)
if ($schedule_type === 'none') {
// Для триггера — условие обязательно
if ($condition_type === 'simple') {
$condition_operator = $_POST['condition_operator'] ?? '==';
$condition_value = trim($_POST['condition_value'] ?? '');
if (!$condition_operator || !$condition_value) {
$error = "Для простого условия нужно указать оператор и значение";
}
} else { // script
$condition_script = trim($_POST['condition_script'] ?? '');
if (!$condition_script) {
$error = "Для скриптового условия нужно ввести выражение";
}
}
} else {
// Для расписания — условие опционально
if ($condition_type === 'simple') {
$condition_operator = $_POST['condition_operator'] ?? null;
$condition_value = trim($_POST['condition_value'] ?? '');
// Если хоть что-то введено — проверяем, что всё заполнено
if (($condition_operator || $condition_value) && (!$condition_operator || !$condition_value)) {
$error = "Если задано простое условие — укажите и оператор, и значение";
}
} else if ($condition_type === 'script') {
$condition_script = trim($_POST['condition_script'] ?? '');
if ($condition_script === '') {
// пустой скрипт — ок, значит условие не задано
} else {
// если что-то введено — должно быть валидно
// (но у нас валидация внутри evaluateScriptCondition)
}
}
}
if (!$name || (!$trigger_topic && $schedule_type === 'none') || !$action_topic || !$action_payload) {
$error = "Название, действие и payload обязательны.";
} elseif ($error === '') {
try {
$stmt = $pdo->prepare("
INSERT INTO automations (
name, trigger_topic, condition_type, condition_operator, condition_value, condition_script,
condition_duration, -- 👈 ДОБАВЛЕНО
action_topic, action_payload, confirmation_topic, confirmation_timeout, max_retries, retry_delay,
delay_seconds, schedule_type, schedule_time, schedule_days, time_restriction_start, time_restriction_end,
dependency_topic, dependency_value, enabled, persistent
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) --
ON DUPLICATE KEY UPDATE
name = VALUES(name),
trigger_topic = VALUES(trigger_topic),
condition_type = VALUES(condition_type),
condition_operator = VALUES(condition_operator),
condition_value = VALUES(condition_value),
condition_script = VALUES(condition_script),
condition_duration = VALUES(condition_duration), -- 👈 ДОБАВЛЕНО
action_topic = VALUES(action_topic),
action_payload = VALUES(action_payload),
confirmation_topic = VALUES(confirmation_topic),
confirmation_timeout = VALUES(confirmation_timeout),
max_retries = VALUES(max_retries),
retry_delay = VALUES(retry_delay),
delay_seconds = VALUES(delay_seconds),
schedule_type = VALUES(schedule_type),
schedule_time = VALUES(schedule_time),
schedule_days = VALUES(schedule_days),
time_restriction_start = VALUES(time_restriction_start),
time_restriction_end = VALUES(time_restriction_end),
dependency_topic = VALUES(dependency_topic),
dependency_value = VALUES(dependency_value),
enabled = VALUES(enabled)
");
$stmt->execute([
$name,
$trigger_topic,
$condition_type,
$condition_operator,
$condition_value,
$condition_script,
$condition_duration, // 👈 ДОБАВЛЕНО — 7-й параметр
$action_topic,
$action_payload,
$_POST['confirmation_topic'] ?? null,
(int)($_POST['confirmation_timeout'] ?? 30),
(int)($_POST['max_retries'] ?? 3),
(int)($_POST['retry_delay'] ?? 5),
(int)($_POST['delay_seconds'] ?? 0),
$schedule_type,
$schedule_time,
$schedule_days,
$_POST['time_restriction_start'] ?: null,
$_POST['time_restriction_end'] ?: null,
$_POST['dependency_topic'] ?? null,
$_POST['dependency_value'] ?? null,
$enabled,
$persistent
]);
$success = "Правило успешно сохранено!";
} catch (Exception $e) {
$error = "Ошибка сохранения: " . $e->getMessage();
}
}
}
// Обработка удаления
if (isset($_GET['delete'])) {
$id = (int)$_GET['delete'];
$stmt = $pdo->prepare("DELETE FROM automations WHERE id = ?");
$stmt->execute([$id]);
header("Location: logic.php");
exit;
}
$stmt = $pdo->query("SELECT DISTINCT topic FROM sensor_data ORDER BY topic");
$topics = $stmt->fetchAll(PDO::FETCH_COLUMN);
$stmt = $pdo->query("SELECT * FROM automations ORDER BY created_at DESC");
$rules = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>🧠 Логика автоматизации</title>
<style>
:root {
--bg-main: #1e1e2e;
--bg-panel: #252536;
--bg-input: #2d2d3d;
--text: #e0e0ff;
--text-muted: #a0a0c0;
--border: #3a3a4a;
--accent: #6c63ff;
--accent-hover: #5a52d5;
--success: #4caf50;
--error: #f44336;
--warning: #ff9800;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background-color: var(--bg-main);
color: var(--text);
padding: 20px;
margin: 0;
}
h1, h2 {
color: #ffffff;
margin-bottom: 20px;
}
.form-box {
background: var(--bg-panel);
padding: 20px;
border-radius: 10px;
margin-bottom: 30px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
border: 1px solid var(--border);
}
label {
display: block;
margin-top: 14px;
color: #d0d0e8;
font-size: 0.95em;
}
small {
display: block;
color: var(--text-muted);
font-size: 0.85em;
margin-top: 4px;
}
input, select, textarea, datalist {
width: 100%;
padding: 10px;
margin-top: 6px;
background: var(--bg-input);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text);
font-size: 1em;
}
input[type="checkbox"] {
width: auto;
margin-right: 8px;
}
.schedule-days label {
display: inline-flex;
align-items: center;
margin-right: 16px;
color: var(--text);
}
button, input[type="submit"] {
padding: 10px 20px;
background: var(--accent);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: background 0.2s;
}
button:hover, input[type="submit"]:hover {
background: var(--accent-hover);
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background: var(--bg-panel);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
th, td {
padding: 12px;
border: 1px solid var(--border);
text-align: left;
color: var(--text);
}
th {
background: #2a2a3a;
font-weight: 600;
}
.status-enabled {
color: var(--success);
}
.status-disabled {
color: var(--error);
}
.actions a {
margin-right: 12px;
text-decoration: none;
color: var(--accent);
}
.actions a:hover {
text-decoration: underline;
}
.message {
padding: 12px;
margin: 14px 0;
border-radius: 6px;
font-weight: 500;
}
.error {
background: rgba(244, 67, 54, 0.15);
color: #f8d7da;
border: 1px solid var(--error);
}
.success {
background: rgba(76, 175, 80, 0.15);
color: #d4edda;
border: 1px solid var(--success);
}
code {
background: rgba(0, 0, 0, 0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
color: #a0f0a0;
}
</style>
</head>
<body>
<h1>🧠 Логика автоматизации</h1>
<?php if ($error): ?>
<div class="message error"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="message success"><?= htmlspecialchars($success) ?></div>
<?php endif; ?>
<div class="form-box">
<h2>➕ Добавить / Редактировать правило</h2>
<form method="post">
<label>Название правила<br>
<input type="text" name="name" required placeholder="Например: Включить свет в 19:00">
</label>
<label>Тип активации<br>
<select name="schedule_type" onchange="toggleSchedule(this.value)">
<option value="none">По триггеру (MQTT)</option>
<option value="daily">Каждый день в заданное время</option>
<option value="weekly">По дням недели</option>
</select>
</label>
<div id="triggerSection">
<!-- Топик-триггер теперь ВСЕГДА виден -->
<label>Топик для условия (опционально)<br>
<input list="topics" name="trigger_topic" placeholder="sensors/temperature/outside">
<small>Используется для проверки условия (например, температура < 5). Оставьте пустым, чтобы игнорировать.</small>
</label>
<!-- <label>Топик-триггер (что слушаем)<br>
<input list="topics" name="trigger_topic" placeholder="sensors/temperature/living_room">
<datalist id="topics">
<?php foreach ($topics as $topic): ?>
<option value="<?= htmlspecialchars($topic) ?>">
<?php endforeach; ?>
</datalist>
</label>
-->
</div>
<!-- ========== Условие (показывается всегда, но опционально для расписания) ========== -->
<label>Тип условия<br>
<select name="condition_type" onchange="toggleConditionType(this.value)">
<option value="simple">Простое (A > B)</option>
<option value="script">Скрипт (JS-выражение)</option>
</select>
</label>
<div id="simpleCondition" style="display:block;">
<label>Оператор<br>
<select name="condition_operator" style="width: auto; margin-right: 10px;">
<option value=">">></option>
<option value="<"><</option>
<option value="==" selected>=</option>
<option value="!=">!=</option>
<option value=">=">>=</option>
<option value="<="><=</option>
</select>
</label>
<label>Значение<br>
<input type="text" name="condition_value" placeholder="25">
</label>
</div>
<div id="scriptCondition" style="display:none; margin-top: 15px;">
<label>JS-условие (используй переменные: sensor.{topic}, data)<br>
<textarea name="condition_script" rows="4" placeholder="
// Примеры:
sensor.temperature > 24 && sensor.humidity < 60
sensor.motion_1 || sensor.motion_2
"></textarea>
<small>Поддерживаются: <code>sensor.{topic}</code>, <code>data</code>, числа, &&, ||, ==, >, <, !, (), [], .</small>
</label>
</div>
<label>Условие должно соблюдаться (сек)<br>
<input type="number" name="condition_duration" value="0" min="0" placeholder="0 = мгновенно">
<small>Например: температура > 25 в течение 300 сек — только тогда срабатывает.</small>
</label>
<div id="scheduleSection" style="display:none;">
<label>Время срабатывания (HH:MM:SS)<br>
<input type="time" name="schedule_time" step="1">
</label>
<div id="weeklyDays" style="display:none; margin-top:10px;">
<label>Дни недели<br>
<div class="schedule-days">
<?php
$days = ['mon'=>'Пн', 'tue'=>'Вт', 'wed'=>'Ср', 'thu'=>'Чт', 'fri'=>'Пт', 'sat'=>'Сб', 'sun'=>'Вс'];
foreach ($days as $k => $v): ?>
<label>
<input type="checkbox" name="schedule_days[]" value="<?= $k ?>">
<?= $v ?>
</label>
<?php endforeach; ?>
<label>
<input type="checkbox" name="persistent"> Повторять (не удалять после выполнения)
</label>
</div>
</label>
<label>Ограничение по времени суток (не раньше)<br>
<input type="time" name="time_restriction_start">
</label>
<label>Ограничение по времени суток (не позже)<br>
<input type="time" name="time_restriction_end">
</label>
<label>Зависимость от другого устройства (опционально)<br>
<input list="topics" name="dependency_topic" placeholder="sensors/window/kitchen">
<small>Правило сработает ТОЛЬКО если это устройство имеет нужное значение.</small>
</label>
<label>Требуемое значение зависимости<br>
<input type="text" name="dependency_value" placeholder="closed / true / 0">
</label>
</div>
</div>
<label>Топик для действия (куда отправить)<br>
<input list="topics" name="action_topic" required placeholder="devices/light/living_room/set">
</label>
<label>Payload (что отправить)<br>
<textarea name="action_payload" rows="2" required placeholder='{"state": "ON"}'>{"state": "ON"}</textarea>
</label>
<label>Топик подтверждения (опционально)<br>
<input list="topics" name="confirmation_topic" placeholder="devices/valve/state или zigbee2mqtt/0x1234/state">
<small>Устройство должно опубликовать сюда состояние после выполнения действия. Если не указано — правило считается выполненным сразу.</smal>
</label>
<label>Таймаут подтверждения (сек)<br>
<input type="number" name="confirmation_timeout" value="30" min="5">
</label>
<label>Максимум попыток<br>
<input type="number" name="max_retries" value="3" min="0" max="10">
</label>
<label>Задержка между попытками (сек)<br>
<input type="number" name="retry_delay" value="5" min="1">
</label>
<label>Задержка перед действием (сек)<br>
<input type="number" name="delay_seconds" value="0" min="0">
</label>
<label>
<input type="checkbox" name="enabled" checked> Активно
</label>
<br><br>
<input type="submit" name="save" value="💾 Сохранить правило">
</form>
</div>
<h2>📋 Все правила</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Название</th>
<th>Тип</th>
<th>Триггер/Время</th>
<th>Действие</th>
<th>Активно</th>
<th>Управление</th>
<th>Условие длится</th>
<th>Подтверждение</th>
<th>Зависимость</th>
</tr>
</thead>
<tbody>
<?php foreach ($rules as $rule): ?>
<tr>
<td><?= $rule['id'] ?></td>
<td><?= htmlspecialchars($rule['name']) ?></td>
<td>
<?php
$type = $rule['schedule_type'];
if ($type === 'none') echo 'Триггер';
elseif ($type === 'daily') echo 'Ежедневно';
elseif ($type === 'weekly') echo 'По дням';
?>
</td>
<td>
<?php if ($rule['schedule_type'] !== 'none'): ?>
<?= $rule['schedule_time'] ?>
<?php if ($rule['schedule_type'] === 'weekly' && $rule['schedule_days']): ?>
(<?= $rule['schedule_days'] ?>)
<?php endif; ?>
<?php else: ?>
<code><?= htmlspecialchars($rule['trigger_topic']) ?></code><br>
<?= htmlspecialchars($rule['condition_operator']) ?> <?= htmlspecialchars($rule['condition_value']) ?>
<?php endif; ?>
</td>
<td>
<b>Топик:</b> <code><?= htmlspecialchars($rule['action_topic']) ?></code><br>
<b>Payload:</b> <code><?= htmlspecialchars($rule['action_payload']) ?></code><br>
<?php if ($rule['delay_seconds'] > 0): ?>
<b>Задержка:</b> <?= $rule['delay_seconds'] ?> сек
<?php endif; ?>
</td>
<td class="<?= $rule['enabled'] ? 'status-enabled' : 'status-disabled' ?>">
<?= $rule['enabled'] ? '✅ Да' : '❌ Нет' ?>
</td>
<td>
<a href="#" onclick="fillForm(
'<?= addslashes($rule['name']) ?>',
'<?= addslashes($rule['trigger_topic']) ?>',
'<?= addslashes($rule['condition_operator']) ?>',
'<?= addslashes($rule['condition_value']) ?>',
<?= (int)$rule['condition_duration'] ?>,
'<?= addslashes($rule['action_topic']) ?>',
'<?= addslashes($rule['action_payload']) ?>',
'<?= addslashes($rule['confirmation_topic'] ?: '') ?>',
<?= (int)$rule['confirmation_timeout'] ?>,
<?= (int)$rule['max_retries'] ?>,
<?= (int)$rule['retry_delay'] ?>,
<?= (int)$rule['delay_seconds'] ?>,
'<?= addslashes($rule['schedule_type']) ?>',
'<?= addslashes($rule['schedule_time'] ?: '') ?>',
'<?= addslashes($rule['schedule_days'] ?: '') ?>',
'<?= addslashes($rule['time_restriction_start'] ?: '') ?>',
'<?= addslashes($rule['time_restriction_end'] ?: '') ?>',
'<?= addslashes($rule['dependency_topic'] ?: '') ?>',
'<?= addslashes($rule['dependency_value'] ?: '') ?>',
<?= $rule['enabled'] ? 'true' : 'false' ?>
)">✏️ Ред.</a>
<a href="?delete=<?= $rule['id'] ?>" onclick="return confirm('Удалить правило?')">🗑️ Удалить</a>
</td>
<td>
<?php if ($rule['condition_duration'] > 0): ?>
<?= $rule['condition_duration'] ?> сек
<?php else: ?>
мгновенно
<?php endif; ?>
</td>
<td>
<?php if ($rule['confirmation_topic']): ?>
<code><?= htmlspecialchars($rule['confirmation_topic']) ?></code><br>
таймаут: <?= $rule['confirmation_timeout'] ?>с, попыток: <?= $rule['max_retries'] ?>
<?php else: ?>
—
<?php endif; ?>
</td>
<td>
<?php if ($rule['dependency_topic']): ?>
<code><?= htmlspecialchars($rule['dependency_topic']) ?> == <?= htmlspecialchars($rule['dependency_value']) ?></code>
<?php else: ?>
—
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<script>
function toggleSchedule(type) {
// const triggerSection = document.getElementById('triggerSection');
const scheduleSection = document.getElementById('scheduleSection');
const weeklyDays = document.getElementById('weeklyDays');
// if (type === 'none') {
// triggerSection.style.display = 'block';
// scheduleSection.style.display = 'none';
// } else {
// triggerSection.style.display = 'none';
scheduleSection.style.display = 'block';
weeklyDays.style.display = (type === 'weekly') ? 'block' : 'none';
// }
}
function fillForm(
name, trigger_topic, condition_operator, condition_value, condition_duration,
action_topic, action_payload, confirmation_topic, confirmation_timeout, max_retries, retry_delay,
delay_seconds, schedule_type, schedule_time, schedule_days_str, time_restriction_start, time_restriction_end,
dependency_topic, dependency_value, enabled
) {
document.querySelector("[name='name']").value = name;
document.querySelector("[name='trigger_topic']").value = trigger_topic;
document.querySelector("[name='condition_operator']").value = condition_operator;
document.querySelector("[name='condition_value']").value = condition_value;
document.querySelector("[name='condition_duration']").value = condition_duration;
document.querySelector("[name='action_topic']").value = action_topic;
document.querySelector("[name='action_payload']").value = action_payload;
document.querySelector("[name='confirmation_topic']").value = confirmation_topic;
document.querySelector("[name='confirmation_timeout']").value = confirmation_timeout;
document.querySelector("[name='max_retries']").value = max_retries;
document.querySelector("[name='retry_delay']").value = retry_delay;
document.querySelector("[name='delay_seconds']").value = delay_seconds;
document.querySelector("[name='schedule_type']").value = schedule_type;
document.querySelector("[name='schedule_time']").value = schedule_time;
document.querySelector("[name='time_restriction_start']").value = time_restriction_start;
document.querySelector("[name='time_restriction_end']").value = time_restriction_end;
document.querySelector("[name='dependency_topic']").value = dependency_topic;
document.querySelector("[name='dependency_value']").value = dependency_value;
// Чекбоксы дней
const checkboxes = document.querySelectorAll("[name='schedule_days[]']");
const selectedDays = schedule_days_str ? schedule_days_str.split(',') : [];
checkboxes.forEach(cb => {
cb.checked = selectedDays.includes(cb.value);
});
document.querySelector("[name='enabled']").checked = enabled;
toggleSchedule(schedule_type);
window.scrollTo(0, 0);
}
function toggleConditionType(type) {
document.getElementById('simpleCondition').style.display = type === 'simple' ? 'block' : 'none';
document.getElementById('scriptCondition').style.display = type === 'script' ? 'block' : 'none';
}
</script>
<form method="post" action="/admin/logout.php" style="margin-top: 30px;">
<button type="submit">🚪 Выйти</button>
</form>
</body>
</html>
Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!