160 lines
8.0 KiB
HTML
160 lines
8.0 KiB
HTML
{% extends 'layout/base.html' %}
|
||
{% block title %}Правила{% endblock %}
|
||
{% block body %}
|
||
<div class="content">
|
||
|
||
<div class="card">
|
||
<div class="card-head"><div class="card-title">Правила обработки входящих</div></div>
|
||
<table class="tbl">
|
||
<thead>
|
||
<tr><th style="width:20px"></th><th>Название</th><th>Условие</th><th>Действие</th><th style="width:160px"></th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for r in rules %}
|
||
<tr>
|
||
<td><span class="dot dot-{{ 'green' if r.enabled else 'gray' }}"></span></td>
|
||
<td>
|
||
<strong>{{ r.name }}</strong>
|
||
<div style="display:flex;gap:4px;margin-top:3px;flex-wrap:wrap">
|
||
{% if r.apply_to_existing %}<span class="badge badge-gray" title="Применяется к уже существующим письмам">к существующим</span>{% endif %}
|
||
{% if r.continue_chain %}<span class="badge badge-gray" title="После срабатывания применяются следующие правила">цепочка</span>{% endif %}
|
||
{% if r.apply_to_spam %}<span class="badge badge-amber" title="Фильтр применяется к спаму">спам</span>{% endif %}
|
||
</div>
|
||
</td>
|
||
<td style="color:var(--color-text-secondary);font-size:12px">
|
||
{{ fields[r.field] }} {{ ops[r.op] }} «<em>{{ r.value }}</em>»
|
||
</td>
|
||
<td style="font-size:12px">
|
||
{{ actions[r.action] }}
|
||
{% if r.action == 'move' %} <span class="badge badge-blue">{{ r.target }}</span>
|
||
{% elif r.action in ('forward_copy', 'autoreply') %} <span style="color:var(--color-text-secondary)">→ {{ r.target[:50] }}{% if r.target|length > 50 %}…{% endif %}</span>
|
||
{% endif %}
|
||
</td>
|
||
<td style="text-align:right;white-space:nowrap">
|
||
<div style="display:inline-flex;gap:6px;align-items:center;justify-content:flex-end">
|
||
<form method="post" action="{{ url_for('rules.toggle', rid=r.id) }}" style="display:inline">
|
||
<button class="btn btn-sm" type="submit">{{ 'Выкл' if r.enabled else 'Вкл' }}</button>
|
||
</form>
|
||
<form method="post" action="{{ url_for('rules.delete', rid=r.id) }}" style="display:inline"
|
||
onsubmit="return confirm('Удалить правило?')">
|
||
<button class="btn btn-sm btn-danger" type="submit">Удалить</button>
|
||
</form>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% else %}
|
||
<tr><td colspan="5" style="text-align:center;color:var(--color-text-tertiary);padding:20px">Правил нет</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-head"><div class="card-title">Новое правило</div></div>
|
||
<form method="post" action="{{ url_for('rules.create') }}" id="rule-form">
|
||
<div class="card-body">
|
||
<div class="form-row">
|
||
<label>Название</label>
|
||
<input type="text" name="name" placeholder="Например: Счета в отдельную папку" required>
|
||
</div>
|
||
|
||
<div style="display:grid;grid-template-columns:1fr 1fr 2fr;gap:10px">
|
||
<div class="form-row">
|
||
<label>Поле</label>
|
||
<select name="field">
|
||
{% for k, t in fields_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>
|
||
Оператор
|
||
<span title="содержит — ищет подстроку; равно — точное совпадение; начинается с — префикс; больше, чем — только для размера"
|
||
style="color:var(--color-text-tertiary);cursor:help">ⓘ</span>
|
||
</label>
|
||
<select name="op">
|
||
{% for k, t in ops_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>Значение</label>
|
||
<input type="text" name="value" placeholder="что искать" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:grid;grid-template-columns:1fr 2fr;gap:10px">
|
||
<div class="form-row">
|
||
<label>Действие</label>
|
||
<select name="action" id="rule-action">
|
||
{% for k, t in actions_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="form-row" id="rule-target-row">
|
||
<label id="rule-target-label">Параметр действия</label>
|
||
<input type="text" name="target" id="rule-target-input" placeholder="">
|
||
<select name="target_folder" id="rule-target-folder" style="display:none">
|
||
{% for key, title, ic, is_user in folders %}<option value="{{ key }}">{{ title }}</option>{% endfor %}
|
||
</select>
|
||
<textarea name="target_text" id="rule-target-text" rows="4" style="display:none;font-family:inherit" placeholder="Текст автоответа…"></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top:12px;padding:12px;background:var(--color-background-secondary);border-radius:var(--border-radius-md)">
|
||
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
|
||
<input type="checkbox" name="apply_to_existing" style="width:auto">
|
||
Применить к письмам, которые уже находятся в папке
|
||
</label>
|
||
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
|
||
<input type="checkbox" name="continue_chain" style="width:auto" checked>
|
||
После срабатывания этого фильтра применять другие фильтры
|
||
</label>
|
||
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
|
||
<input type="checkbox" name="apply_to_spam" style="width:auto">
|
||
Применять фильтр к спаму
|
||
</label>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="card-head" style="border-top:0.5px solid var(--color-border-tertiary);border-bottom:none;justify-content:flex-end">
|
||
<button type="submit" class="btn btn-primary">Добавить правило</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
(function(){
|
||
const sel = document.getElementById('rule-action');
|
||
const label = document.getElementById('rule-target-label');
|
||
const inp = document.getElementById('rule-target-input');
|
||
const fld = document.getElementById('rule-target-folder');
|
||
const ta = document.getElementById('rule-target-text');
|
||
function sync(){
|
||
inp.style.display = 'none'; fld.style.display = 'none'; ta.style.display = 'none';
|
||
inp.name = '__off'; fld.name = '__off'; ta.name = '__off';
|
||
switch(sel.value){
|
||
case 'move':
|
||
label.textContent = 'Папка';
|
||
fld.style.display = 'block'; fld.name = 'target';
|
||
break;
|
||
case 'forward_copy':
|
||
label.textContent = 'Адрес для пересылки';
|
||
inp.style.display = 'block'; inp.name = 'target';
|
||
inp.placeholder = 'email@domain';
|
||
break;
|
||
case 'autoreply':
|
||
label.textContent = 'Текст авто-ответа';
|
||
ta.style.display = 'block'; ta.name = 'target';
|
||
break;
|
||
default:
|
||
label.textContent = '—';
|
||
inp.style.display = 'block'; inp.name = 'target';
|
||
inp.placeholder = '(не требуется)';
|
||
}
|
||
}
|
||
sel.addEventListener('change', sync);
|
||
sync();
|
||
})();
|
||
</script>
|
||
{% endblock %}
|