estelam ticket, varizha , others
This commit is contained in:
1 parent
35a1ec1794
commit
6b546aad76
71 files changed
+2865
-191
No files matched your search
@@ -1,17 +1,88 @@
|
||||
{% extends 'base.html' %}{% load static %}
|
||||
{% extends 'base.html' %}{% load static jalali %}
|
||||
{% block title %}{{ page_title }}{% endblock %}
|
||||
{% block content %}<div class="operations-page operations-dispatch">
|
||||
<section class="operations-hero"><div><p class="eyebrow">ارسال انبوه امن</p><h1>ارسال گروهی ایزوله</h1><p>برای هر مخاطب یک تیکت و Magic Link مستقل ایجاد میشود؛ هیچ دریافتکنندهای پاسخ دیگران را نمیبیند.</p></div><div class="security-callout"><span>⌾</span><div><b>حریم خصوصی فعال</b><small>تیکت مستقل برای هر گیرنده</small></div></div></section>
|
||||
<section class="operations-metrics dispatch-metrics" aria-label="آمار ارسالهای گروهی"><article><small>کل عملیات</small><b>{{ metrics.total }}</b></article><article><small>کل گیرندگان</small><b>{{ metrics.recipients }}</b></article><article><small>ارسال کامل</small><b>{{ metrics.sent }}</b></article><article><small>نیازمند پیگیری</small><b>{{ metrics.attention }}</b></article></section>
|
||||
<div class="dispatch-layout"><form method="post" enctype="multipart/form-data" class="dispatch-composer" data-disable-on-submit data-ticket-composer>{% csrf_token %}{% if form.non_field_errors %}<div class="create-form-errors" role="alert">{{ form.non_field_errors }}</div>{% endif %}
|
||||
<section><header><span>۱</span><div><h2>نوع عملیات، مخاطبان و مالکیت</h2><p>قابلیتهای مجاز و گروه هدف را مشخص کنید.</p></div></header><div class="editor-grid"><label><span>{{ form.operation_type.label }}</span>{{ form.operation_type }}{{ form.operation_type.errors }}</label><label><span>{{ form.unit.label }}</span>{{ form.unit }}{{ form.unit.errors }}</label><label><span>{{ form.contact_group.label }}</span>{{ form.contact_group }}{{ form.contact_group.errors }}<small>فقط گروههای واحد انتخابشده معتبر هستند.</small></label></div></section>
|
||||
<section><header><span>۲</span><div><h2>موضوع و دستهبندی</h2><p>عنوان کوتاه و برچسبهای مناسب، گزارشگیری را دقیقتر میکند.</p></div></header><div class="editor-grid"><label><span>{{ form.category.label }}</span>{{ form.category }}{{ form.category.errors }}</label><label><span>{{ form.subject.label }}</span>{{ form.subject }}{{ form.subject.errors }}</label><label class="editor-wide"><span>{{ form.tags.label }}</span>{{ form.tags }}{{ form.tags.errors }}</label></div></section>
|
||||
<section><header><span>۳</span><div><h2>متن و اسناد پیام</h2><p>درخواست را شفاف بنویسید و اسناد لازم را برای همه تیکتهای خصوصی ضمیمه کنید.</p></div></header><label class="message-editor"><span>{{ form.body.label }}</span>{{ form.body }}{{ form.body.errors }}</label><div class="dispatch-attachment-picker media-picker"><div class="attachment-picker-copy"><span class="attachment-icon" aria-hidden="true">+</span><div><b>{{ form.files.label }}</b><small>{{ form.files.help_text }}</small></div></div><div class="media-picker-actions"><label class="media-picker-button gallery-button" for="dispatch-gallery-input">▣ افزودن عکس از گالری</label><label class="media-picker-button" for="dispatch-file-input">+ افزودن فایل</label></div><input id="dispatch-gallery-input" type="file" accept="image/*" multiple data-gallery-input><input id="dispatch-file-input" type="file" multiple data-document-input><span class="canonical-files">{{ form.files }}</span>{{ form.files.errors }}<small class="compression-note" data-compression-status>تصاویر بزرگ پیش از ارسال روی دستگاه شما بهینه میشوند؛ هر پیوست را میتوانید پیش از ثبت حذف کنید.</small><div class="file-preview" data-file-preview aria-live="polite" aria-label="پیشنمایش پیوستهای انتخابشده"></div></div></section>
|
||||
<footer><div><b>قبل از ارسال بررسی کنید</b><small>این عملیات برای همه اعضای گروه تیکت مستقل ایجاد میکند.</small></div><button type="submit">ایجاد تیکتها و قرار دادن پیامک در صف ←</button></footer>
|
||||
</form><aside class="dispatch-history"><header><div><small>ردیابی عملیات</small><h2>ارسالهای اخیر</h2></div><span>{{ page.paginator.count }}</span></header>
|
||||
<form method="get" class="dispatch-filter" aria-label="فیلتر ارسالها"><label class="dispatch-search"><span>جستجو</span><input type="search" name="q" value="{{ request.GET.q }}" placeholder="موضوع، گروه یا کارشناس"></label><div><label><span>وضعیت</span><select name="status"><option value="">همه وضعیتها</option>{% for value,label in dispatch_statuses %}<option value="{{ value }}" {% if request.GET.status == value %}selected{% endif %}>{{ label }}</option>{% endfor %}</select></label><label><span>واحد</span><select name="unit"><option value="">همه واحدها</option>{% for item in units %}<option value="{{ item.pk }}" {% if request.GET.unit == item.pk|stringformat:'s' %}selected{% endif %}>{{ item.name }}</option>{% endfor %}</select></label></div><label><span>گروه مخاطب</span><select name="group"><option value="">همه گروهها</option>{% for item in groups %}<option value="{{ item.pk }}" {% if request.GET.group == item.pk|stringformat:'s' %}selected{% endif %}>{{ item.unit.name }} — {{ item.name }}</option>{% endfor %}</select></label><div><label><span>از تاریخ</span><input type="date" name="created_from" value="{{ request.GET.created_from }}"></label><label><span>تا تاریخ</span><input type="date" name="created_to" value="{{ request.GET.created_to }}"></label></div><footer><button type="submit">اعمال فیلتر</button><a href="{% url 'staff_tickets:dispatch_create' %}">پاک کردن</a></footer></form>
|
||||
<div class="dispatch-results">{% for item in dispatches %}<a class="dispatch-history-card" href="{% url 'staff_tickets:dispatch_detail' item.public_id %}"><span class="dispatch-state state-{{ item.status|lower }}"></span><div><b>{{ item.subject }}</b><small>{{ item.get_operation_type_display }} · {{ item.unit }} · {{ item.contact_group.name }}</small><p><span>{{ item.get_status_display }}</span><span>{{ item.recipient_count }} گیرنده</span><span>{{ item.created_at|date:'Y/m/d H:i' }}</span></p></div><em>←</em></a>{% empty %}<div class="empty-state"><span>⌕</span><p>ارسالی مطابق فیلترهای انتخابی پیدا نشد.</p></div>{% endfor %}</div>
|
||||
{% if page.paginator.num_pages > 1 %}<nav class="operations-pagination" aria-label="صفحهبندی ارسالها">{% if page.has_previous %}<a href="?q={{ request.GET.q|urlencode }}&status={{ request.GET.status|urlencode }}&unit={{ request.GET.unit|urlencode }}&group={{ request.GET.group|urlencode }}&created_from={{ request.GET.created_from|urlencode }}&created_to={{ request.GET.created_to|urlencode }}&page={{ page.previous_page_number }}">قبلی</a>{% endif %}<span>صفحه {{ page.number }} از {{ page.paginator.num_pages }}</span>{% if page.has_next %}<a href="?q={{ request.GET.q|urlencode }}&status={{ request.GET.status|urlencode }}&unit={{ request.GET.unit|urlencode }}&group={{ request.GET.group|urlencode }}&created_from={{ request.GET.created_from|urlencode }}&created_to={{ request.GET.created_to|urlencode }}&page={{ page.next_page_number }}">بعدی</a>{% endif %}</nav>{% endif %}
|
||||
</aside></div>
|
||||
</div>{% endblock %}
|
||||
{% block extra_scripts %}<script defer src="{% static 'vendor/compressor.min.js' %}?v={{ static_asset_version }}"></script><script defer src="{% static 'js/attachment-uploader.js' %}?v={{ static_asset_version }}"></script>{% endblock %}
|
||||
{% block extra_head %}<link rel="stylesheet" href="{% static 'css/dispatch-workspace.css' %}?v={{ static_asset_version }}">{% endblock %}
|
||||
{% block content %}
|
||||
<div class="operations-page operations-dispatch dispatch-workspace" {% if can_create_dispatch %}data-dispatch-workspace{% endif %}>
|
||||
<header class="dispatch-page-heading">
|
||||
<div><p class="dispatch-eyebrow">ارتباط با گروههای مخاطبان</p><h1>ارسال گروهی ایزوله</h1><p>{% if can_create_dispatch %}یک پیام مشترک بفرستید؛ پاسخ هر مخاطب را در تیکت خصوصی خودش پیگیری کنید.{% else %}سوابق ارسالهای مجاز و وضعیت پاسخ مخاطبان را پیگیری کنید.{% endif %}</p></div>
|
||||
<span class="dispatch-privacy">{% include 'tickets/_dispatch_icon.html' with icon='shield' %} پاسخها برای سایر گیرندگان نمایش داده نمیشوند</span>
|
||||
</header>
|
||||
<section class="dispatch-summary-strip" aria-label="آمار ارسالهای گروهی">
|
||||
<div><span>کل ارسالها</span><strong>{{ metrics.total }}</strong></div><div><span>کل گیرندگان</span><strong>{{ metrics.recipients }}</strong></div><div><span>ارسال به درگاه</span><strong>{{ metrics.sent }}</strong></div><div><span>در صف یا نیازمند پیگیری</span><strong>{{ metrics.attention }}</strong></div>
|
||||
</section>
|
||||
<nav class="dispatch-view-switch" aria-label="بخشهای ارسال گروهی">
|
||||
{% if can_create_dispatch %}<a id="dispatch-compose-tab" href="#dispatch-compose-panel" data-dispatch-tab="compose">{% include 'tickets/_dispatch_icon.html' with icon='send' %} ارسال جدید</a>{% endif %}
|
||||
<a id="dispatch-history-tab" href="#dispatch-history-panel" data-dispatch-tab="history">{% include 'tickets/_dispatch_icon.html' with icon='history' %} سوابق ارسال <span>{{ page.paginator.count }}</span></a>
|
||||
</nav>
|
||||
{% if can_create_dispatch %}<section id="dispatch-compose-panel" data-dispatch-panel="compose" aria-labelledby="dispatch-compose-tab">
|
||||
<div class="dispatch-compose-layout">
|
||||
<form id="dispatch-compose-form" method="post" enctype="multipart/form-data" class="dispatch-composer" data-disable-on-submit data-ticket-composer>
|
||||
{% csrf_token %}
|
||||
{% if form.errors %}<div class="dispatch-error-summary" role="alert" tabindex="-1"><b>ارسال انجام نشد؛ موارد زیر را بررسی کنید.</b>{{ form.non_field_errors }}<ul>{% for field in form %}{% for error in field.errors %}<li><a href="#{{ field.id_for_label }}">{{ field.label }}: {{ error }}</a></li>{% endfor %}{% endfor %}</ul>{% if request.FILES %}<p>پیوستها را دوباره انتخاب کنید.</p>{% endif %}</div>{% endif %}
|
||||
<section><header><span>۱</span><div><h2>گیرندگان پیام</h2><p>واحد و گروه هدف را انتخاب کنید.</p></div></header><div class="editor-grid">
|
||||
<label for="{{ form.operation_type.id_for_label }}"><span>{{ form.operation_type.label }}</span>{{ form.operation_type }}{{ form.operation_type.errors }}</label>
|
||||
<label for="{{ form.unit.id_for_label }}"><span>{{ form.unit.label }} <em>الزامی</em></span>{{ form.unit }}{{ form.unit.errors }}</label>
|
||||
<label class="editor-wide" for="{{ form.contact_group.id_for_label }}"><span>{{ form.contact_group.label }} <em>الزامی</em></span>{{ form.contact_group }}{{ form.contact_group.errors }}<small data-dispatch-group-hint aria-live="polite">فقط اعضای فعال دارای شماره همراه، پیام دریافت میکنند.</small></label>
|
||||
</div></section>
|
||||
<section><header><span>۲</span><div><h2>پیام شما</h2><p>موضوع روشن و متن مشترک برای تمام گیرندگان.</p></div></header><div class="editor-grid">
|
||||
<label class="editor-wide" for="{{ form.subject.id_for_label }}"><span>{{ form.subject.label }} <em>الزامی</em></span>{{ form.subject }}{{ form.subject.errors }}</label>
|
||||
<label class="editor-wide" for="{{ form.category.id_for_label }}"><span>{{ form.category.label }} <em>الزامی</em></span>{{ form.category }}{{ form.category.errors }}</label>
|
||||
</div>
|
||||
<label class="message-editor" for="{{ form.body.id_for_label }}"><span>{{ form.body.label }} <em>الزامی</em></span>{{ form.body }}{{ form.body.errors }}<small>این متن برای همه مشترک است؛ پاسخها در گفتوگوهای مستقل ثبت میشوند.</small></label>
|
||||
<details class="dispatch-tags" {% if form.tags.value %}open{% endif %}><summary>برچسبهای گزارشگیری <span>اختیاری</span></summary><label for="{{ form.tags.id_for_label }}">{{ form.tags.label }}{{ form.tags }}{{ form.tags.errors }}<small>برای انتخاب چند برچسب در رایانه، Ctrl یا Command را نگه دارید.</small></label></details>
|
||||
<div class="dispatch-attachment-picker media-picker">
|
||||
<div class="attachment-picker-copy">{% include 'tickets/_dispatch_icon.html' with icon='attachment' %}<div><b>{{ form.files.label }} <small>اختیاری</small></b><small>هر پیوست به تیکت خصوصی تمام گیرندگان اضافه میشود.</small></div></div>
|
||||
<div class="media-picker-actions"><label class="media-picker-button gallery-button" for="dispatch-gallery-input">افزودن عکس از گالری</label><label class="media-picker-button" for="dispatch-file-input">افزودن فایل</label></div>
|
||||
<input id="dispatch-gallery-input" type="file" accept="image/*" multiple data-gallery-input><input id="dispatch-file-input" type="file" multiple data-document-input><span class="canonical-files">{{ form.files }}</span>{{ form.files.errors }}
|
||||
<small class="compression-note" data-compression-status>انتخاب فایل به معنی ارسال نیست؛ پیوستها را پیش از ثبت میتوانید حذف کنید.</small><div class="file-preview" data-file-preview aria-live="polite" aria-label="پیشنمایش پیوستهای انتخابشده"></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="dispatch-response-options"><header><span>۳</span><div><h2>دسترسی به پاسخها</h2><p>روش مشاهده پاسخها پس از ایجاد ارسال قابل تغییر نیست.</p></div></header>
|
||||
<fieldset><legend>{{ form.response_mode.label }}</legend>{{ form.response_mode }}{{ form.response_mode.errors }}</fieldset>
|
||||
<p>در حالت یکجا، متن و پیوست پاسخها برای همه کارکنان، حتی admin، تا بازگشایی قفل میماند. هر مخاطب پاسخ خودش را میبیند.</p>
|
||||
<label class="dispatch-sms-choice">{{ form.notify_opening_sms }} <span>{{ form.notify_opening_sms.label }}</span></label>
|
||||
<small data-opening-sms-hint aria-live="polite">فقط در حالت یکجا و برای حداکثر ۱۵ گیرندهٔ واجد شرایط مجاز است.</small>
|
||||
</section>
|
||||
<footer><div><b>ابتدا بررسی، سپس ارسال</b><small>قبل از تأیید نهایی، پیامک یا تیکتی ایجاد نمیشود.</small></div><button type="submit" data-dispatch-send>ایجاد تیکتها و قرار دادن پیامک در صف</button></footer>
|
||||
</form>
|
||||
<aside class="dispatch-compose-guide" aria-label="خلاصه ارسال جدید">
|
||||
<div class="dispatch-guide-icon">{% include 'tickets/_dispatch_icon.html' with icon='people' %}</div><h2>پیش از ارسال</h2><p>گیرندگان و پیام را بررسی کنید؛ هر فرد یک مسیر اختصاصی برای پاسخ خواهد داشت.</p>
|
||||
<dl><div><dt>واحد ارسالکننده</dt><dd data-dispatch-unit-summary>انتخاب نشده</dd></div><div><dt>گروه مخاطبان</dt><dd data-dispatch-group-summary>انتخاب نشده</dd></div><div><dt>گیرندگان واجد شرایط</dt><dd data-dispatch-count-summary>پس از انتخاب گروه</dd></div></dl>
|
||||
<p class="dispatch-guide-note">{% include 'tickets/_dispatch_icon.html' with icon='shield' %} اطلاعات سایر اعضا در تیکت مخاطب نمایش داده نمیشود.</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}<section id="dispatch-history-panel" class="dispatch-history" data-dispatch-panel="history" aria-labelledby="dispatch-history-tab">
|
||||
<header><div><h2>سوابق و پیگیری ارسالها</h2><p>هر ارسال را باز کنید تا وضعیت پیامکها و پاسخ مخاطبان را ببینید.</p></div><span>{{ page.paginator.count }} ارسال</span></header>
|
||||
<form method="get" class="dispatch-filter" aria-label="فیلتر ارسالها">
|
||||
<label class="dispatch-search"><span>جستجو</span><input type="search" name="q" value="{{ request.GET.q }}" placeholder="موضوع، گروه یا نام کاربری کارشناس"></label>
|
||||
<label><span>وضعیت ارسال</span><select name="status"><option value="">همه وضعیتها</option>{% for value,label in dispatch_statuses %}<option value="{{ value }}" {% if request.GET.status == value %}selected{% endif %}>{{ label }}</option>{% endfor %}</select></label>
|
||||
<details class="dispatch-more-filters" {% if request.GET.unit or request.GET.group or request.GET.created_from or request.GET.created_to %}open{% endif %}><summary>فیلترهای بیشتر</summary><div>
|
||||
<label><span>واحد</span><select name="unit"><option value="">همه واحدها</option>{% for item in history_units %}<option value="{{ item.pk }}" {% if request.GET.unit == item.pk|stringformat:'s' %}selected{% endif %}>{{ item.name }}</option>{% endfor %}</select></label>
|
||||
<label><span>گروه مخاطب</span><select name="group"><option value="">همه گروهها</option>{% for item in history_groups %}<option value="{{ item.pk }}" {% if request.GET.group == item.pk|stringformat:'s' %}selected{% endif %}>{{ item.unit.name }} — {{ item.name }}</option>{% endfor %}</select></label>
|
||||
<label><span>از تاریخ (میلادی)</span><input type="date" name="created_from" value="{{ request.GET.created_from }}"></label><label><span>تا تاریخ (میلادی)</span><input type="date" name="created_to" value="{{ request.GET.created_to }}"></label>
|
||||
</div></details>
|
||||
<footer><button type="submit">اعمال فیلتر</button><a href="{% url 'staff_tickets:dispatch_create' %}#dispatch-history-panel">پاک کردن فیلترها</a></footer>
|
||||
</form>
|
||||
<div class="dispatch-results">{% for item in dispatches %}
|
||||
<a class="dispatch-history-card" href="{% url 'staff_tickets:dispatch_detail' item.public_id %}">
|
||||
<div class="dispatch-history-main"><b>{{ item.subject }}</b><small>{{ item.get_operation_type_display }} · {{ item.unit }} · {{ item.contact_group.name }}</small></div>
|
||||
<span class="report-status status-{{ item.status|lower }}">{{ item.get_status_display }}</span><span class="dispatch-history-count">{{ item.recipient_count }} گیرنده</span>
|
||||
<time datetime="{{ item.created_at|date:'c' }}">{{ item.created_at|jalali_datetime }}</time><span class="dispatch-history-open">مشاهده گزارش {% include 'tickets/_dispatch_icon.html' with icon='arrow' %}</span>
|
||||
</a>
|
||||
{% empty %}<div class="dispatch-empty">{% include 'tickets/_dispatch_icon.html' with icon='history' %}<h3>{% if metrics.total %}ارسالی با این فیلترها پیدا نشد{% else %}هنوز ارسال گروهی ثبت نشده است{% endif %}</h3><p>{% if metrics.total %}عبارت جستجو یا فیلترها را تغییر دهید.{% else %}از بخش «ارسال جدید» اولین پیام گروهی را آماده کنید.{% endif %}</p></div>{% endfor %}</div>
|
||||
{% if page.paginator.num_pages > 1 %}<nav class="operations-pagination" aria-label="صفحهبندی ارسالها">{% if page.has_previous %}<a href="?q={{ request.GET.q|urlencode }}&status={{ request.GET.status|urlencode }}&unit={{ request.GET.unit|urlencode }}&group={{ request.GET.group|urlencode }}&created_from={{ request.GET.created_from|urlencode }}&created_to={{ request.GET.created_to|urlencode }}&page={{ page.previous_page_number }}#dispatch-history-panel">قبلی</a>{% endif %}<span>صفحه {{ page.number }} از {{ page.paginator.num_pages }}</span>{% if page.has_next %}<a href="?q={{ request.GET.q|urlencode }}&status={{ request.GET.status|urlencode }}&unit={{ request.GET.unit|urlencode }}&group={{ request.GET.group|urlencode }}&created_from={{ request.GET.created_from|urlencode }}&created_to={{ request.GET.created_to|urlencode }}&page={{ page.next_page_number }}#dispatch-history-panel">بعدی</a>{% endif %}</nav>{% endif %}
|
||||
</section>
|
||||
<dialog class="dispatch-review-dialog" aria-labelledby="dispatch-review-title" data-dispatch-review>
|
||||
<header><div><p class="dispatch-eyebrow">هنوز ارسال نشده است</p><h2 id="dispatch-review-title">بررسی نهایی ارسال گروهی</h2></div><button type="button" class="dispatch-dialog-close" aria-label="بستن پیشنمایش" data-dispatch-review-close>×</button></header>
|
||||
<dl class="dispatch-review-meta"><div><dt>واحد</dt><dd data-review-unit></dd></div><div><dt>گروه</dt><dd data-review-group></dd></div><div><dt>تعداد گیرندگان</dt><dd data-review-count></dd></div><div><dt>پیوستها</dt><dd data-review-files></dd></div></dl>
|
||||
<p data-review-response-policy></p>
|
||||
<aside class="dispatch-inquiry-recommendation" data-review-inquiry-recommendation hidden role="note"><strong>توصیه برای استعلامگیری</strong><p>برای تمامی استعلامگیریها توصیه میکنیم «بازگشایی یکجا» و «اطلاعرسانی بازگشایی با پیامک» را فعال کنید؛ این دو گزینه به شفافیت و اعتماد مخاطبان کمک میکنند.</p><p data-review-inquiry-limit hidden>در گروههای بیش از ۱۵ گیرنده، پیامک بازگشایی مجاز نیست؛ بازگشایی یکجا را فعال نگه دارید.</p></aside>
|
||||
<h3 data-review-subject></h3><p class="dispatch-review-body" data-review-body></p>
|
||||
<p class="dispatch-review-warning">با تأیید، برای هر گیرنده یک تیکت خصوصی ایجاد و پیامک در صف ارسال قرار میگیرد. تعداد نهایی بر اساس اعضای واجد شرایط در لحظه ثبت محاسبه میشود.</p>
|
||||
<footer><button type="button" class="dispatch-secondary" data-dispatch-review-close>بازگشت و ویرایش</button><button type="button" class="dispatch-primary" data-dispatch-confirm>تأیید و ارسال گروهی</button></footer>
|
||||
</dialog>
|
||||
{{ dispatch_options|json_script:'dispatch-options' }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_scripts %}<script defer src="{% static 'vendor/compressor.min.js' %}?v={{ static_asset_version }}"></script><script defer src="{% static 'js/attachment-uploader.js' %}?v={{ static_asset_version }}"></script><script defer src="{% static 'js/dispatch-workspace.js' %}?v={{ static_asset_version }}"></script>{% endblock %}
|
||||
Reference in new issue
Block a user