Категории

logic.php конструктор правил автоматизации

23.11.2025 12:46 | коды из категории: IOT умный дом

про logic.php конструктор правил автоматизации

🧠 logic.php — Конструктор правил автоматизации

Этот файл реализует веб-интерфейс для создания и управления умными правилами в системе IoT-автоматизации. Вы можете задавать условия срабатывания по MQTT-топикам, времени суток или дням недели — и указывать, какое действие должно последовать.

Поддерживаемые сценарии:

Все правила хранятся в таблице 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>

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Важно: Блог-эксперимент

Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.

Посетителей сегодня: 0


кто я | книга | контакты без контактов

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA