This commit is contained in:
javad committed 2026-10-10 14:21:04 +03:30
1 parent 250cdbab7f
commit 5c6069c3ef
87 files changed
+29209 -3697

No files matched your search

@@ -0,0 +1,149 @@
{% extends "./base.html" %}
{% load custom_tags %}
{% block bodyPage %}
<div class="container mt-5" dir="rtl">
<h1 class="title is-4">صف پیامک‌ها</h1>
<div class="notification is-warning is-light">
پیامک‌ها تا زمانی که مدیر آن‌ها را تأیید نکند ارسال نمی‌شوند. صف را بازبینی
کنید، موارد نامناسب را حذف کنید و سپس تأیید بزنید.
<br>
حذف یک مورد، فقط همان نوبت را کنسل می‌کند. یادآوری‌های دوره‌ای (بازدید و ثبت
اطلاعات چک) در <strong>دورهٔ بعدی</strong> دوباره ساخته می‌شوند؛ پس با حذف یک
مورد، پیامک برای آن مشتری برای همیشه قطع نمی‌شود.
</div>
<div class="columns is-multiline mb-2" dir="rtl">
<div class="column is-narrow">
<div class="box py-3 px-4 has-text-centered">
<p class="heading mb-0">کل صف</p>
<p class="title is-5 mb-0">{{ total_count }}</p>
</div>
</div>
{% for code, label, count in status_stats %}
<div class="column is-narrow">
<a href="?status={{ code }}" class="box py-3 px-4 has-text-centered"
{% if status == code %}style="border:2px solid #3273dc"{% endif %}>
<p class="heading mb-0">{{ label }}</p>
<p class="title is-5 mb-0">{{ count }}</p>
</a>
</div>
{% endfor %}
</div>
{% if status or delivery %}
<p class="mb-3">نتایج فیلترشده: <strong>{{ filtered_count }}</strong> مورد — <a href="{% url 'admin_panel:sms_queue' %}">حذف فیلتر</a></p>
{% endif %}
<form method="get" class="field has-addons mb-3">
<div class="control">
<div class="select">
<select name="status">
<option value="">همهٔ وضعیت‌ها</option>
{% for value, label in status_choices %}
<option value="{{ value }}" {% if status == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="control">
<div class="select">
<select name="delivery">
<option value="">همهٔ دلیوری‌ها</option>
{% for value, label in delivery_choices %}
<option value="{{ value }}" {% if delivery == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="control"><button class="button" type="submit">فیلتر</button></div>
</form>
<form method="post" action="{% url 'admin_panel:sms_queue_bulk' %}" id="bulk-form" class="mb-3">
{% csrf_token %}
<button class="button is-success" name="action" value="approve_all"
onclick="return confirm('همهٔ پیامک‌های «در انتظار تأیید» تأیید و ارسال شوند؟');">
تأیید همهٔ موارد در انتظار ({{ pending_count }})
</button>
<button class="button is-info" name="action" value="approve_selected">تأیید انتخاب‌شده‌ها</button>
<button class="button is-danger" name="action" value="delete_selected"
onclick="return confirm('موارد انتخاب‌شده از صف حذف شوند؟');">حذف انتخاب‌شده‌ها</button>
</form>
<div class="notification is-danger is-light is-flex is-align-items-center is-justify-content-space-between mb-3">
<span>خالی کردن کل صف: همهٔ پیامک‌ها (در هر وضعیتی) حذف می‌شوند و دیگر بازنمی‌گردند.</span>
<form method="post" action="{% url 'admin_panel:sms_queue_empty' %}"
onsubmit="return confirm('کل صف پیامک خالی شود؟ این پیامک‌ها دیگر هرگز ارسال یا بازسازی نمی‌شوند.');">
{% csrf_token %}
<button class="button is-danger" type="submit">خالی کردن کل صف</button>
</form>
</div>
<div class="table-container">
<table class="table is-fullwidth is-narrow is-hoverable is-striped">
<thead>
<tr>
<th><input type="checkbox" onclick="document.querySelectorAll('.row-check').forEach(c => c.checked = this.checked)"></th>
<th>شناسه</th><th>مشتری</th><th>نوع</th><th>شماره</th>
<th>وضعیت</th><th>دلیوری</th><th>تلاش</th><th>ایجاد</th><th>ارسال</th><th>خطا</th><th></th>
</tr>
</thead>
<tbody>
{% for item in queue %}
<tr>
<td><input class="row-check" type="checkbox" form="bulk-form" name="ids" value="{{ item.id }}"></td>
<td>{{ item.id }}</td>
<td>
{% if item.customer_id %}
<a href="{% url 'admin_panel:customer' item.customer_id %}">{{ item.customer.name_family }}</a>
{% else %}—{% endif %}
</td>
<td>{{ item.get_sms_type_display }}</td>
<td dir="ltr">{{ item.phone_number }}</td>
<td>{{ item.get_status_display }}</td>
<td>{{ item.get_delivery_status_display|default:'—' }}</td>
<td>{{ item.attempts }}</td>
<td>{{ item.created_at|toJalaliDT }}</td>
<td>{{ item.sent_at|toJalaliDT|default:'—' }}</td>
<td class="is-size-7">{{ item.last_error|truncatechars:60 }}</td>
<td>
<div class="buttons are-small">
{% if item.status == 'pending' %}
<form method="post" action="{% url 'admin_panel:sms_queue_approve' item.id %}">
{% csrf_token %}
<button class="button is-small is-success" type="submit">تأیید</button>
</form>
{% elif item.status == 'failed' %}
<form method="post" action="{% url 'admin_panel:sms_queue_retry' item.id %}">
{% csrf_token %}
<button class="button is-small is-warning" type="submit">ارسال مجدد</button>
</form>
{% endif %}
<form method="post" action="{% url 'admin_panel:sms_queue_delete' item.id %}"
onclick="return confirm('این پیامک از صف حذف شود؟');">
{% csrf_token %}
<button class="button is-small is-danger" type="submit">حذف</button>
</form>
</div>
</td>
</tr>
{% empty %}
<tr><td colspan="12" class="has-text-centered">موردی یافت نشد.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% if queue.has_other_pages %}
<nav class="pagination" role="navigation" aria-label="pagination">
{% if queue.has_previous %}
<a class="pagination-previous" href="?page={{ queue.previous_page_number }}{% if status %}&status={{ status }}{% endif %}{% if delivery %}&delivery={{ delivery }}{% endif %}">قبلی</a>
{% endif %}
{% if queue.has_next %}
<a class="pagination-next" href="?page={{ queue.next_page_number }}{% if status %}&status={{ status }}{% endif %}{% if delivery %}&delivery={{ delivery }}{% endif %}">بعدی</a>
{% endif %}
<ul class="pagination-list"><li><span class="pagination-link">صفحه {{ queue.number }} از {{ queue.paginator.num_pages }}</span></li></ul>
</nav>
{% endif %}
</div>
{% endblock %}