diff --git a/apps/tickets/forms.py b/apps/tickets/forms.py index ea2fe6d..07c0b1d 100644 --- a/apps/tickets/forms.py +++ b/apps/tickets/forms.py @@ -181,7 +181,13 @@ class StaffContactForm(forms.Form): last_name = forms.CharField(label="نام خانوادگی", max_length=100, required=False) organization_name = forms.CharField(label="نام شرکت / سازمان", max_length=180, required=False) stakeholder_type = forms.ChoiceField(label="نوع مخاطب", choices=CustomerProfile.StakeholderType.choices) - groups = forms.ModelMultipleChoiceField(label="عضویت در گروهها", queryset=ContactGroup.objects.none(), required=True, help_text="حداقل یک گروه برای تعیین مالکیت واحدی مخاطب انتخاب کنید.") + groups = forms.ModelMultipleChoiceField( + label="عضویت در گروهها", + queryset=ContactGroup.objects.none(), + required=True, + help_text="گروههای موردنظر را روشن یا خاموش کنید؛ حداقل یک گروه باید باقی بماند.", + widget=forms.CheckboxSelectMultiple(attrs={"data-contact-group-option": ""}), + ) province = forms.ChoiceField(label="استان", required=False) city = forms.ChoiceField(label="شهر", required=False) diff --git a/static/css/operations.css b/static/css/operations.css index ca93423..f99c220 100644 --- a/static/css/operations.css +++ b/static/css/operations.css @@ -39,7 +39,8 @@ .contact-card-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem;padding:1rem;background:#f7fafc}.contact-card{display:grid;gap:.75rem;min-width:0;border:1px solid #dce7ef;border-radius:1rem;background:#fff;padding:1rem;transition:.18s ease;box-shadow:0 10px 28px -26px #08376b}.contact-card:hover{transform:translateY(-2px);border-color:#9dcbe2;box-shadow:0 18px 36px -29px #08376b}.contact-card header{display:flex;align-items:center;gap:.7rem}.contact-avatar{display:grid;width:2.65rem;height:2.65rem;flex:none;place-items:center;border-radius:.8rem;background:linear-gradient(145deg,#dff4ff,#dff7ef);color:#084d73;font-size:1rem;font-weight:900}.contact-identity{min-width:0;flex:1}.contact-identity h2{overflow:hidden;margin:0;color:#153f60;font-size:.88rem;text-overflow:ellipsis;white-space:nowrap}.contact-identity p{overflow:hidden;margin:.15rem 0 0;color:#718698;font-size:.63rem;text-overflow:ellipsis;white-space:nowrap}.contact-type{flex:none;border-radius:999px;background:#e7f4fb;padding:.2rem .48rem;color:#146b98;font-size:.57rem;font-weight:900}.contact-type.type-supplier{background:#fff3d8;color:#966000}.contact-type.type-carrier{background:#f0eaff;color:#6841b8}.contact-meta{display:flex;flex-wrap:wrap;gap:.4rem .9rem;color:#5f7689;font-size:.64rem}.contact-groups{display:flex;min-height:1.6rem;flex-wrap:wrap;gap:.3rem}.contact-groups span{border-radius:999px;background:#edf5f8;padding:.18rem .48rem;color:#49677c;font-size:.58rem;font-weight:800}.contact-groups small{color:#93a2ae;font-size:.6rem}.contact-ticket-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:.35rem}.contact-ticket-stats span{display:grid;gap:.1rem;border-radius:.6rem;background:#f3f6f8;padding:.45rem;text-align:center;color:#718394;font-size:.55rem}.contact-ticket-stats b{color:#173f60;font-size:.82rem}.contact-ticket-stats .needs-action{background:#fff5df;color:#916000}.contact-ticket-stats .needs-action b{color:#c37700}.contact-card footer{display:flex;align-items:center;justify-content:space-between;border-top:1px solid #edf2f5;padding-top:.7rem}.contact-card footer a{color:#557187;font-size:.64rem;font-weight:900}.contact-card footer .primary-action{border-radius:.6rem;background:#e8f6ff;padding:.4rem .65rem;color:#0875b5}.contact-empty{grid-column:1/-1}.contact-empty>span{display:grid;width:3rem;height:3rem;margin:0 auto .5rem;place-items:center;border-radius:1rem;background:#eaf5fb;color:#1679aa;font-size:1.3rem} .operations-split,.template-layout,.dispatch-layout{display:grid;grid-template-columns:minmax(0,1fr) 20rem;align-items:start;gap:1rem}.panel-heading{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.1rem;border-bottom:1px solid #e5edf3;background:#f8fbfd}.panel-heading small{color:#74889a;font-size:.6rem}.panel-heading h2{margin:.15rem 0 0;color:#173f60;font-size:.95rem}.panel-heading>span{border-radius:999px;background:#e7f4fb;padding:.3rem .6rem;color:#126c9d;font-size:.6rem;font-weight:900}.group-card-list,.template-card-list{display:grid;gap:.55rem;padding:.8rem}.group-card,.template-card{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:.75rem;border:1px solid #e0e9ef;border-radius:.8rem;padding:.75rem;transition:.15s}.group-card:hover,.template-card:hover{border-color:#acd2e5;background:#fafdff}.group-symbol,.template-icon{display:grid;width:2.35rem;height:2.35rem;place-items:center;border-radius:.7rem;background:#e8f5fb;color:#0870a6;font-weight:900}.group-card h3,.template-card h3{margin:0;color:#173f60;font-size:.78rem}.group-card p,.template-card p{margin:.12rem 0;color:#667d90;font-size:.62rem}.group-card small,.template-card small{color:#8a9aa7;font-size:.56rem}.group-card>a,.template-card>a{color:#0875b5;font-size:.62rem;font-weight:900}.operations-form-side{overflow:hidden;border:1px solid #d8e4ec;border-radius:1rem;background:#fff;box-shadow:0 18px 40px -36px #08376b;position:sticky;top:5.6rem}.operations-form-side>header{display:flex;align-items:center;gap:.65rem;padding:1rem;background:linear-gradient(135deg,#0a4d78,#087b91);color:#fff}.operations-form-side>header>span{display:grid;width:2rem;height:2rem;place-items:center;border-radius:.6rem;background:rgba(255,255,255,.16);font-weight:900}.operations-form-side header small{font-size:.56rem;color:rgba(255,255,255,.65)}.operations-form-side header h2{margin:.12rem 0 0;font-size:.85rem}.operations-form{display:grid;gap:.75rem;padding:1rem}.operations-form label{display:grid;gap:.35rem}.operations-form label>span{color:#405e75;font-size:.65rem;font-weight:900}.operations-form input,.operations-form select,.operations-form textarea{width:100%;min-height:2.65rem;border:1px solid #c8d8e4;border-radius:.7rem;background:#fbfdff;padding:.6rem .7rem;color:#143e60}.operations-form textarea{min-height:6rem;resize:vertical}.operations-form button{min-height:2.75rem;border:0;border-radius:.7rem;background:linear-gradient(135deg,#0879b7,#075b8d);color:#fff;font-size:.7rem;font-weight:900}.operations-form>a{text-align:center;color:#6e8293;font-size:.62rem;font-weight:800}.operations-form .errorlist,.editor-section .errorlist,.dispatch-composer .errorlist{margin:0;padding:0;color:#b42318;font-size:.6rem;list-style:none} .contact-editor,.dispatch-composer{display:grid;gap:.85rem}.contact-editor{max-width:58rem;width:100%;margin-inline:auto}.editor-section,.dispatch-composer>section{overflow:hidden;border:1px solid #dbe6ee;border-radius:1rem;background:#fff;box-shadow:0 15px 38px -35px #08376b}.editor-section>header,.dispatch-composer>section>header{display:flex;align-items:center;gap:.7rem;border-bottom:1px solid #e8eef3;padding:.85rem 1rem;background:#f9fcfe}.editor-section>header>span,.dispatch-composer>section>header>span{display:grid;width:2rem;height:2rem;flex:none;place-items:center;border-radius:.65rem;background:linear-gradient(135deg,#0a699f,#098d9c);color:#fff;font-size:.7rem;font-weight:900}.editor-section h2,.dispatch-composer h2{margin:0;color:#173f60;font-size:.82rem}.editor-section header p,.dispatch-composer header p{margin:.15rem 0 0;color:#73889a;font-size:.6rem}.editor-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem;padding:1rem}.editor-grid label,.group-selector,.message-editor{display:grid;align-content:start;gap:.35rem;color:#3f5f77;font-size:.65rem;font-weight:900}.editor-grid input,.editor-grid select,.group-selector select,.message-editor textarea{width:100%;min-height:2.75rem;border:1px solid #c8d8e4;border-radius:.72rem;background:#fbfdff;padding:.62rem .72rem;color:#123f61}.editor-grid input:focus,.editor-grid select:focus,.group-selector select:focus,.message-editor textarea:focus{border-color:#1689bd;outline:3px solid rgba(22,137,189,.11);background:#fff}.editor-grid small,.group-selector small{color:#7a8e9e;font-size:.56rem;font-weight:500}.editor-grid em,.group-selector em{color:#d05c3b;font-style:normal}.editor-wide{grid-column:1/-1}.group-selector,.message-editor{margin:1rem}.group-selector select{min-height:9rem}.location-status{margin:-.35rem 1rem .85rem;border-radius:.6rem;background:#edf7fc;padding:.55rem .7rem;color:#39708e;font-size:.58rem}.location-status.is-error{background:#fff0ed;color:#b04432}.editor-actions{display:flex;align-items:center;gap:.7rem;border:1px solid #d9e5ed;border-radius:1rem;background:#fff;padding:.8rem}.editor-actions button{min-height:2.75rem;border:0;border-radius:.7rem;background:linear-gradient(135deg,#0879b7,#075b8d);padding:.65rem 1.4rem;color:#fff;font-weight:900}.editor-actions a{color:#657d90;font-size:.65rem;font-weight:900}.editor-actions span{margin-right:auto;color:#8798a5;font-size:.58rem} +.group-selector{border:0}.group-selector legend{color:#3f5f77;font-size:.7rem;font-weight:900}.group-selector-tools{display:grid;grid-template-columns:minmax(12rem,1fr) auto auto;align-items:center;gap:.55rem;margin:.4rem 0 .65rem}.group-selector-tools label{display:block}.group-selector-tools input{width:100%;min-height:2.65rem;border:1px solid #c8d8e4;border-radius:.72rem;background:#fbfdff;padding:.58rem .75rem}.group-selection-count{border-radius:999px;background:#e7f4fb;padding:.42rem .7rem;color:#126c9d;white-space:nowrap}.group-selector-tools button{min-height:2.55rem;border:1px solid #d8e4ec;border-radius:.65rem;background:#fff;padding:.45rem .7rem;color:#64798c;font-size:.6rem;font-weight:900}.group-selector-tools button:disabled{cursor:not-allowed;opacity:.45}.group-choice-list>div{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.55rem}.group-choice-list>div>div{border:1px solid #dbe5ec;border-radius:.75rem;background:#fbfdff;transition:.15s}.group-choice-list label{display:flex;align-items:center;gap:.65rem;min-height:3.15rem;padding:.65rem .75rem;cursor:pointer;color:#35566e;font-size:.65rem}.group-choice-list input{width:1.1rem;height:1.1rem;flex:none;accent-color:#0879a7}.group-choice-list>div>div.is-selected{border-color:#58aeca;background:#eaf8fb;box-shadow:0 0 0 2px rgba(22,137,189,.08)}.group-choice-list>div>div[hidden]{display:none}.group-empty{margin:.5rem 0;border-radius:.65rem;background:#f5f8fa;padding:.75rem;color:#758999;font-size:.62rem}.staff-attachment-picker{display:grid;gap:.8rem}.attachment-picker-copy{display:flex;align-items:center;gap:.7rem}.staff-attachment-picker .media-picker-actions{margin:0}.staff-attachment-picker .file-preview:empty{display:none} .dispatch-composer>footer{display:flex;align-items:center;justify-content:space-between;gap:1rem;border:1px solid #d7e4ec;border-radius:1rem;background:#fff;padding:.9rem 1rem}.dispatch-composer footer b,.dispatch-composer footer small{display:block}.dispatch-composer footer b{color:#173f60;font-size:.68rem}.dispatch-composer footer small{margin-top:.18rem;color:#73889a;font-size:.56rem}.dispatch-composer footer button{min-height:2.8rem;border:0;border-radius:.72rem;background:linear-gradient(135deg,#0879b7,#087c86);padding:.65rem 1rem;color:#fff;font-size:.68rem;font-weight:900}.message-editor textarea{min-height:11rem;resize:vertical;line-height:1.9}.dispatch-history{overflow:hidden;border:1px solid #d8e4ec;border-radius:1rem;background:#fff;position:sticky;top:5.6rem}.dispatch-history>header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #e5edf3;padding:1rem}.dispatch-history header small{color:#7b8d9d;font-size:.56rem}.dispatch-history header h2{margin:.12rem 0 0;color:#173f60;font-size:.88rem}.dispatch-history header>span{display:grid;width:2rem;height:2rem;place-items:center;border-radius:.65rem;background:#e8f4fb;color:#0873a9;font-size:.65rem;font-weight:900}.dispatch-history>div{display:grid;max-height:39rem;overflow:auto}.dispatch-history-card{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.55rem;border-bottom:1px solid #edf2f5;padding:.75rem;color:inherit}.dispatch-history-card:hover{background:#f7fbfd}.dispatch-state{width:.5rem;height:.5rem;border-radius:50%;background:#8da0ae}.dispatch-state.state-sent{background:#12a36d}.dispatch-state.state-queued{background:#e19b18}.dispatch-state.state-partial{background:#dc5c42}.dispatch-history-card b{display:block;overflow:hidden;color:#24485f;font-size:.68rem;text-overflow:ellipsis;white-space:nowrap}.dispatch-history-card small{display:block;margin-top:.15rem;color:#718698;font-size:.56rem}.dispatch-history-card p{display:flex;gap:.6rem;margin:.35rem 0 0;color:#8798a5;font-size:.52rem}.dispatch-history-card em{color:#8aa0b0;font-style:normal} .template-card-list{max-height:44rem;overflow:auto}.variable-box{border:1px dashed #b9cedb;border-radius:.7rem;background:#f7fbfd;padding:.7rem}.variable-box>b{display:block;margin-bottom:.45rem;color:#3e6077;font-size:.62rem}.variable-box>div{display:flex;flex-wrap:wrap;gap:.3rem}.variable-box code{border-radius:.35rem;background:#e7f3f9;padding:.18rem .35rem;color:#075e8d;font-size:.53rem} @media(max-width:1100px){.operations-kpis{grid-template-columns:repeat(3,1fr)}.contact-filter-bar{grid-template-columns:repeat(2,minmax(0,1fr))}.contact-search{grid-column:1/-1}.operations-split,.template-layout,.dispatch-layout{grid-template-columns:1fr}.operations-form-side,.dispatch-history{position:static}.dispatch-history>div,.template-card-list{max-height:none}} -@media(max-width:700px){.operations-hero{align-items:stretch;flex-direction:column;padding:1.1rem}.operations-hero h1{font-size:1.3rem}.operations-hero-actions{align-items:stretch;flex-direction:column}.security-callout,.template-guide{align-self:stretch}.operations-kpis,.operations-kpis.compact{display:flex;max-width:none;overflow-x:auto;padding-bottom:.25rem}.operations-kpis article{min-width:9rem}.contact-filter-bar{grid-template-columns:1fr}.contact-search{grid-column:auto}.contact-card-grid{grid-template-columns:1fr;padding:.65rem}.contact-result-meta{align-items:flex-start;flex-direction:column;gap:.4rem}.editor-grid{grid-template-columns:1fr;padding:.8rem}.editor-wide{grid-column:auto}.editor-actions,.dispatch-composer>footer{align-items:stretch;flex-direction:column}.editor-actions span{margin:0}.group-card,.template-card{grid-template-columns:auto minmax(0,1fr) auto}.group-card .status-pill,.template-card .status-pill{grid-column:2}.group-card>a,.template-card>a{grid-column:3;grid-row:1/3}.contact-ticket-stats{grid-template-columns:repeat(2,1fr)}} +@media(max-width:700px){.operations-hero{align-items:stretch;flex-direction:column;padding:1.1rem}.operations-hero h1{font-size:1.3rem}.operations-hero-actions{align-items:stretch;flex-direction:column}.security-callout,.template-guide{align-self:stretch}.operations-kpis,.operations-kpis.compact{display:flex;max-width:none;overflow-x:auto;padding-bottom:.25rem}.operations-kpis article{min-width:9rem}.contact-filter-bar{grid-template-columns:1fr}.contact-search{grid-column:auto}.contact-card-grid{grid-template-columns:1fr;padding:.65rem}.contact-result-meta{align-items:flex-start;flex-direction:column;gap:.4rem}.editor-grid{grid-template-columns:1fr;padding:.8rem}.editor-wide{grid-column:auto}.editor-actions,.dispatch-composer>footer{align-items:stretch;flex-direction:column}.editor-actions span{margin:0}.group-selector-tools{grid-template-columns:1fr}.group-selection-count{justify-self:start}.group-choice-list>div{grid-template-columns:1fr}.group-card,.template-card{grid-template-columns:auto minmax(0,1fr) auto}.group-card .status-pill,.template-card .status-pill{grid-column:2}.group-card>a,.template-card>a{grid-column:3;grid-row:1/3}.contact-ticket-stats{grid-template-columns:repeat(2,1fr)}} diff --git a/static/js/contact-group-selector.js b/static/js/contact-group-selector.js new file mode 100644 index 0000000..7091de0 --- /dev/null +++ b/static/js/contact-group-selector.js @@ -0,0 +1,35 @@ +document.querySelectorAll('[data-contact-group-selector]').forEach(selector => { + const search = selector.querySelector('[data-group-search]'); + const count = selector.querySelector('[data-group-selection-count]'); + const clear = selector.querySelector('[data-clear-groups]'); + const empty = selector.querySelector('[data-group-empty]'); + const choices = Array.from(selector.querySelectorAll('.group-choice-list > div > div')); + + const update = () => { + let selected = 0; + let visible = 0; + const query = (search?.value || '').trim().toLocaleLowerCase('fa'); + choices.forEach(choice => { + const input = choice.querySelector('input[type="checkbox"]'); + const matches = !query || choice.textContent.toLocaleLowerCase('fa').includes(query); + choice.hidden = !matches; + choice.classList.toggle('is-selected', Boolean(input?.checked)); + selected += input?.checked ? 1 : 0; + visible += matches ? 1 : 0; + }); + if (count) count.textContent = `${selected.toLocaleString('fa-IR')} گروه انتخاب شده`; + if (clear) clear.disabled = selected === 0; + if (empty) empty.hidden = visible !== 0; + }; + + selector.addEventListener('change', update); + search?.addEventListener('input', update); + clear?.addEventListener('click', () => { + choices.forEach(choice => { + const input = choice.querySelector('input[type="checkbox"]'); + if (input) input.checked = false; + }); + update(); + }); + update(); +}); diff --git a/templates/tickets/staff_create.html b/templates/tickets/staff_create.html index 888b675..9ecd755 100644 --- a/templates/tickets/staff_create.html +++ b/templates/tickets/staff_create.html @@ -1,11 +1,13 @@ {% extends 'base.html' %}{% load static %} {% block title %}{{ page_title }}{% endblock %} {% block content %} + +
ایجاد پرونده از طرف واحد فروش
ابتدا مشتری را شناسایی کنید، سپس موضوع و پیام کامل را ثبت کنید. مشتری یک لینک امن برای مشاهده دریافت میکند.
ایجاد پرونده از طرف {{ staff_unit.name|default:'واحد سازمانی' }}
ابتدا مشتری را شناسایی کنید، سپس موضوع و پیام کامل را ثبت کنید. مشتری یک لینک امن برای مشاهده دریافت میکند.
اطلاعات پایه مخاطب برای شناسایی و ارسال پیامک
استان و شهر را از پایگاه مکانهای ایران انتخاب کنید
برای نمایش شهرها، ابتدا استان را انتخاب کنید.
حداقل یک گروه انتخاب کنید؛ عضویت همزمان در چند گروه پشتیبانی میشود
با یک کلیک عضویت مخاطب را در گروههای قابل مدیریت اضافه یا حذف کنید