This commit is contained in:
2026-09-29 22:00:50 +03:30
parent 148f00a75d
commit 4d27da98fc
85 changed files with 865 additions and 522 deletions
@@ -1 +1 @@
import{O as e,Z as t,at as n,g as r,l as i}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a}from"./http-Djf2pGxE.js";import{B as o}from"./index-CznUUXv3.js";import{t as s}from"./BaseSwitch-TV5Yvtf7.js";function c(e=480){return new Promise(t=>{window.setTimeout(t,e)})}function l(e){let n=t(null),r=t(null),i=a();async function o(t,a){if(n.value)return a;let o=!a;if(!o&&e.confirmOff&&!await e.confirmOff())return a;n.value=t,r.value=null;let s=a;try{return await e.onPersist(o),i.success(e.successMessage?.(o)??(o?`وضعیت فعال شد.`:`وضعیت غیرفعال شد.`)),o}catch{return r.value=t,i.error(e.errorMessage??`به‌روزرسانی وضعیت انجام نشد.`),s}finally{n.value=null}}function s(e){return n.value===e}function c(e){return r.value===e}return{toggle:o,isLoading:s,hasError:c}}var u=r({__name:`ActiveSwitchCell`,props:{id:{},modelValue:{type:Boolean},entityName:{},entityType:{},persist:{type:Function}},emits:[`update:modelValue`],setup(t,{emit:r}){let a=t,u=r,{toggle:d,isLoading:f,hasError:p}=l({onPersist:async e=>{a.persist?await a.persist(a.id,e):await c()},successMessage:e=>e?`${a.entityType??`مورد`} «${a.entityName}» فعال شد.`:`${a.entityType??`مورد`} «${a.entityName}» غیرفعال شد.`});async function m(e){if(e===a.modelValue)return;let t=a.entityType??`مورد`;if(!await o({title:e?`فعال‌سازی ${t}`:`غیرفعال‌سازی ${t}`,message:e?`آیا از فعال کردن «${a.entityName}» مطمئن هستید؟`:`آیا از غیرفعال کردن «${a.entityName}» مطمئن هستید؟`,tone:e?`primary`:`danger`,confirmLabel:e?`فعال کردن`:`غیرفعال کردن`,cancelLabel:`انصراف`}))return;let n=await d(a.id,a.modelValue);u(`update:modelValue`,n)}return(r,a)=>(e(),i(s,{"model-value":t.modelValue,loading:n(f)(t.id),error:n(p)(t.id),"onUpdate:modelValue":m},null,8,[`model-value`,`loading`,`error`]))}});export{u as t};
import{$ as e,g as t,k as n,l as r,st as i}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a}from"./http-BjLkjdQu.js";import{B as o}from"./index-pv0Ktkd1.js";import{t as s}from"./BaseSwitch-pJwnFBVo.js";function c(e=480){return new Promise(t=>{window.setTimeout(t,e)})}function l(t){let n=e(null),r=e(null),i=a();async function o(e,a){if(n.value)return a;let o=!a;if(!o&&t.confirmOff&&!await t.confirmOff())return a;n.value=e,r.value=null;let s=a;try{return await t.onPersist(o),i.success(t.successMessage?.(o)??(o?`وضعیت فعال شد.`:`وضعیت غیرفعال شد.`)),o}catch{return r.value=e,i.error(t.errorMessage??`به‌روزرسانی وضعیت انجام نشد.`),s}finally{n.value=null}}function s(e){return n.value===e}function c(e){return r.value===e}return{toggle:o,isLoading:s,hasError:c}}var u=t({__name:`ActiveSwitchCell`,props:{id:{},modelValue:{type:Boolean},entityName:{},entityType:{},persist:{type:Function}},emits:[`update:modelValue`],setup(e,{emit:t}){let a=e,u=t,{toggle:d,isLoading:f,hasError:p}=l({onPersist:async e=>{a.persist?await a.persist(a.id,e):await c()},successMessage:e=>e?`${a.entityType??`مورد`} «${a.entityName}» فعال شد.`:`${a.entityType??`مورد`} «${a.entityName}» غیرفعال شد.`});async function m(e){if(e===a.modelValue)return;let t=a.entityType??`مورد`;if(!await o({title:e?`فعال‌سازی ${t}`:`غیرفعال‌سازی ${t}`,message:e?`آیا از فعال کردن «${a.entityName}» مطمئن هستید؟`:`آیا از غیرفعال کردن «${a.entityName}» مطمئن هستید؟`,tone:e?`primary`:`danger`,confirmLabel:e?`فعال کردن`:`غیرفعال کردن`,cancelLabel:`انصراف`}))return;let n=await d(a.id,a.modelValue);u(`update:modelValue`,n)}return(t,a)=>(n(),r(s,{"model-value":e.modelValue,loading:i(f)(e.id),error:i(p)(e.id),"onUpdate:modelValue":m},null,8,[`model-value`,`loading`,`error`]))}});export{u as t};
-1
View File
@@ -1 +0,0 @@
import{O as e,Tt as t,d as n,g as r,s as i,t as a}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{c as o,r as s}from"./index-CznUUXv3.js";var c=[`id`,`value`,`placeholder`,`disabled`],l=a(r({__name:`AdminCurrencyInput`,props:{modelValue:{default:null},placeholder:{default:``},disabled:{type:Boolean,default:!1},id:{},inputClass:{default:`admin-input`},allowEmpty:{type:Boolean,default:!0}},emits:[`update:modelValue`],setup(r,{emit:a}){let l=r,u=a,d=i(()=>l.modelValue==null||!Number.isFinite(l.modelValue)?``:o(l.modelValue));function f(e){let t=e.target,n=s(t.value);if(!n){u(`update:modelValue`,l.allowEmpty?null:0),t.value=``;return}let r=Number(n);u(`update:modelValue`,r),t.value=o(r)}return(i,a)=>(e(),n(`input`,{id:r.id,type:`text`,inputmode:`numeric`,dir:`ltr`,class:t([`admin-currency-input`,r.inputClass]),value:d.value,placeholder:r.placeholder,disabled:r.disabled,onInput:f},null,42,c))}}),[[`__scopeId`,`data-v-56435fc8`]]);export{l as t};
+1
View File
@@ -0,0 +1 @@
import{Dt as e,d as t,g as n,k as r,s as i,t as a}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{c as o,r as s}from"./index-pv0Ktkd1.js";var c=[`id`,`value`,`placeholder`,`disabled`],l=a(n({__name:`AdminCurrencyInput`,props:{modelValue:{default:null},placeholder:{default:``},disabled:{type:Boolean,default:!1},id:{},inputClass:{default:`admin-input`},allowEmpty:{type:Boolean,default:!0}},emits:[`update:modelValue`],setup(n,{emit:a}){let l=n,u=a,d=i(()=>l.modelValue==null||!Number.isFinite(l.modelValue)?``:o(l.modelValue));function f(e){let t=e.target,n=s(t.value);if(!n){u(`update:modelValue`,l.allowEmpty?null:0),t.value=``;return}let r=Number(n);u(`update:modelValue`,r),t.value=o(r)}return(i,a)=>(r(),t(`input`,{id:n.id,type:`text`,inputmode:`numeric`,dir:`ltr`,class:e([`admin-currency-input`,n.inputClass]),value:d.value,placeholder:n.placeholder,disabled:n.disabled,onInput:f},null,42,c))}}),[[`__scopeId`,`data-v-56435fc8`]]);export{l as t};
+1
View File
@@ -0,0 +1 @@
import{R as e,S as t,a as n,c as r,d as i,g as a,k as o,l as s,t as c,u as l}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{m as u}from"./http-BjLkjdQu.js";var d=[`src`,`alt`],f=c(a({__name:`AdminImageLightbox`,props:t({src:{},alt:{}},{modelValue:{type:Boolean,required:!0},modelModifiers:{}}),emits:[`update:modelValue`],setup(t){let a=e(t,`modelValue`);return(e,c)=>(o(),s(n,{to:`body`},[a.value?(o(),i(`div`,{key:0,class:`admin-image-lightbox`,onClick:c[1]||=u(e=>a.value=!1,[`self`])},[r(`button`,{type:`button`,class:`admin-image-lightbox__close`,onClick:c[0]||=e=>a.value=!1},` بستن `),r(`img`,{src:t.src,alt:t.alt??`پیش‌نمایش تصویر`},null,8,d)])):l(``,!0)]))}}),[[`__scopeId`,`data-v-65676449`]]);export{f as t};
+1
View File
@@ -0,0 +1 @@
.admin-image-lightbox[data-v-65676449]{z-index:300000;background:#000000d6;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.admin-image-lightbox img[data-v-65676449]{object-fit:contain;border-radius:8px;max-width:min(900px,100%);max-height:88vh}.admin-image-lightbox__close[data-v-65676449]{top:14px;cursor:pointer;background:var(--color-surface);color:var(--color-text);font:inherit;border:0;border-radius:8px;padding:8px 12px;font-size:.875rem;font-weight:600;position:absolute;inset-inline-end:14px}
@@ -1 +1 @@
import{Dt as e,O as t,Ot as n,Tt as r,Z as i,at as a,c as o,d as s,g as c,t as l,u}from"./_plugin-vue_export-helper-OaxA6A2f.js";var d=960,f=.82;function p(e){let t=e.trim();return t?`url("${t.replace(/"/g,`\\"`)}")`:``}async function m(e){if(!e.type.startsWith(`image/`))throw Error(`فقط فایل تصویری مجاز است.`);if(e.size>8388608)throw Error(`حجم تصویر نباید بیشتر از ۸ مگابایت باشد.`);return g(await h(e))}function h(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>t(String(r.result??``)),r.onerror=()=>n(Error(`خواندن تصویر ناموفق بود.`)),r.readAsDataURL(e)})}function g(e){return new Promise((t,n)=>{let r=new Image;r.onload=()=>{let e=Math.min(1,d/Math.max(r.width,r.height)),i=Math.max(1,Math.round(r.width*e)),a=Math.max(1,Math.round(r.height*e)),o=document.createElement(`canvas`);o.width=i,o.height=a;let s=o.getContext(`2d`);if(!s){n(Error(`پردازش تصویر ناموفق بود.`));return}s.drawImage(r,0,0,i,a),t(o.toDataURL(`image/jpeg`,f))},r.onerror=()=>n(Error(`تصویر نامعتبر است.`)),r.src=e})}var _={class:`image-picker`},v={key:0,class:`image-picker__label`},y={class:`image-picker__row`},b={class:`image-picker__actions`},x=[`disabled`],S=[`disabled`],C={key:1,class:`image-picker__error`},w={key:2,class:`image-picker__ok`},T=l(c({__name:`AdminImagePicker`,props:{modelValue:{},label:{}},emits:[`update:modelValue`],setup(c,{emit:l}){let d=c,f=l,h=i(null),g=i(!1),T=i(``),E=i(!1);function D(){h.value?.click()}async function O(e){let t=e.target,n=t.files?.[0];if(t.value=``,n){g.value=!0,T.value=``,E.value=!1;try{f(`update:modelValue`,await m(n)),E.value=!0}catch(e){T.value=e instanceof Error?e.message:`بارگذاری تصویر ناموفق بود.`}finally{g.value=!1}}}function k(){f(`update:modelValue`,null)}return(i,l)=>(t(),s(`div`,_,[c.label?(t(),s(`p`,v,n(c.label),1)):u(``,!0),o(`div`,y,[o(`div`,{class:r([`image-picker__preview`,{"image-picker__preview--empty":!d.modelValue}]),style:e(d.modelValue?{backgroundImage:a(p)(d.modelValue)}:void 0)},null,6),o(`div`,b,[o(`button`,{type:`button`,class:`admin-btn admin-btn--outline admin-btn--sm`,disabled:g.value,onClick:D},n(d.modelValue?`تغییر تصویر`:`افزودن تصویر`),9,x),d.modelValue?(t(),s(`button`,{key:0,type:`button`,class:`admin-btn admin-btn--outline admin-btn--sm`,disabled:g.value,onClick:k},` حذف `,8,S)):u(``,!0),T.value?(t(),s(`p`,C,n(T.value),1)):E.value?(t(),s(`p`,w,`تصویر انتخاب شد — برای ثبت نهایی «ذخیره» را بزنید.`)):u(``,!0)])]),o(`input`,{ref_key:`inputRef`,ref:h,type:`file`,accept:`image/*`,class:`image-picker__file`,onChange:O},null,544)]))}}),[[`__scopeId`,`data-v-05db5be7`]]);export{m as n,p as r,T as t};
import{$ as e,At as t,Dt as n,c as r,d as i,g as a,k as o,kt as s,st as c,t as l,u}from"./_plugin-vue_export-helper-QrIvvHC8.js";var d=960,f=.82;function p(e){let t=e.trim();return t?`url("${t.replace(/"/g,`\\"`)}")`:``}async function m(e){if(!e.type.startsWith(`image/`))throw Error(`فقط فایل تصویری مجاز است.`);if(e.size>8388608)throw Error(`حجم تصویر نباید بیشتر از ۸ مگابایت باشد.`);return g(await h(e))}function h(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>t(String(r.result??``)),r.onerror=()=>n(Error(`خواندن تصویر ناموفق بود.`)),r.readAsDataURL(e)})}function g(e){return new Promise((t,n)=>{let r=new Image;r.onload=()=>{let e=Math.min(1,d/Math.max(r.width,r.height)),i=Math.max(1,Math.round(r.width*e)),a=Math.max(1,Math.round(r.height*e)),o=document.createElement(`canvas`);o.width=i,o.height=a;let s=o.getContext(`2d`);if(!s){n(Error(`پردازش تصویر ناموفق بود.`));return}s.drawImage(r,0,0,i,a),t(o.toDataURL(`image/jpeg`,f))},r.onerror=()=>n(Error(`تصویر نامعتبر است.`)),r.src=e})}var _={class:`image-picker`},v={key:0,class:`image-picker__label`},y={class:`image-picker__row`},b={class:`image-picker__actions`},x=[`disabled`],S=[`disabled`],C={key:1,class:`image-picker__error`},w={key:2,class:`image-picker__ok`},T=l(a({__name:`AdminImagePicker`,props:{modelValue:{},label:{}},emits:[`update:modelValue`],setup(a,{emit:l}){let d=a,f=l,h=e(null),g=e(!1),T=e(``),E=e(!1);function D(){h.value?.click()}async function O(e){let t=e.target,n=t.files?.[0];if(t.value=``,n){g.value=!0,T.value=``,E.value=!1;try{f(`update:modelValue`,await m(n)),E.value=!0}catch(e){T.value=e instanceof Error?e.message:`بارگذاری تصویر ناموفق بود.`}finally{g.value=!1}}}function k(){f(`update:modelValue`,null)}return(e,l)=>(o(),i(`div`,_,[a.label?(o(),i(`p`,v,t(a.label),1)):u(``,!0),r(`div`,y,[r(`div`,{class:n([`image-picker__preview`,{"image-picker__preview--empty":!d.modelValue}]),style:s(d.modelValue?{backgroundImage:c(p)(d.modelValue)}:void 0)},null,6),r(`div`,b,[r(`button`,{type:`button`,class:`admin-btn admin-btn--outline admin-btn--sm`,disabled:g.value,onClick:D},t(d.modelValue?`تغییر تصویر`:`افزودن تصویر`),9,x),d.modelValue?(o(),i(`button`,{key:0,type:`button`,class:`admin-btn admin-btn--outline admin-btn--sm`,disabled:g.value,onClick:k},` حذف `,8,S)):u(``,!0),T.value?(o(),i(`p`,C,t(T.value),1)):E.value?(o(),i(`p`,w,`تصویر انتخاب شد — برای ثبت نهایی «ذخیره» را بزنید.`)):u(``,!0)])]),r(`input`,{ref_key:`inputRef`,ref:h,type:`file`,accept:`image/*`,class:`image-picker__file`,onChange:O},null,544)]))}}),[[`__scopeId`,`data-v-05db5be7`]]);export{m as n,p as r,T as t};
@@ -1 +1 @@
import{O as e,c as t,d as n,g as r,j as i,p as a,r as o,t as s}from"./_plugin-vue_export-helper-OaxA6A2f.js";var c={class:`admin-page-skeleton`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,"aria-label":`در حال بارگذاری`},l={class:`admin-card admin-page-skeleton__table`},u={key:1,class:`admin-card admin-page-skeleton__form`},d={key:2,class:`admin-card admin-page-skeleton__detail`},f={key:3,class:`admin-page-skeleton__cards`},p=s(r({__name:`AdminPageSkeleton`,props:{variant:{default:`cards`},rows:{default:5}},setup(r){return(s,p)=>(e(),n(`div`,c,[r.variant===`table`?(e(),n(o,{key:0},[p[1]||=t(`div`,{class:`admin-page-skeleton__toolbar`},[t(`span`,{class:`admin-skeleton admin-page-skeleton__search`}),t(`span`,{class:`admin-skeleton admin-page-skeleton__btn`})],-1),t(`div`,l,[(e(!0),n(o,null,i(r.rows,t=>(e(),n(`div`,{key:t,class:`admin-page-skeleton__tr`},[...p[0]||=[a(`<span class="admin-skeleton" style="width:18%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:22%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:14%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:16%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:12%;height:12px;" data-v-8283cd1d></span>`,5)]]))),128))])],64)):r.variant===`form`?(e(),n(`div`,u,[(e(!0),n(o,null,i(r.rows,r=>(e(),n(`div`,{key:r,class:`admin-page-skeleton__field`},[...p[2]||=[t(`span`,{class:`admin-skeleton`,style:{width:`28%`,height:`10px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`100%`,height:`40px`,"border-radius":`10px`}},null,-1)]]))),128))])):r.variant===`detail`?(e(),n(`div`,d,[...p[3]||=[a(`<span class="admin-skeleton" style="width:40%;height:18px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:70%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:100%;height:120px;border-radius:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:100%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:88%;height:12px;" data-v-8283cd1d></span>`,5)]])):(e(),n(`div`,f,[(e(!0),n(o,null,i(r.rows,r=>(e(),n(`div`,{key:r,class:`admin-card admin-page-skeleton__card`},[...p[4]||=[t(`span`,{class:`admin-skeleton`,style:{width:`45%`,height:`14px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`70%`,height:`11px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`35%`,height:`11px`}},null,-1)]]))),128))]))]))}}),[[`__scopeId`,`data-v-8283cd1d`]]);export{p as t};
import{M as e,c as t,d as n,g as r,k as i,p as a,r as o,t as s}from"./_plugin-vue_export-helper-QrIvvHC8.js";var c={class:`admin-page-skeleton`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,"aria-label":`در حال بارگذاری`},l={class:`admin-card admin-page-skeleton__table`},u={key:1,class:`admin-card admin-page-skeleton__form`},d={key:2,class:`admin-card admin-page-skeleton__detail`},f={key:3,class:`admin-page-skeleton__cards`},p=s(r({__name:`AdminPageSkeleton`,props:{variant:{default:`cards`},rows:{default:5}},setup(r){return(s,p)=>(i(),n(`div`,c,[r.variant===`table`?(i(),n(o,{key:0},[p[1]||=t(`div`,{class:`admin-page-skeleton__toolbar`},[t(`span`,{class:`admin-skeleton admin-page-skeleton__search`}),t(`span`,{class:`admin-skeleton admin-page-skeleton__btn`})],-1),t(`div`,l,[(i(!0),n(o,null,e(r.rows,e=>(i(),n(`div`,{key:e,class:`admin-page-skeleton__tr`},[...p[0]||=[a(`<span class="admin-skeleton" style="width:18%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:22%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:14%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:16%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:12%;height:12px;" data-v-8283cd1d></span>`,5)]]))),128))])],64)):r.variant===`form`?(i(),n(`div`,u,[(i(!0),n(o,null,e(r.rows,e=>(i(),n(`div`,{key:e,class:`admin-page-skeleton__field`},[...p[2]||=[t(`span`,{class:`admin-skeleton`,style:{width:`28%`,height:`10px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`100%`,height:`40px`,"border-radius":`10px`}},null,-1)]]))),128))])):r.variant===`detail`?(i(),n(`div`,d,[...p[3]||=[a(`<span class="admin-skeleton" style="width:40%;height:18px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:70%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:100%;height:120px;border-radius:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:100%;height:12px;" data-v-8283cd1d></span><span class="admin-skeleton" style="width:88%;height:12px;" data-v-8283cd1d></span>`,5)]])):(i(),n(`div`,f,[(i(!0),n(o,null,e(r.rows,e=>(i(),n(`div`,{key:e,class:`admin-card admin-page-skeleton__card`},[...p[4]||=[t(`span`,{class:`admin-skeleton`,style:{width:`45%`,height:`14px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`70%`,height:`11px`}},null,-1),t(`span`,{class:`admin-skeleton`,style:{width:`35%`,height:`11px`}},null,-1)]]))),128))]))]))}}),[[`__scopeId`,`data-v-8283cd1d`]]);export{p as t};
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,B as n,D as r,Dt as i,M as a,N as o,U as s,a as c,c as l,d as u,g as d,h as f,k as p,kt as m,l as h,r as g,s as _,t as v,u as y,w as b}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{f as x,m as S,p as C}from"./http-BjLkjdQu.js";import{L as w,M as T}from"./index-pv0Ktkd1.js";var E=[`id`],D=[`aria-label`,`aria-expanded`],O={class:`admin-select__trigger-content`},k={class:`admin-select__value`},A={class:`admin-select__chevron`,"aria-hidden":`true`},j=[`aria-label`],M={key:0,class:`admin-select__search`,role:`presentation`},N=[`placeholder`],P={key:1,class:`admin-select__empty`,role:`presentation`},F=[`aria-selected`,`onClick`],I={class:`admin-select__option-label`},L=v(d({__name:`AdminSelect`,props:{modelValue:{},options:{},placeholder:{default:`انتخاب کنید`},ariaLabel:{default:`انتخاب`},block:{type:Boolean,default:!1},searchable:{type:Boolean,default:!1},searchPlaceholder:{default:`جستجو…`},id:{default:void 0}},emits:[`update:modelValue`],setup(d,{emit:v}){let L=d,R=v,z=e(!1),B=e(``),V=e(null),H=e(null),U=e(null),W=e({});T(V,()=>{z.value=!1,B.value=``},{ignore:[H]});let G=_(()=>L.options.find(e=>e.value===L.modelValue)),K=_(()=>G.value?.label??L.placeholder),q=_(()=>{let e=B.value.trim().toLowerCase();return e?L.options.filter(t=>t.label.toLowerCase().includes(e)):L.options});function J(){let e=V.value;if(!e)return;let t=e.getBoundingClientRect(),n=Math.min(320,window.innerHeight*.5),r=window.innerHeight-t.bottom-6,i=t.top-6,a=r<Math.min(160,n)&&i>r,o=Math.max(120,Math.min(n,a?i:r));W.value={position:`fixed`,left:`${Math.max(8,Math.min(t.left,window.innerWidth-Math.max(t.width,220)-8))}px`,width:`${Math.max(t.width,220)}px`,zIndex:`1100`,maxHeight:`${o}px`,...a?{top:`auto`,bottom:`${window.innerHeight-t.top+6}px`}:{top:`${t.bottom+6}px`,bottom:`auto`}}}function Y(e){e?(window.addEventListener(`resize`,J),window.addEventListener(`scroll`,J,!0)):(window.removeEventListener(`resize`,J),window.removeEventListener(`scroll`,J,!0))}async function X(){z.value=!z.value,z.value&&(await b(),J(),L.searchable&&(B.value=``,await b(),U.value?.focus()))}function Z(e){R(`update:modelValue`,e),z.value=!1,B.value=``}return n(z,e=>{Y(e),e&&b(()=>J())}),r(()=>{Y(!1)}),(e,n)=>(p(),u(`div`,{id:d.id,ref_key:`rootRef`,ref:V,class:i([`admin-select`,{"admin-select--open":z.value,"admin-select--block":d.block}])},[l(`button`,{type:`button`,class:`admin-select__trigger`,"aria-label":d.ariaLabel,"aria-expanded":z.value,"aria-haspopup":`listbox`,onClick:X},[l(`span`,O,[o(e.$slots,`option-leading`,{option:G.value},void 0,!0),l(`span`,k,t(K.value),1)]),l(`span`,A,[f(w,{name:`chevron-down`,size:16})])],8,D),(p(),h(c,{to:`body`},[z.value?(p(),u(`ul`,{key:0,ref_key:`menuRef`,ref:H,class:`admin-select__menu`,role:`listbox`,"aria-label":d.ariaLabel,style:m(W.value)},[d.searchable?(p(),u(`li`,M,[s(l(`input`,{ref_key:`searchInputRef`,ref:U,"onUpdate:modelValue":n[0]||=e=>B.value=e,type:`search`,class:`admin-select__search-input`,placeholder:d.searchPlaceholder,onClick:n[1]||=S(()=>{},[`stop`]),onKeydown:n[2]||=C(S(e=>z.value=!1,[`stop`]),[`esc`])},null,40,N),[[x,B.value]])])):y(``,!0),q.value.length?y(``,!0):(p(),u(`li`,P,` موردی یافت نشد `)),(p(!0),u(g,null,a(q.value,n=>(p(),u(`li`,{key:n.value,role:`presentation`},[l(`button`,{type:`button`,class:i([`admin-select__option`,{"admin-select__option--active":n.value===d.modelValue}]),role:`option`,"aria-selected":n.value===d.modelValue,onClick:e=>Z(n.value)},[l(`span`,I,[o(e.$slots,`option-leading`,{option:n},void 0,!0),l(`span`,null,t(n.label),1)]),n.value===d.modelValue?(p(),h(w,{key:0,name:`check`,size:16,class:`admin-select__check`})):y(``,!0)],10,F)]))),128))],12,j)):y(``,!0)]))],10,E))}}),[[`__scopeId`,`data-v-4623e322`]]);export{L as t};
-1
View File
@@ -1 +0,0 @@
import{C as e,Dt as t,E as n,M as r,O as i,Ot as a,R as o,Tt as s,V as c,Z as l,a as u,c as d,d as f,g as p,h as m,j as h,l as g,r as _,s as v,t as y,u as b}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{f as x,m as S,p as C}from"./http-Djf2pGxE.js";import{L as w,M as T}from"./index-CznUUXv3.js";var E=[`id`],D=[`aria-label`,`aria-expanded`],O={class:`admin-select__trigger-content`},k={class:`admin-select__value`},A={class:`admin-select__chevron`,"aria-hidden":`true`},j=[`aria-label`],M={key:0,class:`admin-select__search`,role:`presentation`},N=[`placeholder`],P={key:1,class:`admin-select__empty`,role:`presentation`},F=[`aria-selected`,`onClick`],I={class:`admin-select__option-label`},L=y(p({__name:`AdminSelect`,props:{modelValue:{},options:{},placeholder:{default:`انتخاب کنید`},ariaLabel:{default:`انتخاب`},block:{type:Boolean,default:!1},searchable:{type:Boolean,default:!1},searchPlaceholder:{default:`جستجو…`},id:{default:void 0}},emits:[`update:modelValue`],setup(p,{emit:y}){let L=p,R=y,z=l(!1),B=l(``),V=l(null),H=l(null),U=l(null),W=l({});T(V,()=>{z.value=!1,B.value=``},{ignore:[H]});let G=v(()=>L.options.find(e=>e.value===L.modelValue)),K=v(()=>G.value?.label??L.placeholder),q=v(()=>{let e=B.value.trim().toLowerCase();return e?L.options.filter(t=>t.label.toLowerCase().includes(e)):L.options});function J(){let e=V.value;if(!e)return;let t=e.getBoundingClientRect(),n=Math.min(320,window.innerHeight*.5),r=window.innerHeight-t.bottom-6,i=t.top-6,a=r<Math.min(160,n)&&i>r,o=Math.max(120,Math.min(n,a?i:r));W.value={position:`fixed`,left:`${Math.max(8,Math.min(t.left,window.innerWidth-Math.max(t.width,220)-8))}px`,width:`${Math.max(t.width,220)}px`,zIndex:`1100`,maxHeight:`${o}px`,...a?{top:`auto`,bottom:`${window.innerHeight-t.top+6}px`}:{top:`${t.bottom+6}px`,bottom:`auto`}}}function Y(e){e?(window.addEventListener(`resize`,J),window.addEventListener(`scroll`,J,!0)):(window.removeEventListener(`resize`,J),window.removeEventListener(`scroll`,J,!0))}async function X(){z.value=!z.value,z.value&&(await e(),J(),L.searchable&&(B.value=``,await e(),U.value?.focus()))}function Z(e){R(`update:modelValue`,e),z.value=!1,B.value=``}return o(z,t=>{Y(t),t&&e(()=>J())}),n(()=>{Y(!1)}),(e,n)=>(i(),f(`div`,{id:p.id,ref_key:`rootRef`,ref:V,class:s([`admin-select`,{"admin-select--open":z.value,"admin-select--block":p.block}])},[d(`button`,{type:`button`,class:`admin-select__trigger`,"aria-label":p.ariaLabel,"aria-expanded":z.value,"aria-haspopup":`listbox`,onClick:X},[d(`span`,O,[r(e.$slots,`option-leading`,{option:G.value},void 0,!0),d(`span`,k,a(K.value),1)]),d(`span`,A,[m(w,{name:`chevron-down`,size:16})])],8,D),(i(),g(u,{to:`body`},[z.value?(i(),f(`ul`,{key:0,ref_key:`menuRef`,ref:H,class:`admin-select__menu`,role:`listbox`,"aria-label":p.ariaLabel,style:t(W.value)},[p.searchable?(i(),f(`li`,M,[c(d(`input`,{ref_key:`searchInputRef`,ref:U,"onUpdate:modelValue":n[0]||=e=>B.value=e,type:`search`,class:`admin-select__search-input`,placeholder:p.searchPlaceholder,onClick:n[1]||=S(()=>{},[`stop`]),onKeydown:n[2]||=C(S(e=>z.value=!1,[`stop`]),[`esc`])},null,40,N),[[x,B.value]])])):b(``,!0),q.value.length?b(``,!0):(i(),f(`li`,P,` موردی یافت نشد `)),(i(!0),f(_,null,h(q.value,t=>(i(),f(`li`,{key:t.value,role:`presentation`},[d(`button`,{type:`button`,class:s([`admin-select__option`,{"admin-select__option--active":t.value===p.modelValue}]),role:`option`,"aria-selected":t.value===p.modelValue,onClick:e=>Z(t.value)},[d(`span`,I,[r(e.$slots,`option-leading`,{option:t},void 0,!0),d(`span`,null,a(t.label),1)]),t.value===p.modelValue?(i(),g(w,{key:0,name:`check`,size:16,class:`admin-select__check`})):b(``,!0)],10,F)]))),128))],12,j)):b(``,!0)]))],10,E))}}),[[`__scopeId`,`data-v-4623e322`]]);export{L as t};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
import{M as e,O as t,Ot as n,Tt as r,c as i,d as a,g as o,h as s,t as c,u as l}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{L as u}from"./index-CznUUXv3.js";var d={class:`base-empty__icon`,"aria-hidden":`true`},f={class:`base-empty__title`},p={key:0,class:`base-empty__description`},m={key:1,class:`base-empty__actions`},h=c(o({__name:`BaseEmptyState`,props:{icon:{default:`file`},title:{},description:{},compact:{type:Boolean}},emits:[`action`,`secondary`],setup(o){return(c,h)=>(t(),a(`div`,{class:r([`base-empty`,{"base-empty--compact":o.compact}])},[i(`div`,d,[s(u,{name:o.icon,size:o.compact?28:36},null,8,[`name`,`size`])]),i(`h3`,f,n(o.title),1),o.description?(t(),a(`p`,p,n(o.description),1)):l(``,!0),c.$slots.default||c.$slots.secondary?(t(),a(`div`,m,[e(c.$slots,`default`,{},void 0,!0),e(c.$slots,`secondary`,{},void 0,!0)])):l(``,!0)],2))}}),[[`__scopeId`,`data-v-47ea81e4`]]);export{h as t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Dt as t,N as n,c as r,d as i,g as a,h as o,k as s,t as c,u as l}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{L as u}from"./index-pv0Ktkd1.js";var d={class:`base-empty__icon`,"aria-hidden":`true`},f={class:`base-empty__title`},p={key:0,class:`base-empty__description`},m={key:1,class:`base-empty__actions`},h=c(a({__name:`BaseEmptyState`,props:{icon:{default:`file`},title:{},description:{},compact:{type:Boolean}},emits:[`action`,`secondary`],setup(a){return(c,h)=>(s(),i(`div`,{class:t([`base-empty`,{"base-empty--compact":a.compact}])},[r(`div`,d,[o(u,{name:a.icon,size:a.compact?28:36},null,8,[`name`,`size`])]),r(`h3`,f,e(a.title),1),a.description?(s(),i(`p`,p,e(a.description),1)):l(``,!0),c.$slots.default||c.$slots.secondary?(s(),i(`div`,m,[n(c.$slots,`default`,{},void 0,!0),n(c.$slots,`secondary`,{},void 0,!0)])):l(``,!0)],2))}}),[[`__scopeId`,`data-v-47ea81e4`]]);export{h as t};
-1
View File
@@ -1 +0,0 @@
import{O as e,Ot as t,Tt as n,c as r,d as i,g as a,s as o,t as s,u as c}from"./_plugin-vue_export-helper-OaxA6A2f.js";var l=[`title`],u={key:0,class:`base-switch__label`},d={class:`base-switch__control`},f=[`id`,`checked`,`disabled`,`aria-checked`,`aria-label`],p={class:`base-switch__track`,"aria-hidden":`true`},m={class:`base-switch__thumb`},h={key:0,class:`base-switch__spinner`},g=s(a({__name:`BaseSwitch`,props:{modelValue:{type:Boolean},disabled:{type:Boolean},loading:{type:Boolean},error:{type:Boolean},label:{},activeText:{default:`فعال`},inactiveText:{default:`غیرفعال`},id:{}},emits:[`update:modelValue`],setup(a,{emit:s}){let g=a,_=s,v=o(()=>g.id??`switch-${crypto.randomUUID().slice(0,8)}`),y=o(()=>g.modelValue?g.activeText:g.inactiveText);function b(e){let t=e.target,n=t.checked;t.checked=g.modelValue,!(g.disabled||g.loading)&&_(`update:modelValue`,n)}return(o,s)=>(e(),i(`label`,{class:n([`base-switch`,{"base-switch--disabled":a.disabled||a.loading,"base-switch--error":a.error}]),title:y.value},[a.label?(e(),i(`span`,u,t(a.label),1)):c(``,!0),r(`span`,d,[r(`input`,{id:v.value,class:`base-switch__input`,type:`checkbox`,role:`switch`,checked:a.modelValue,disabled:a.disabled||a.loading,"aria-checked":a.modelValue,"aria-label":a.label||y.value,onChange:b},null,40,f),r(`span`,p,[r(`span`,m,[a.loading?(e(),i(`span`,h)):c(``,!0)])])])],10,l))}}),[[`__scopeId`,`data-v-0410eed4`]]);export{g as t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Dt as t,c as n,d as r,g as i,k as a,s as o,t as s,u as c}from"./_plugin-vue_export-helper-QrIvvHC8.js";var l=[`title`],u={key:0,class:`base-switch__label`},d={class:`base-switch__control`},f=[`id`,`checked`,`disabled`,`aria-checked`,`aria-label`],p={class:`base-switch__track`,"aria-hidden":`true`},m={class:`base-switch__thumb`},h={key:0,class:`base-switch__spinner`},g=s(i({__name:`BaseSwitch`,props:{modelValue:{type:Boolean},disabled:{type:Boolean},loading:{type:Boolean},error:{type:Boolean},label:{},activeText:{default:`فعال`},inactiveText:{default:`غیرفعال`},id:{}},emits:[`update:modelValue`],setup(i,{emit:s}){let g=i,_=s,v=o(()=>g.id??`switch-${crypto.randomUUID().slice(0,8)}`),y=o(()=>g.modelValue?g.activeText:g.inactiveText);function b(e){let t=e.target,n=t.checked;t.checked=g.modelValue,!(g.disabled||g.loading)&&_(`update:modelValue`,n)}return(o,s)=>(a(),r(`label`,{class:t([`base-switch`,{"base-switch--disabled":i.disabled||i.loading,"base-switch--error":i.error}]),title:y.value},[i.label?(a(),r(`span`,u,e(i.label),1)):c(``,!0),n(`span`,d,[n(`input`,{id:v.value,class:`base-switch__input`,type:`checkbox`,role:`switch`,checked:i.modelValue,disabled:i.disabled||i.loading,"aria-checked":i.modelValue,"aria-label":i.label||y.value,onChange:b},null,40,f),n(`span`,p,[n(`span`,m,[i.loading?(a(),r(`span`,h)):c(``,!0)])])])],10,l))}}),[[`__scopeId`,`data-v-0410eed4`]]);export{g as t};
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,E as n,H as r,M as i,U as a,Z as o,c as s,d as c,g as l,h as u,k as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as _,f as v,t as y}from"./http-BjLkjdQu.js";import{V as b,p as x}from"./index-pv0Ktkd1.js";import{t as S}from"./AdminPageSkeleton-oWhHYjl4.js";import{t as C}from"./BaseSwitch-pJwnFBVo.js";import{t as w}from"./BaseEmptyState-y-wpauXF.js";var T={class:`admin-page`},E={key:2,class:`admin-table`},D={dir:`ltr`},O=[`onClick`],k={class:`field`},A={class:`field`},j={class:`field`},M={class:`field`},N=[`disabled`],P=g(l({__name:`BrandsView`,setup(l){let g=e([]),P=e(!0),F=e(!1),I=e(null),L=_(),R=o({name:``,slug:``,description:``,displayOrder:0,isActive:!0}),z=h(()=>I.value?`ویرایش برند`:`افزودن برند`);async function B(){P.value=!0;try{g.value=await x.list()}catch(e){L.error(e instanceof y?e.message:`بارگذاری برندها ناموفق بود`)}finally{P.value=!1}}function V(){I.value=null,Object.assign(R,{name:``,slug:``,description:``,displayOrder:g.value.length+1,isActive:!0}),F.value=!0}function H(e){I.value=e.id,Object.assign(R,{name:e.name,slug:e.slug??``,description:e.description??``,displayOrder:e.displayOrder,isActive:e.isActive}),F.value=!0}async function U(){try{let e={name:R.name.trim(),slug:R.slug.trim()||void 0,description:R.description.trim()||void 0,displayOrder:R.displayOrder,isActive:R.isActive};I.value?await x.update(I.value,e):await x.create(e),F.value=!1,L.success(`ذخیره شد`),await B()}catch(e){L.error(e instanceof y?e.message:`ذخیره ناموفق بود`)}}return n(()=>{B()}),(e,n)=>(d(),c(`div`,T,[s(`header`,{class:`admin-page__head`},[n[6]||=s(`div`,null,[s(`h1`,null,`برندها`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:V},`افزودن برند`)]),P.value?(d(),f(S,{key:0,variant:`table`})):g.value.length?(d(),c(`table`,E,[n[7]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`نام`),s(`th`,null,`شناسه لاتین`),s(`th`,null,`مشتریان`),s(`th`,null,`فعال`),s(`th`)])],-1),s(`tbody`,null,[(d(!0),c(m,null,i(g.value,e=>(d(),c(`tr`,{key:e.id},[s(`td`,null,t(e.name),1),s(`td`,D,t(e.slug||`—`),1),s(`td`,null,t(e.customersCount??0),1),s(`td`,null,t(e.isActive?`بله`:`خیر`),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>H(e)},`ویرایش`,8,O)])]))),128))])])):(d(),f(w,{key:1,title:`برندی ثبت نشده`})),u(b,{open:F.value,title:z.value,onClose:n[5]||=e=>F.value=!1},{footer:r(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!R.name.trim(),onClick:U},`ذخیره`,8,N)]),default:r(()=>[s(`label`,k,[n[8]||=p(`نام`,-1),a(s(`input`,{"onUpdate:modelValue":n[0]||=e=>R.name=e,class:`admin-input`},null,512),[[v,R.name]])]),s(`label`,A,[n[9]||=p(`شناسه لاتین`,-1),a(s(`input`,{"onUpdate:modelValue":n[1]||=e=>R.slug=e,class:`admin-input`,dir:`ltr`,placeholder:`مثلاً nademi-silk`},null,512),[[v,R.slug]])]),s(`label`,j,[n[10]||=p(`توضیح`,-1),a(s(`textarea`,{"onUpdate:modelValue":n[2]||=e=>R.description=e,class:`admin-input`,rows:`3`},null,512),[[v,R.description]])]),s(`label`,M,[n[11]||=p(`ترتیب`,-1),a(s(`input`,{"onUpdate:modelValue":n[3]||=e=>R.displayOrder=e,type:`number`,class:`admin-input`},null,512),[[v,R.displayOrder,void 0,{number:!0}]])]),u(C,{modelValue:R.isActive,"onUpdate:modelValue":n[4]||=e=>R.isActive=e,label:`فعال`},null,8,[`modelValue`])]),_:1},8,[`open`,`title`])]))}}),[[`__scopeId`,`data-v-88043806`]]);export{P as default};
-1
View File
@@ -1 +0,0 @@
import{B as e,O as t,Ot as n,T as r,V as i,Y as a,Z as o,c as s,d as c,g as l,h as u,j as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as _,f as v,t as y}from"./http-Djf2pGxE.js";import{V as b,p as x}from"./index-CznUUXv3.js";import{t as S}from"./AdminPageSkeleton-CTgUqaAu.js";import{t as C}from"./BaseSwitch-TV5Yvtf7.js";import{t as w}from"./BaseEmptyState-D6sk-aI_.js";var T={class:`admin-page`},E={key:2,class:`admin-table`},D={dir:`ltr`},O=[`onClick`],k={class:`field`},A={class:`field`},j={class:`field`},M={class:`field`},N=[`disabled`],P=g(l({__name:`BrandsView`,setup(l){let g=o([]),P=o(!0),F=o(!1),I=o(null),L=_(),R=a({name:``,slug:``,description:``,displayOrder:0,isActive:!0}),z=h(()=>I.value?`ویرایش برند`:`افزودن برند`);async function B(){P.value=!0;try{g.value=await x.list()}catch(e){L.error(e instanceof y?e.message:`بارگذاری برندها ناموفق بود`)}finally{P.value=!1}}function V(){I.value=null,Object.assign(R,{name:``,slug:``,description:``,displayOrder:g.value.length+1,isActive:!0}),F.value=!0}function H(e){I.value=e.id,Object.assign(R,{name:e.name,slug:e.slug??``,description:e.description??``,displayOrder:e.displayOrder,isActive:e.isActive}),F.value=!0}async function U(){try{let e={name:R.name.trim(),slug:R.slug.trim()||void 0,description:R.description.trim()||void 0,displayOrder:R.displayOrder,isActive:R.isActive};I.value?await x.update(I.value,e):await x.create(e),F.value=!1,L.success(`ذخیره شد`),await B()}catch(e){L.error(e instanceof y?e.message:`ذخیره ناموفق بود`)}}return r(()=>{B()}),(r,a)=>(t(),c(`div`,T,[s(`header`,{class:`admin-page__head`},[a[6]||=s(`div`,null,[s(`h1`,null,`برندها`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:V},`افزودن برند`)]),P.value?(t(),f(S,{key:0,variant:`table`})):g.value.length?(t(),c(`table`,E,[a[7]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`نام`),s(`th`,null,`شناسه لاتین`),s(`th`,null,`مشتریان`),s(`th`,null,`فعال`),s(`th`)])],-1),s(`tbody`,null,[(t(!0),c(m,null,d(g.value,e=>(t(),c(`tr`,{key:e.id},[s(`td`,null,n(e.name),1),s(`td`,D,n(e.slug||`—`),1),s(`td`,null,n(e.customersCount??0),1),s(`td`,null,n(e.isActive?`بله`:`خیر`),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>H(e)},`ویرایش`,8,O)])]))),128))])])):(t(),f(w,{key:1,title:`برندی ثبت نشده`})),u(b,{open:F.value,title:z.value,onClose:a[5]||=e=>F.value=!1},{footer:e(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!R.name.trim(),onClick:U},`ذخیره`,8,N)]),default:e(()=>[s(`label`,k,[a[8]||=p(`نام`,-1),i(s(`input`,{"onUpdate:modelValue":a[0]||=e=>R.name=e,class:`admin-input`},null,512),[[v,R.name]])]),s(`label`,A,[a[9]||=p(`شناسه لاتین`,-1),i(s(`input`,{"onUpdate:modelValue":a[1]||=e=>R.slug=e,class:`admin-input`,dir:`ltr`,placeholder:`مثلاً nademi-silk`},null,512),[[v,R.slug]])]),s(`label`,j,[a[10]||=p(`توضیح`,-1),i(s(`textarea`,{"onUpdate:modelValue":a[2]||=e=>R.description=e,class:`admin-input`,rows:`3`},null,512),[[v,R.description]])]),s(`label`,M,[a[11]||=p(`ترتیب`,-1),i(s(`input`,{"onUpdate:modelValue":a[3]||=e=>R.displayOrder=e,type:`number`,class:`admin-input`},null,512),[[v,R.displayOrder,void 0,{number:!0}]])]),u(C,{modelValue:R.isActive,"onUpdate:modelValue":a[4]||=e=>R.isActive=e,label:`فعال`},null,8,[`modelValue`])]),_:1},8,[`open`,`title`])]))}}),[[`__scopeId`,`data-v-88043806`]]);export{P as default};
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
.cash-payments-page__filters[data-v-9afb2a83]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;display:flex}.cash-payments-page__search[data-v-9afb2a83]{min-width:200px;color:var(--color-text-muted);flex:1;align-items:center;gap:10px;display:flex}.cash-payments-page__search-input[data-v-9afb2a83]{color:var(--color-text);background:0 0;border:none;outline:none;flex:1;font-size:.875rem}.cash-payments-page__status-select[data-v-9afb2a83]{flex:0 220px;width:220px}.cash-payments-page__table[data-v-9afb2a83]{overflow:hidden}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
.cash-payments-page__filters[data-v-367bdef1]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;display:flex}.cash-payments-page__search[data-v-367bdef1]{min-width:200px;color:var(--color-text-muted);flex:1;align-items:center;gap:10px;display:flex}.cash-payments-page__search-input[data-v-367bdef1]{color:var(--color-text);background:0 0;border:none;outline:none;flex:1;font-size:.875rem}.cash-payments-page__status-select[data-v-367bdef1]{flex:0 220px;width:220px}.cash-payments-page__table[data-v-367bdef1]{overflow:hidden}
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,E as n,M as r,c as i,d as a,g as o,h as s,k as c,l,m as u,r as d,st as f,t as p,u as m}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as h,t as g}from"./http-BjLkjdQu.js";import{h as _,o as v}from"./index-pv0Ktkd1.js";import{t as y}from"./AdminPageSkeleton-oWhHYjl4.js";import{t as b}from"./BaseEmptyState-y-wpauXF.js";import{t as x}from"./AdminSelect-DFH4VaRE.js";var S={class:`admin-page`},C={class:`admin-page__head`},w={class:`request-card__top`},T={class:`muted`,dir:`ltr`},E={class:`badge`},D={key:0,class:`muted`},O={class:`admin-table`},k={dir:`ltr`},A={key:0,class:`movements`},j={class:`muted`},M=p(o({__name:`CatalogRequestsView`,setup(o){let p=[{value:``,label:`همه وضعیت‌ها`},{value:`new`,label:`درخواست جدید`},{value:`approved`,label:`تأیید شده`},{value:`ready_to_ship`,label:`آماده ارسال`},{value:`delivered`,label:`تحویل به مشتری`},{value:`returned`,label:`بازگردانده شده`},{value:`cancelled`,label:`لغو شده`}],M=[{value:`warehouse`,label:`انبار`},{value:`customer`,label:`مشتری`},{value:`agent`,label:`واسطه`}],N=Object.fromEntries(p.filter(e=>e.value).map(e=>[e.value,e.label])),P=Object.fromEntries(M.map(e=>[e.value,e.label])),F=e([]),I=e(``),L=e(!0),R=e(null),z=h();async function B(){L.value=!0;try{F.value=await _.list(I.value||void 0)}catch(e){z.error(e instanceof g?e.message:`بارگذاری انجام نشد`)}finally{L.value=!1}}async function V(e,t){try{await _.updateStatus(e,t),z.success(`وضعیت به‌روز شد`),await B()}catch(e){z.error(e instanceof g?e.message:`به‌روزرسانی ناموفق بود`)}}async function H(e,t){if(!R.value){R.value=e;try{await _.updateHolder(e,{holderType:t}),z.success(`محل نگهداری به‌روز شد`),await B()}catch(e){z.error(e instanceof g?e.message:`به‌روزرسانی محل ناموفق بود`)}finally{R.value=null}}}function U(e){return P[e]??e}return n(()=>{B()}),(e,n)=>(c(),a(`div`,S,[i(`header`,C,[n[1]||=i(`div`,null,[i(`h1`,null,`درخواست کالیته فیزیکی`),i(`p`,null,`بررسی، گردش وضعیت و محل نگهداری اقلام`)],-1),s(x,{modelValue:I.value,"onUpdate:modelValue":[n[0]||=e=>I.value=e,B],options:p},null,8,[`modelValue`])]),L.value?(c(),l(y,{key:0,variant:`cards`})):F.value.length?(c(!0),a(d,{key:2},r(F.value,e=>(c(),a(`div`,{key:e.id,class:`request-card`},[i(`div`,w,[i(`div`,null,[i(`strong`,null,t(e.customerName),1),i(`span`,T,t(e.customerPhone),1),i(`span`,E,t(f(N)[e.status]??e.status),1)]),s(x,{"model-value":e.status,options:p.filter(e=>e.value),"onUpdate:modelValue":t=>V(e.id,String(t))},null,8,[`model-value`,`options`,`onUpdate:modelValue`])]),e.note?(c(),a(`p`,D,t(e.note),1)):m(``,!0),i(`table`,O,[n[2]||=i(`thead`,null,[i(`tr`,null,[i(`th`,null,`محصول`),i(`th`,null,`کد`),i(`th`,null,`تعداد`),i(`th`,null,`محل`)])],-1),i(`tbody`,null,[(c(!0),a(d,null,r(e.items,e=>(c(),a(`tr`,{key:e.id},[i(`td`,null,t(e.productName),1),i(`td`,k,t(e.productCode),1),i(`td`,null,t(e.quantity),1),i(`td`,null,[s(x,{"model-value":e.holderType,options:M,"onUpdate:modelValue":t=>H(e.id,String(t))},null,8,[`model-value`,`onUpdate:modelValue`]),e.movements?.length?(c(),a(`ul`,A,[(c(!0),a(d,null,r(e.movements,e=>(c(),a(`li`,{key:e.id},[u(t(U(e.fromHolder))+` → `+t(U(e.toHolder))+` `,1),i(`span`,j,t(f(v)(e.movedAt)),1)]))),128))])):m(``,!0)])]))),128))])])]))),128)):(c(),l(b,{key:1,title:`درخواستی نیست`}))]))}}),[[`__scopeId`,`data-v-747d8f88`]]);export{M as default};
-1
View File
@@ -1 +0,0 @@
import{O as e,Ot as t,T as n,Z as r,at as i,c as a,d as o,g as s,h as c,j as l,l as u,m as d,r as f,t as p,u as m}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as h,t as g}from"./http-Djf2pGxE.js";import{h as _,o as v}from"./index-CznUUXv3.js";import{t as y}from"./AdminPageSkeleton-CTgUqaAu.js";import{t as b}from"./BaseEmptyState-D6sk-aI_.js";import{t as x}from"./AdminSelect-DK-_otkw.js";var S={class:`admin-page`},C={class:`admin-page__head`},w={class:`request-card__top`},T={class:`muted`,dir:`ltr`},E={class:`badge`},D={key:0,class:`muted`},O={class:`admin-table`},k={dir:`ltr`},A={key:0,class:`movements`},j={class:`muted`},M=p(s({__name:`CatalogRequestsView`,setup(s){let p=[{value:``,label:`همه وضعیت‌ها`},{value:`new`,label:`درخواست جدید`},{value:`approved`,label:`تأیید شده`},{value:`ready_to_ship`,label:`آماده ارسال`},{value:`delivered`,label:`تحویل به مشتری`},{value:`returned`,label:`بازگردانده شده`},{value:`cancelled`,label:`لغو شده`}],M=[{value:`warehouse`,label:`انبار`},{value:`customer`,label:`مشتری`},{value:`agent`,label:`واسطه`}],N=Object.fromEntries(p.filter(e=>e.value).map(e=>[e.value,e.label])),P=Object.fromEntries(M.map(e=>[e.value,e.label])),F=r([]),I=r(``),L=r(!0),R=r(null),z=h();async function B(){L.value=!0;try{F.value=await _.list(I.value||void 0)}catch(e){z.error(e instanceof g?e.message:`بارگذاری انجام نشد`)}finally{L.value=!1}}async function V(e,t){try{await _.updateStatus(e,t),z.success(`وضعیت به‌روز شد`),await B()}catch(e){z.error(e instanceof g?e.message:`به‌روزرسانی ناموفق بود`)}}async function H(e,t){if(!R.value){R.value=e;try{await _.updateHolder(e,{holderType:t}),z.success(`محل نگهداری به‌روز شد`),await B()}catch(e){z.error(e instanceof g?e.message:`به‌روزرسانی محل ناموفق بود`)}finally{R.value=null}}}function U(e){return P[e]??e}return n(()=>{B()}),(n,r)=>(e(),o(`div`,S,[a(`header`,C,[r[1]||=a(`div`,null,[a(`h1`,null,`درخواست کالیته فیزیکی`),a(`p`,null,`بررسی، گردش وضعیت و محل نگهداری اقلام`)],-1),c(x,{modelValue:I.value,"onUpdate:modelValue":[r[0]||=e=>I.value=e,B],options:p},null,8,[`modelValue`])]),L.value?(e(),u(y,{key:0,variant:`cards`})):F.value.length?(e(!0),o(f,{key:2},l(F.value,n=>(e(),o(`div`,{key:n.id,class:`request-card`},[a(`div`,w,[a(`div`,null,[a(`strong`,null,t(n.customerName),1),a(`span`,T,t(n.customerPhone),1),a(`span`,E,t(i(N)[n.status]??n.status),1)]),c(x,{"model-value":n.status,options:p.filter(e=>e.value),"onUpdate:modelValue":e=>V(n.id,String(e))},null,8,[`model-value`,`options`,`onUpdate:modelValue`])]),n.note?(e(),o(`p`,D,t(n.note),1)):m(``,!0),a(`table`,O,[r[2]||=a(`thead`,null,[a(`tr`,null,[a(`th`,null,`محصول`),a(`th`,null,`کد`),a(`th`,null,`تعداد`),a(`th`,null,`محل`)])],-1),a(`tbody`,null,[(e(!0),o(f,null,l(n.items,n=>(e(),o(`tr`,{key:n.id},[a(`td`,null,t(n.productName),1),a(`td`,k,t(n.productCode),1),a(`td`,null,t(n.quantity),1),a(`td`,null,[c(x,{"model-value":n.holderType,options:M,"onUpdate:modelValue":e=>H(n.id,String(e))},null,8,[`model-value`,`onUpdate:modelValue`]),n.movements?.length?(e(),o(`ul`,A,[(e(!0),o(f,null,l(n.movements,n=>(e(),o(`li`,{key:n.id},[d(t(U(n.fromHolder))+` → `+t(U(n.toHolder))+` `,1),a(`span`,j,t(i(v)(n.movedAt)),1)]))),128))])):m(``,!0)])]))),128))])])]))),128)):(e(),u(b,{key:1,title:`درخواستی نیست`}))]))}}),[[`__scopeId`,`data-v-747d8f88`]]);export{M as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
import{B as e,O as t,Ot as n,T as r,V as i,Y as a,Z as o,c as s,d as c,g as l,h as u,j as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as _,f as v,t as y}from"./http-Djf2pGxE.js";import{V as b,x}from"./index-CznUUXv3.js";import{t as S}from"./AdminPageSkeleton-CTgUqaAu.js";import{t as C}from"./BaseEmptyState-D6sk-aI_.js";var w={class:`admin-page`},T={key:2,class:`admin-table`},E={dir:`ltr`},D=[`onClick`],O={class:`field`},k={class:`field`},A={class:`field`},j={class:`field`},M=[`disabled`],N=g(l({__name:`LevelsView`,setup(l){let g=o([]),N=o(!0),P=o(!1),F=o(null),I=_(),L=a({code:``,label:``,sortOrder:0,benefitsText:``}),R=h(()=>F.value?`ویرایش سطح`:`سطح جدید`);function z(e){return e.split(`
import{$ as e,At as t,E as n,H as r,M as i,U as a,Z as o,c as s,d as c,g as l,h as u,k as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as _,f as v,t as y}from"./http-BjLkjdQu.js";import{V as b,x}from"./index-pv0Ktkd1.js";import{t as S}from"./AdminPageSkeleton-oWhHYjl4.js";import{t as C}from"./BaseEmptyState-y-wpauXF.js";var w={class:`admin-page`},T={key:2,class:`admin-table`},E={dir:`ltr`},D=[`onClick`],O={class:`field`},k={class:`field`},A={class:`field`},j={class:`field`},M=[`disabled`],N=g(l({__name:`LevelsView`,setup(l){let g=e([]),N=e(!0),P=e(!1),F=e(null),I=_(),L=o({code:``,label:``,sortOrder:0,benefitsText:``}),R=h(()=>F.value?`ویرایش سطح`:`سطح جدید`);function z(e){return e.split(`
`).map(e=>e.trim()).filter(Boolean).map(e=>({title:e}))}async function B(){N.value=!0;try{g.value=await x.list()}catch(e){I.error(e instanceof y?e.message:`بارگذاری سطوح ناموفق بود`)}finally{N.value=!1}}function V(){F.value=null,Object.assign(L,{code:``,label:``,sortOrder:g.value.length+1,benefitsText:``}),P.value=!0}function H(e){F.value=e.id,Object.assign(L,{code:e.code,label:e.label,sortOrder:e.sortOrder,benefitsText:e.benefits.map(e=>e.title).join(`
`)}),P.value=!0}async function U(){try{let e={code:L.code.trim(),label:L.label.trim(),sortOrder:L.sortOrder,benefits:z(L.benefitsText)};F.value?await x.update(F.value,e):await x.create(e),P.value=!1,I.success(`ذخیره شد`),await B()}catch(e){I.error(e instanceof y?e.message:`ذخیره ناموفق بود`)}}return r(()=>{B()}),(r,a)=>(t(),c(`div`,w,[s(`header`,{class:`admin-page__head`},[a[5]||=s(`div`,null,[s(`h1`,null,`سطوح و مزایای مشتری`),s(`p`,null,`تعریف Level داخلی CRM و مزایای هر سطح (نمایش فقط در ادمین)`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:V},`سطح جدید`)]),N.value?(t(),f(S,{key:0,variant:`table`})):g.value.length?(t(),c(`table`,T,[a[6]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`کد`),s(`th`,null,`عنوان`),s(`th`,null,`مزایا`),s(`th`,null,`مشتریان`),s(`th`)])],-1),s(`tbody`,null,[(t(!0),c(m,null,d(g.value,e=>(t(),c(`tr`,{key:e.id},[s(`td`,E,n(e.code),1),s(`td`,null,n(e.label),1),s(`td`,null,n(e.benefits.map(e=>e.title).join(`، `)||`—`),1),s(`td`,null,n(e.customersCount),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>H(e)},`ویرایش`,8,D)])]))),128))])])):(t(),f(C,{key:1,title:`سطحی تعریف نشده`})),u(b,{open:P.value,title:R.value,onClose:a[4]||=e=>P.value=!1},{footer:e(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!L.code.trim()||!L.label.trim(),onClick:U},` ذخیره `,8,M)]),default:e(()=>[s(`label`,O,[a[7]||=p(`کد`,-1),i(s(`input`,{"onUpdate:modelValue":a[0]||=e=>L.code=e,class:`admin-input`,dir:`ltr`},null,512),[[v,L.code]])]),s(`label`,k,[a[8]||=p(`عنوان`,-1),i(s(`input`,{"onUpdate:modelValue":a[1]||=e=>L.label=e,class:`admin-input`},null,512),[[v,L.label]])]),s(`label`,A,[a[9]||=p(`ترتیب`,-1),i(s(`input`,{"onUpdate:modelValue":a[2]||=e=>L.sortOrder=e,type:`number`,class:`admin-input`},null,512),[[v,L.sortOrder,void 0,{number:!0}]])]),s(`label`,j,[a[10]||=p(` مزایا (هر خط یک مورد) `,-1),i(s(`textarea`,{"onUpdate:modelValue":a[3]||=e=>L.benefitsText=e,class:`admin-input`,rows:`4`},null,512),[[v,L.benefitsText]])])]),_:1},8,[`open`,`title`])]))}}),[[`__scopeId`,`data-v-44c7f808`]]);export{N as default};
`)}),P.value=!0}async function U(){try{let e={code:L.code.trim(),label:L.label.trim(),sortOrder:L.sortOrder,benefits:z(L.benefitsText)};F.value?await x.update(F.value,e):await x.create(e),P.value=!1,I.success(`ذخیره شد`),await B()}catch(e){I.error(e instanceof y?e.message:`ذخیره ناموفق بود`)}}return n(()=>{B()}),(e,n)=>(d(),c(`div`,w,[s(`header`,{class:`admin-page__head`},[n[5]||=s(`div`,null,[s(`h1`,null,`سطوح و مزایای مشتری`),s(`p`,null,`تعریف Level داخلی CRM و مزایای هر سطح (نمایش فقط در ادمین)`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:V},`سطح جدید`)]),N.value?(d(),f(S,{key:0,variant:`table`})):g.value.length?(d(),c(`table`,T,[n[6]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`کد`),s(`th`,null,`عنوان`),s(`th`,null,`مزایا`),s(`th`,null,`مشتریان`),s(`th`)])],-1),s(`tbody`,null,[(d(!0),c(m,null,i(g.value,e=>(d(),c(`tr`,{key:e.id},[s(`td`,E,t(e.code),1),s(`td`,null,t(e.label),1),s(`td`,null,t(e.benefits.map(e=>e.title).join(`، `)||`—`),1),s(`td`,null,t(e.customersCount),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>H(e)},`ویرایش`,8,D)])]))),128))])])):(d(),f(C,{key:1,title:`سطحی تعریف نشده`})),u(b,{open:P.value,title:R.value,onClose:n[4]||=e=>P.value=!1},{footer:r(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!L.code.trim()||!L.label.trim(),onClick:U},` ذخیره `,8,M)]),default:r(()=>[s(`label`,O,[n[7]||=p(`کد`,-1),a(s(`input`,{"onUpdate:modelValue":n[0]||=e=>L.code=e,class:`admin-input`,dir:`ltr`},null,512),[[v,L.code]])]),s(`label`,k,[n[8]||=p(`عنوان`,-1),a(s(`input`,{"onUpdate:modelValue":n[1]||=e=>L.label=e,class:`admin-input`},null,512),[[v,L.label]])]),s(`label`,A,[n[9]||=p(`ترتیب`,-1),a(s(`input`,{"onUpdate:modelValue":n[2]||=e=>L.sortOrder=e,type:`number`,class:`admin-input`},null,512),[[v,L.sortOrder,void 0,{number:!0}]])]),s(`label`,j,[n[10]||=p(` مزایا (هر خط یک مورد) `,-1),a(s(`textarea`,{"onUpdate:modelValue":n[3]||=e=>L.benefitsText=e,class:`admin-input`,rows:`4`},null,512),[[v,L.benefitsText]])])]),_:1},8,[`open`,`title`])]))}}),[[`__scopeId`,`data-v-44c7f808`]]);export{N as default};
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,U as n,c as r,d as i,g as a,h as o,k as s,m as c,s as l,st as u,t as d,u as f}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as p,f as m,l as h,m as g,u as _}from"./http-BjLkjdQu.js";import{F as v,I as y,L as b,P as x,R as S,z as C}from"./index-pv0Ktkd1.js";var w={class:`login-page`},T={class:`login-page__form-wrap`},E={class:`login-page__card admin-card`},D={class:`login-page__header`},O={key:0,class:`login-page__mock-hint`},k={dir:`ltr`},A={dir:`ltr`},j={key:0,class:`admin-form__error`,role:`alert`},M={class:`admin-form__field`},N={class:`login-page__input-wrap`},P={class:`login-page__field-icon`,"aria-hidden":`true`},F={class:`admin-form__field`},I={class:`login-page__input-wrap login-page__input-wrap--password`},L={class:`login-page__field-icon`,"aria-hidden":`true`},R=[`type`],z=[`aria-label`],B={class:`login-page__remember`},V=[`disabled`],H={key:0,class:`admin-btn__spinner`,"aria-hidden":`true`},U=d(a({__name:`LoginView`,setup(a){let d=C(),U=S(),W=x(),G=p(),K=e(y()?v.phone:``),q=e(y()?v.password:``),J=e(!0),Y=e(!1),X=y(),Z=l(()=>K.value.trim().length>0&&q.value.length>0);function Q(e){return e.replace(/[۰-۹]/g,e=>String(`۰۱۲۳۴۵۶۷۸۹`.indexOf(e))).replace(/[٠-٩]/g,e=>String(`٠١٢٣٤٥٦٧٨٩`.indexOf(e)))}async function $(){if(!Z.value){W.error=`لطفاً شماره موبایل و رمز عبور را وارد کنید.`;return}if(!await W.login(Q(K.value.trim()),q.value,J.value))return;G.success(`خوش آمدید، ${W.fullName}`);let e=typeof U.query.redirect==`string`?U.query.redirect:`/`,t=`/admin/`.replace(/\/$/,``),n=e.startsWith(t)?e.slice(t.length)||`/`:e;await d.replace(n)}return(e,a)=>(s(),i(`div`,w,[r(`div`,T,[r(`div`,E,[r(`div`,D,[a[8]||=r(`h2`,{class:`login-page__title`},`ورود به پنل مدیریت`,-1),a[9]||=r(`p`,{class:`login-page__subtitle`},`برای ادامه، اطلاعات حساب کاربری خود را وارد کنید.`,-1),u(X)?(s(),i(`p`,O,[a[6]||=c(` حالت موک فعال است — `,-1),r(`span`,k,t(u(v).phone),1),a[7]||=c(` / `,-1),r(`span`,A,t(u(v).password),1)])):f(``,!0)]),r(`form`,{class:`admin-form login-page__form`,onSubmit:g($,[`prevent`])},[u(W).error?(s(),i(`p`,j,t(u(W).error),1)):f(``,!0),r(`div`,M,[a[10]||=r(`label`,{for:`login-phone`},`شماره موبایل`,-1),r(`div`,N,[r(`span`,P,[o(b,{name:`phone`,size:18})]),n(r(`input`,{id:`login-phone`,"onUpdate:modelValue":a[0]||=e=>K.value=e,type:`tel`,class:`admin-input login-page__input`,placeholder:`۰۹۱۲۱۱۱۱۲۲۲۲`,autocomplete:`username`,inputmode:`tel`,dir:`ltr`,onInput:a[1]||=e=>u(W).clearError()},null,544),[[m,K.value]])])]),r(`div`,F,[a[11]||=r(`label`,{for:`login-password`},`رمز عبور`,-1),r(`div`,I,[r(`span`,L,[o(b,{name:`lock`,size:18})]),n(r(`input`,{id:`login-password`,"onUpdate:modelValue":a[2]||=e=>q.value=e,type:Y.value?`text`:`password`,class:`admin-input login-page__input login-page__input--with-toggle`,placeholder:`رمز عبور`,autocomplete:`current-password`,onInput:a[3]||=e=>u(W).clearError()},null,40,R),[[_,q.value]]),r(`button`,{type:`button`,class:`login-page__toggle-password`,"aria-label":Y.value?`پنهان کردن رمز`:`نمایش رمز`,onClick:a[4]||=e=>Y.value=!Y.value},[o(b,{name:Y.value?`eye-off`:`eye`,size:18},null,8,[`name`])],8,z)])]),r(`label`,B,[n(r(`input`,{"onUpdate:modelValue":a[5]||=e=>J.value=e,type:`checkbox`},null,512),[[h,J.value]]),a[12]||=r(`span`,null,`مرا به خاطر بسپار`,-1)]),r(`button`,{type:`submit`,class:`admin-btn admin-btn--primary login-page__submit`,disabled:!Z.value||u(W).loading},[u(W).loading?(s(),i(`span`,H)):f(``,!0),a[13]||=c(` ورود به پنل `,-1)],8,V)],32)])]),r(`div`,{class:`login-page__brand`},[r(`div`,{class:`login-page__brand-inner`},[r(`img`,{src:`/admin/brand-logo.png`,alt:`نادمی تکس`,class:`login-page__brand-logo`}),a[14]||=r(`p`,{class:`login-page__brand-badge`},`پارچه`,-1),a[15]||=r(`h1`,{class:`login-page__brand-title`},`پنل مدیریت سفارش‌های عمده`,-1),a[16]||=r(`p`,{class:`login-page__brand-text`},` مدیریت سفارش‌ها، مشتریان، قیمت‌گذاری، چک‌ها و گزارش‌های فروش در یک محیط یکپارچه. `,-1)])])]))}}),[[`__scopeId`,`data-v-df8d196a`]]);export{U as default};
-1
View File
@@ -1 +0,0 @@
import{O as e,Ot as t,V as n,Z as r,at as i,c as a,d as o,g as s,h as c,m as l,s as u,t as d,u as f}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as p,f as m,l as h,m as g,u as _}from"./http-Djf2pGxE.js";import{F as v,I as y,L as b,P as x,R as S,z as C}from"./index-CznUUXv3.js";var w={class:`login-page`},T={class:`login-page__form-wrap`},E={class:`login-page__card admin-card`},D={class:`login-page__header`},O={key:0,class:`login-page__mock-hint`},k={dir:`ltr`},A={dir:`ltr`},j={key:0,class:`admin-form__error`,role:`alert`},M={class:`admin-form__field`},N={class:`login-page__input-wrap`},P={class:`login-page__field-icon`,"aria-hidden":`true`},F={class:`admin-form__field`},I={class:`login-page__input-wrap login-page__input-wrap--password`},L={class:`login-page__field-icon`,"aria-hidden":`true`},R=[`type`],z=[`aria-label`],B={class:`login-page__remember`},V=[`disabled`],H={key:0,class:`admin-btn__spinner`,"aria-hidden":`true`},U=d(s({__name:`LoginView`,setup(s){let d=C(),U=S(),W=x(),G=p(),K=r(y()?v.phone:``),q=r(y()?v.password:``),J=r(!0),Y=r(!1),X=y(),Z=u(()=>K.value.trim().length>0&&q.value.length>0);function Q(e){return e.replace(/[۰-۹]/g,e=>String(`۰۱۲۳۴۵۶۷۸۹`.indexOf(e))).replace(/[٠-٩]/g,e=>String(`٠١٢٣٤٥٦٧٨٩`.indexOf(e)))}async function $(){if(!Z.value){W.error=`لطفاً شماره موبایل و رمز عبور را وارد کنید.`;return}if(!await W.login(Q(K.value.trim()),q.value,J.value))return;G.success(`خوش آمدید، ${W.fullName}`);let e=typeof U.query.redirect==`string`?U.query.redirect:`/`,t=`/admin/`.replace(/\/$/,``),n=e.startsWith(t)?e.slice(t.length)||`/`:e;await d.replace(n)}return(r,s)=>(e(),o(`div`,w,[a(`div`,T,[a(`div`,E,[a(`div`,D,[s[8]||=a(`h2`,{class:`login-page__title`},`ورود به پنل مدیریت`,-1),s[9]||=a(`p`,{class:`login-page__subtitle`},`برای ادامه، اطلاعات حساب کاربری خود را وارد کنید.`,-1),i(X)?(e(),o(`p`,O,[s[6]||=l(` حالت موک فعال است — `,-1),a(`span`,k,t(i(v).phone),1),s[7]||=l(` / `,-1),a(`span`,A,t(i(v).password),1)])):f(``,!0)]),a(`form`,{class:`admin-form login-page__form`,onSubmit:g($,[`prevent`])},[i(W).error?(e(),o(`p`,j,t(i(W).error),1)):f(``,!0),a(`div`,M,[s[10]||=a(`label`,{for:`login-phone`},`شماره موبایل`,-1),a(`div`,N,[a(`span`,P,[c(b,{name:`phone`,size:18})]),n(a(`input`,{id:`login-phone`,"onUpdate:modelValue":s[0]||=e=>K.value=e,type:`tel`,class:`admin-input login-page__input`,placeholder:`۰۹۱۲۱۱۱۱۲۲۲۲`,autocomplete:`username`,inputmode:`tel`,dir:`ltr`,onInput:s[1]||=e=>i(W).clearError()},null,544),[[m,K.value]])])]),a(`div`,F,[s[11]||=a(`label`,{for:`login-password`},`رمز عبور`,-1),a(`div`,I,[a(`span`,L,[c(b,{name:`lock`,size:18})]),n(a(`input`,{id:`login-password`,"onUpdate:modelValue":s[2]||=e=>q.value=e,type:Y.value?`text`:`password`,class:`admin-input login-page__input login-page__input--with-toggle`,placeholder:`رمز عبور`,autocomplete:`current-password`,onInput:s[3]||=e=>i(W).clearError()},null,40,R),[[_,q.value]]),a(`button`,{type:`button`,class:`login-page__toggle-password`,"aria-label":Y.value?`پنهان کردن رمز`:`نمایش رمز`,onClick:s[4]||=e=>Y.value=!Y.value},[c(b,{name:Y.value?`eye-off`:`eye`,size:18},null,8,[`name`])],8,z)])]),a(`label`,B,[n(a(`input`,{"onUpdate:modelValue":s[5]||=e=>J.value=e,type:`checkbox`},null,512),[[h,J.value]]),s[12]||=a(`span`,null,`مرا به خاطر بسپار`,-1)]),a(`button`,{type:`submit`,class:`admin-btn admin-btn--primary login-page__submit`,disabled:!Z.value||i(W).loading},[i(W).loading?(e(),o(`span`,H)):f(``,!0),s[13]||=l(` ورود به پنل `,-1)],8,V)],32)])]),a(`div`,{class:`login-page__brand`},[a(`div`,{class:`login-page__brand-inner`},[a(`img`,{src:`/admin/brand-logo.png`,alt:`نادمی تکس`,class:`login-page__brand-logo`}),s[14]||=a(`p`,{class:`login-page__brand-badge`},`پارچه`,-1),s[15]||=a(`h1`,{class:`login-page__brand-title`},`پنل مدیریت سفارش‌های عمده`,-1),s[16]||=a(`p`,{class:`login-page__brand-text`},` مدیریت سفارش‌ها، مشتریان، قیمت‌گذاری، چک‌ها و گزارش‌های فروش در یک محیط یکپارچه. `,-1)])])]))}}),[[`__scopeId`,`data-v-df8d196a`]]);export{U as default};
-1
View File
@@ -1 +0,0 @@
import{B as e,N as t,O as n,c as r,d as i,h as a,m as o,t as s}from"./_plugin-vue_export-helper-OaxA6A2f.js";var c={},l={class:`not-found`};function u(s,c){let u=t(`RouterLink`);return n(),i(`main`,l,[c[1]||=r(`p`,{class:`not-found__code`},`404`,-1),c[2]||=r(`h1`,null,`صفحه پیدا نشد`,-1),c[3]||=r(`p`,null,`آدرسی که وارد کرده‌اید وجود ندارد.`,-1),a(u,{to:`/`},{default:e(()=>[...c[0]||=[o(`بازگشت به داشبورد`,-1)]]),_:1})])}var d=s(c,[[`render`,u],[`__scopeId`,`data-v-1c91077f`]]);export{d as default};
+1
View File
@@ -0,0 +1 @@
import{H as e,P as t,c as n,d as r,h as i,k as a,m as o,t as s}from"./_plugin-vue_export-helper-QrIvvHC8.js";var c={},l={class:`not-found`};function u(s,c){let u=t(`RouterLink`);return a(),r(`main`,l,[c[1]||=n(`p`,{class:`not-found__code`},`404`,-1),c[2]||=n(`h1`,null,`صفحه پیدا نشد`,-1),c[3]||=n(`p`,null,`آدرسی که وارد کرده‌اید وجود ندارد.`,-1),i(u,{to:`/`},{default:e(()=>[...c[0]||=[o(`بازگشت به داشبورد`,-1)]]),_:1})])}var d=s(c,[[`render`,u],[`__scopeId`,`data-v-1c91077f`]]);export{d as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
import{O as e,Ot as t,Tt as n,at as r,d as i,g as a,t as o}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{t as s}from"./orderStatus-CYVblRJB.js";var c=o(a({__name:`StatusBadge`,props:{status:{}},setup(a){let o={active:{label:`فعال`,tone:`success`},inactive:{label:`غیرفعال`,tone:`neutral`},pending_check_review:{label:`در انتظار بررسی`,tone:`warning`},check_approved:{label:`تأیید شده`,tone:`success`},check_rejected:{label:`رد شده`,tone:`danger`}};return(c,l)=>(e(),i(`span`,{class:n([`admin-badge status-badge`,`admin-badge--${(r(s)[a.status]??o[a.status])?.tone??`neutral`}`])},t((r(s)[a.status]??o[a.status])?.label??a.status),3))}}),[[`__scopeId`,`data-v-23aa055a`]]);export{c as t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Dt as t,d as n,g as r,k as i,st as a,t as o}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{t as s}from"./orderStatus-CeC05Cv4.js";var c=o(r({__name:`StatusBadge`,props:{status:{}},setup(r){let o={active:{label:`فعال`,tone:`success`},inactive:{label:`غیرفعال`,tone:`neutral`},pending_check_review:{label:`در انتظار بررسی`,tone:`warning`},check_approved:{label:`تأیید شده`,tone:`success`},check_rejected:{label:`رد شده`,tone:`danger`}};return(c,l)=>(i(),n(`span`,{class:t([`admin-badge status-badge`,`admin-badge--${(a(s)[r.status]??o[r.status])?.tone??`neutral`}`])},e((a(s)[r.status]??o[r.status])?.label??r.status),3))}}),[[`__scopeId`,`data-v-23aa055a`]]);export{c as t};
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,E as n,M as r,c as i,d as a,g as o,k as s,l as c,m as l,r as u,t as d}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as f,t as p}from"./http-BjLkjdQu.js";import{A as m}from"./index-pv0Ktkd1.js";import{t as h}from"./AdminPageSkeleton-oWhHYjl4.js";import{t as g}from"./BaseEmptyState-y-wpauXF.js";var _={class:`admin-page`},v={key:2,class:`admin-table`},y={class:`muted`,dir:`ltr`},b={class:`muted`,dir:`ltr`},x=[`onClick`],S=d(o({__name:`StockAlertsView`,setup(o){let d=e([]),S=e(!0),C=f();async function w(){S.value=!0;try{d.value=await m.list()}catch(e){C.error(e instanceof p?e.message:`بارگذاری ناموفق بود`)}finally{S.value=!1}}async function T(e){try{await m.notify(e),C.success(`اعلان موجودی ارسال شد`),await w()}catch(e){C.error(e instanceof p?e.message:`ارسال ناموفق بود`)}}return n(()=>{w()}),(e,n)=>(s(),a(`div`,_,[n[1]||=i(`header`,{class:`admin-page__head`},[i(`div`,null,[i(`h1`,null,`درخواست خبر موجودی`),i(`p`,null,`مشتریانی که برای محصول ناموجود درخواست اطلاع داده‌اند`)])],-1),S.value?(s(),c(h,{key:0,variant:`table`})):d.value.length?(s(),a(`table`,v,[n[0]||=i(`thead`,null,[i(`tr`,null,[i(`th`,null,`مشتری`),i(`th`,null,`محصول`),i(`th`,null,`موجودی فعلی`),i(`th`)])],-1),i(`tbody`,null,[(s(!0),a(u,null,r(d.value,e=>(s(),a(`tr`,{key:e.id},[i(`td`,null,[l(t(e.customerName)+` `,1),i(`span`,y,t(e.customerPhone),1)]),i(`td`,null,[l(t(e.productName)+` `,1),i(`span`,b,`(`+t(e.productCode)+`)`,1)]),i(`td`,null,t(e.stock??`—`),1),i(`td`,null,[i(`button`,{type:`button`,class:`admin-btn admin-btn--primary admin-btn--sm`,onClick:t=>T(e.id)},`ارسال اعلان`,8,x)])]))),128))])])):(s(),c(g,{key:1,title:`درخواستی فعال نیست`}))]))}}),[[`__scopeId`,`data-v-61131544`]]);export{S as default};
-1
View File
@@ -1 +0,0 @@
import{O as e,Ot as t,T as n,Z as r,c as i,d as a,g as o,j as s,l as c,m as l,r as u,t as d}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as f,t as p}from"./http-Djf2pGxE.js";import{A as m}from"./index-CznUUXv3.js";import{t as h}from"./AdminPageSkeleton-CTgUqaAu.js";import{t as g}from"./BaseEmptyState-D6sk-aI_.js";var _={class:`admin-page`},v={key:2,class:`admin-table`},y={class:`muted`,dir:`ltr`},b={class:`muted`,dir:`ltr`},x=[`onClick`],S=d(o({__name:`StockAlertsView`,setup(o){let d=r([]),S=r(!0),C=f();async function w(){S.value=!0;try{d.value=await m.list()}catch(e){C.error(e instanceof p?e.message:`بارگذاری ناموفق بود`)}finally{S.value=!1}}async function T(e){try{await m.notify(e),C.success(`اعلان موجودی ارسال شد`),await w()}catch(e){C.error(e instanceof p?e.message:`ارسال ناموفق بود`)}}return n(()=>{w()}),(n,r)=>(e(),a(`div`,_,[r[1]||=i(`header`,{class:`admin-page__head`},[i(`div`,null,[i(`h1`,null,`درخواست خبر موجودی`),i(`p`,null,`مشتریانی که برای محصول ناموجود درخواست اطلاع داده‌اند`)])],-1),S.value?(e(),c(h,{key:0,variant:`table`})):d.value.length?(e(),a(`table`,v,[r[0]||=i(`thead`,null,[i(`tr`,null,[i(`th`,null,`مشتری`),i(`th`,null,`محصول`),i(`th`,null,`موجودی فعلی`),i(`th`)])],-1),i(`tbody`,null,[(e(!0),a(u,null,s(d.value,n=>(e(),a(`tr`,{key:n.id},[i(`td`,null,[l(t(n.customerName)+` `,1),i(`span`,y,t(n.customerPhone),1)]),i(`td`,null,[l(t(n.productName)+` `,1),i(`span`,b,`(`+t(n.productCode)+`)`,1)]),i(`td`,null,t(n.stock??`—`),1),i(`td`,null,[i(`button`,{type:`button`,class:`admin-btn admin-btn--primary admin-btn--sm`,onClick:e=>T(n.id)},`ارسال اعلان`,8,x)])]))),128))])])):(e(),c(g,{key:1,title:`درخواستی فعال نیست`}))]))}}),[[`__scopeId`,`data-v-61131544`]]);export{S as default};
+1
View File
@@ -0,0 +1 @@
import{$ as e,At as t,E as n,H as r,M as i,U as a,Z as o,c as s,d as c,g as l,h as u,k as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-QrIvvHC8.js";import{a as _,f as v,t as y}from"./http-BjLkjdQu.js";import{T as b,V as x,j as S,y as C}from"./index-pv0Ktkd1.js";import{t as w}from"./AdminPageSkeleton-oWhHYjl4.js";import{t as T}from"./BaseEmptyState-y-wpauXF.js";import{t as E}from"./AdminSelect-DFH4VaRE.js";var D={class:`admin-page`},O={class:`admin-page__head`},k={key:2,class:`admin-table`},A={class:`muted`,dir:`ltr`},j=[`onClick`],M={class:`field`},N={class:`field`},P={class:`field`},F=[`disabled`],I=g(l({__name:`SuggestionsView`,setup(l){let g=e([]),I=e(!0),L=e([]),R=e([]),z=e(!1),B=_(),V=o({customerId:``,productId:``,note:``}),H=h(()=>L.value.map(e=>({value:e.id,label:e.name?.trim()||e.phone}))),U=h(()=>R.value.map(e=>({value:e.id,label:`${e.name} (${e.productCode})`})));async function W(){I.value=!0;try{let[e,t,n]=await Promise.all([S.list(),C.list(),b.list()]);g.value=e,L.value=t,R.value=n}catch(e){B.error(e instanceof y?e.message:`بارگذاری ناموفق بود`)}finally{I.value=!1}}async function G(){try{await S.create({customerId:V.customerId,productId:V.productId,note:V.note.trim()||void 0}),z.value=!1,V.note=``,B.success(`پیشنهاد ثبت شد`),await W()}catch(e){B.error(e instanceof y?e.message:`ثبت ناموفق بود`)}}async function K(e){try{await S.setActive(e.id,!e.isActive),await W()}catch(e){B.error(e instanceof y?e.message:`به‌روزرسانی ناموفق بود`)}}return n(()=>{W()}),(e,n)=>(d(),c(`div`,D,[s(`header`,O,[n[5]||=s(`div`,null,[s(`h1`,null,`پیشنهاد محصول`),s(`p`,null,`پیشنهاد دستی محصول به مشتری`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:n[0]||=e=>z.value=!0},`پیشنهاد جدید`)]),I.value?(d(),f(w,{key:0,variant:`table`})):g.value.length?(d(),c(`table`,k,[n[6]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`مشتری`),s(`th`,null,`محصول`),s(`th`,null,`یادداشت`),s(`th`,null,`وضعیت`),s(`th`)])],-1),s(`tbody`,null,[(d(!0),c(m,null,i(g.value,e=>(d(),c(`tr`,{key:e.id},[s(`td`,null,t(e.customerName),1),s(`td`,null,[p(t(e.productName)+` `,1),s(`span`,A,`(`+t(e.productCode)+`)`,1)]),s(`td`,null,t(e.note||`—`),1),s(`td`,null,t(e.isActive?`فعال`:`غیرفعال`),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>K(e)},t(e.isActive?`غیرفعال`:`فعال`),9,j)])]))),128))])])):(d(),f(T,{key:1,title:`پیشنهادی ثبت نشده`})),u(x,{open:z.value,title:`پیشنهاد محصول`,onClose:n[4]||=e=>z.value=!1},{footer:r(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!V.customerId||!V.productId,onClick:G},` ثبت `,8,F)]),default:r(()=>[s(`label`,M,[n[7]||=p(`مشتری `,-1),u(E,{modelValue:V.customerId,"onUpdate:modelValue":n[1]||=e=>V.customerId=e,options:H.value},null,8,[`modelValue`,`options`])]),s(`label`,N,[n[8]||=p(`محصول `,-1),u(E,{modelValue:V.productId,"onUpdate:modelValue":n[2]||=e=>V.productId=e,options:U.value},null,8,[`modelValue`,`options`])]),s(`label`,P,[n[9]||=p(`یادداشت`,-1),a(s(`textarea`,{"onUpdate:modelValue":n[3]||=e=>V.note=e,class:`admin-input`,rows:`3`},null,512),[[v,V.note]])])]),_:1},8,[`open`])]))}}),[[`__scopeId`,`data-v-56e3e728`]]);export{I as default};
-1
View File
@@ -1 +0,0 @@
import{B as e,O as t,Ot as n,T as r,V as i,Y as a,Z as o,c as s,d as c,g as l,h as u,j as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-OaxA6A2f.js";import{a as _,f as v,t as y}from"./http-Djf2pGxE.js";import{T as b,V as x,j as S,y as C}from"./index-CznUUXv3.js";import{t as w}from"./AdminPageSkeleton-CTgUqaAu.js";import{t as T}from"./BaseEmptyState-D6sk-aI_.js";import{t as E}from"./AdminSelect-DK-_otkw.js";var D={class:`admin-page`},O={class:`admin-page__head`},k={key:2,class:`admin-table`},A={class:`muted`,dir:`ltr`},j=[`onClick`],M={class:`field`},N={class:`field`},P={class:`field`},F=[`disabled`],I=g(l({__name:`SuggestionsView`,setup(l){let g=o([]),I=o(!0),L=o([]),R=o([]),z=o(!1),B=_(),V=a({customerId:``,productId:``,note:``}),H=h(()=>L.value.map(e=>({value:e.id,label:e.name?.trim()||e.phone}))),U=h(()=>R.value.map(e=>({value:e.id,label:`${e.name} (${e.productCode})`})));async function W(){I.value=!0;try{let[e,t,n]=await Promise.all([S.list(),C.list(),b.list()]);g.value=e,L.value=t,R.value=n}catch(e){B.error(e instanceof y?e.message:`بارگذاری ناموفق بود`)}finally{I.value=!1}}async function G(){try{await S.create({customerId:V.customerId,productId:V.productId,note:V.note.trim()||void 0}),z.value=!1,V.note=``,B.success(`پیشنهاد ثبت شد`),await W()}catch(e){B.error(e instanceof y?e.message:`ثبت ناموفق بود`)}}async function K(e){try{await S.setActive(e.id,!e.isActive),await W()}catch(e){B.error(e instanceof y?e.message:`به‌روزرسانی ناموفق بود`)}}return r(()=>{W()}),(r,a)=>(t(),c(`div`,D,[s(`header`,O,[a[5]||=s(`div`,null,[s(`h1`,null,`پیشنهاد محصول`),s(`p`,null,`پیشنهاد دستی محصول به مشتری`)],-1),s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:a[0]||=e=>z.value=!0},`پیشنهاد جدید`)]),I.value?(t(),f(w,{key:0,variant:`table`})):g.value.length?(t(),c(`table`,k,[a[6]||=s(`thead`,null,[s(`tr`,null,[s(`th`,null,`مشتری`),s(`th`,null,`محصول`),s(`th`,null,`یادداشت`),s(`th`,null,`وضعیت`),s(`th`)])],-1),s(`tbody`,null,[(t(!0),c(m,null,d(g.value,e=>(t(),c(`tr`,{key:e.id},[s(`td`,null,n(e.customerName),1),s(`td`,null,[p(n(e.productName)+` `,1),s(`span`,A,`(`+n(e.productCode)+`)`,1)]),s(`td`,null,n(e.note||`—`),1),s(`td`,null,n(e.isActive?`فعال`:`غیرفعال`),1),s(`td`,null,[s(`button`,{type:`button`,class:`link`,onClick:t=>K(e)},n(e.isActive?`غیرفعال`:`فعال`),9,j)])]))),128))])])):(t(),f(T,{key:1,title:`پیشنهادی ثبت نشده`})),u(x,{open:z.value,title:`پیشنهاد محصول`,onClose:a[4]||=e=>z.value=!1},{footer:e(()=>[s(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!V.customerId||!V.productId,onClick:G},` ثبت `,8,F)]),default:e(()=>[s(`label`,M,[a[7]||=p(`مشتری `,-1),u(E,{modelValue:V.customerId,"onUpdate:modelValue":a[1]||=e=>V.customerId=e,options:H.value},null,8,[`modelValue`,`options`])]),s(`label`,N,[a[8]||=p(`محصول `,-1),u(E,{modelValue:V.productId,"onUpdate:modelValue":a[2]||=e=>V.productId=e,options:U.value},null,8,[`modelValue`,`options`])]),s(`label`,P,[a[9]||=p(`یادداشت`,-1),i(s(`textarea`,{"onUpdate:modelValue":a[3]||=e=>V.note=e,class:`admin-input`,rows:`3`},null,512),[[v,V.note]])])]),_:1},8,[`open`])]))}}),[[`__scopeId`,`data-v-56e3e728`]]);export{I as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-382
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+382
View File
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
var e={pending_review:{label:`در انتظار بررسی`,tone:`warning`},awaiting_customer:{label:`در انتظار مشتری`,tone:`info`},pending_check:{label:`بررسی چک`,tone:`purple`},pending_payment:{label:`بررسی رسید پرداخت`,tone:`purple`},needs_correction:{label:`نیاز به اصلاح`,tone:`danger`},check_correction:{label:`نیاز به اصلاح چک`,tone:`warning`},final_approval:{label:`تأیید نهایی`,tone:`success`},shipped:{label:`ارسال شده`,tone:`info`},delivered:{label:`تحویل شده`,tone:`delivered`},cancelled:{label:`لغو شده`,tone:`neutral`},rejected:{label:`رد شده`,tone:`danger`},expired:{label:`منقضی شده`,tone:`neutral`}},t={cart:`سبد خرید`,submitted:`ثبت‌شده`,awaiting_review:`در انتظار بررسی`,pricing:`قیمت‌گذاری`,awaiting_settlement:`در انتظار تسویه`,awaiting_settlement_fix:`اصلاح تسویه`,cash_in_progress:`در حال ثبت نقدی`,cash_invoice_issued:`صدور فاکتور نقدی`,awaiting_cash_payment:`در انتظار پرداخت نقدی`,cash_payment_submitted:`رسید نقدی ارسال‌شده`,awaiting_cash_confirmation:`تأیید پرداخت نقدی`,cash_confirmed:`پرداخت نقدی تأیید شد`,check_in_progress:`در حال ثبت چک`,awaiting_check_review:`بررسی چک`,check_needs_fix:`اصلاح چک`,check_rejected:`رد چک`,checks_approved:`تأیید چک‌ها`,final_approved:`تأیید نهایی`,preparing:`آماده‌سازی`,ready_to_ship:`آماده ارسال`,shipped:`ارسال‌شده`,delivered:`تحویل‌شده`,needs_correction:`نیاز به اصلاح`,cancelled:`لغو شده`,rejected:`رد شده`,expired:`منقضی`};function n(e){return e?t[e]??e:`—`}var r=[`cart`,`submitted`,`awaiting_review`,`pricing`,`needs_correction`],i=[`pending_review`,`needs_correction`];function a(e){return e.rawStatus?r.includes(e.rawStatus):i.includes(e.status)}function o(e){return e.rawStatus===`checks_approved`||e.rawStatus===`cash_confirmed`}var s=[`final_approved`,`preparing`,`ready_to_ship`];function c(e){return!!e.rawStatus&&s.includes(e.rawStatus)}var l=[{key:`all`,label:`همه`},{key:`pending_review`,label:`در انتظار بررسی`},{key:`awaiting_customer`,label:`در انتظار مشتری`},{key:`pending_check`,label:`بررسی چک`},{key:`pending_payment`,label:`بررسی رسید`},{key:`check_correction`,label:`اصلاح چک`},{key:`needs_correction`,label:`نیاز به اصلاح`},{key:`final_approval`,label:`تأیید نهایی`},{key:`shipped`,label:`ارسال شده`},{key:`delivered`,label:`تحویل شده`}];export{c as a,n as c,t as i,l as n,o,r,a as s,e as t};
var e={pending_review:{label:`در انتظار بررسی`,tone:`warning`},awaiting_customer:{label:`در انتظار مشتری`,tone:`info`},pending_check:{label:`بررسی چک`,tone:`purple`},pending_payment:{label:`بررسی رسید پرداخت`,tone:`purple`},needs_correction:{label:`نیاز به اصلاح`,tone:`danger`},check_correction:{label:`نیاز به اصلاح چک`,tone:`warning`},final_approval:{label:`تأیید نهایی`,tone:`success`},shipped:{label:`ارسال شده`,tone:`info`},delivered:{label:`تحویل شده`,tone:`delivered`},cancelled:{label:`لغو شده`,tone:`neutral`},rejected:{label:`رد شده`,tone:`danger`},expired:{label:`منقضی شده`,tone:`neutral`}},t={cart:`سبد خرید`,submitted:`ثبت‌شده`,awaiting_review:`در انتظار بررسی`,pricing:`قیمت‌گذاری`,awaiting_settlement:`در انتظار تسویه`,awaiting_settlement_fix:`اصلاح تسویه`,cash_in_progress:`در حال ثبت نقدی`,cash_invoice_issued:`صدور فاکتور نقدی`,awaiting_cash_payment:`در انتظار پرداخت نقدی`,cash_payment_submitted:`رسید نقدی ارسال‌شده`,awaiting_cash_confirmation:`تأیید پرداخت نقدی`,cash_confirmed:`پرداخت نقدی تأیید شد`,check_in_progress:`در حال ثبت چک`,awaiting_check_review:`بررسی چک`,check_needs_fix:`اصلاح چک`,check_rejected:`رد چک`,checks_approved:`تأیید چک‌ها`,final_approved:`تأیید نهایی`,preparing:`آماده‌سازی`,ready_to_ship:`آماده ارسال`,shipped:`ارسال‌شده`,delivered:`تحویل‌شده`,needs_correction:`نیاز به اصلاح`,cancelled:`لغو شده`,rejected:`رد شده`,expired:`منقضی`};function n(e){return e?t[e]??e:`—`}var r=[`cart`,`submitted`,`awaiting_review`,`pricing`,`needs_correction`],i=[`pending_review`,`needs_correction`];function a(e){return e.rawStatus?r.includes(e.rawStatus):i.includes(e.status)}function o(e){return e.rawStatus===`checks_approved`||e.rawStatus===`cash_confirmed`}var s=[`final_approved`,`preparing`,`ready_to_ship`];function c(e){return!!e.rawStatus&&s.includes(e.rawStatus)}var l=[{key:`all`,label:`همه`},{key:`pending_review`,label:`در انتظار بررسی`},{key:`awaiting_customer`,label:`در انتظار مشتری`},{key:`pending_check`,label:`بررسی چک`},{key:`pending_payment`,label:`بررسی رسید`},{key:`check_correction`,label:`اصلاح چک`},{key:`needs_correction`,label:`نیاز به اصلاح`},{key:`final_approval`,label:`تأیید نهایی`},{key:`shipped`,label:`ارسال شده`},{key:`delivered`,label:`تحویل شده`}];export{o as a,c as i,l as n,a as o,r,n as s,e as t};
+4 -4
View File
@@ -11,10 +11,10 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>پنل مدیریت | پارچه</title>
<script type="module" crossorigin src="/admin/assets/index-CznUUXv3.js"></script>
<link rel="modulepreload" crossorigin href="/admin/assets/_plugin-vue_export-helper-OaxA6A2f.js">
<link rel="modulepreload" crossorigin href="/admin/assets/http-Djf2pGxE.js">
<link rel="stylesheet" crossorigin href="/admin/assets/index-BZ7aOp8K.css">
<script type="module" crossorigin src="/admin/assets/index-pv0Ktkd1.js"></script>
<link rel="modulepreload" crossorigin href="/admin/assets/_plugin-vue_export-helper-QrIvvHC8.js">
<link rel="modulepreload" crossorigin href="/admin/assets/http-BjLkjdQu.js">
<link rel="stylesheet" crossorigin href="/admin/assets/index-Ddm1RcgL.css">
</head>
<body>
<div id="app"></div>
+53
View File
@@ -0,0 +1,53 @@
<script setup lang="ts">
defineProps<{
src: string
alt?: string
}>()
const open = defineModel<boolean>({ required: true })
</script>
<template>
<Teleport to="body">
<div v-if="open" class="admin-image-lightbox" @click.self="open = false">
<button type="button" class="admin-image-lightbox__close" @click="open = false">
بستن
</button>
<img :src="src" :alt="alt ?? 'پیش‌نمایش تصویر'" />
</div>
</Teleport>
</template>
<style scoped>
.admin-image-lightbox {
position: fixed;
inset: 0;
z-index: 300000;
display: grid;
place-items: center;
background: rgba(0, 0, 0, 0.84);
padding: 20px;
}
.admin-image-lightbox img {
max-width: min(900px, 100%);
max-height: 88vh;
object-fit: contain;
border-radius: 8px;
}
.admin-image-lightbox__close {
position: absolute;
top: 14px;
inset-inline-end: 14px;
border: 0;
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
background: var(--color-surface);
color: var(--color-text);
font: inherit;
font-size: 0.875rem;
font-weight: 600;
}
</style>
+10 -5
View File
@@ -170,9 +170,18 @@ export function useOrdersPage() {
}
}
function openOrderDetail(order: Order) {
async function openOrderDetail(order: Order) {
selectedOrderId.value = order.id
showDetailModal.value = true
try {
const fresh = mapAdminOrder(await ordersApi.get(order.id)) as Order
const index = orderList.value.findIndex((o) => o.id === order.id)
if (index >= 0) {
orderList.value[index] = { ...orderList.value[index]!, ...fresh }
}
} catch {
/* جزئیات از لیست همان لحظه نمایش داده می‌شود */
}
}
function closeDetailPanel() {
@@ -194,8 +203,6 @@ export function useOrdersPage() {
orderId: string
status: RawOrderStatus
note?: string
reason?: string
force?: boolean
}) {
if (statusSaving.value) return null
statusSaving.value = true
@@ -203,8 +210,6 @@ export function useOrdersPage() {
const updated = await ordersApi.updateStatus(payload.orderId, {
status: payload.status,
note: payload.note,
reason: payload.reason,
force: payload.force,
})
const mapped = mapAdminOrder(updated) as Order
const index = orderList.value.findIndex((o) => o.id === payload.orderId)
+2 -4
View File
@@ -11,6 +11,7 @@ import type {
Customer,
InternalMessage,
Order,
OrderCashReceipt,
OrderItem,
OrderStatus,
OrderStatusHistoryItem,
@@ -271,15 +272,12 @@ export type ApiOrder = Order & {
statusHistory?: OrderStatusHistoryItem[]
/** وضعیت‌های مجاز بعدی از دید ماشین وضعیت سرور */
allowedTransitions?: string[]
cashReceipt?: { id: string } | null
cashReceipt?: OrderCashReceipt | null
}
export type UpdateOrderStatusPayload = {
status: string
note?: string
reason?: string
/** گذر خارج از ماشین وضعیت؛ سرور reason را اجباری می‌کند */
force?: boolean
}
export const ordersApi = {
+21 -2
View File
@@ -81,6 +81,22 @@ export interface OrderItem {
companyName?: string
}
export type CashPaymentStatus = 'pending_review' | 'approved' | 'rejected' | 'expired'
export interface OrderCashReceipt {
id: string
amount: number
paidAmount?: number | null
transferDate?: string | null
transferTime?: string
trackingNumber?: string
trackingCode?: string
receiptImage?: string
notes?: string
status: CashPaymentStatus
submittedAt?: string
}
export interface Order {
id: string
orderNumber: string
@@ -98,6 +114,7 @@ export interface Order {
customerNationalId?: string
customerType?: string
items?: OrderItem[]
cashReceipt?: OrderCashReceipt | null
}
export interface Check {
@@ -222,6 +239,7 @@ export interface Product {
productCode: string
minMeterage: number
orderStep: number
orderMultiplier?: number
price: number | null
internalStock: number
isActive: boolean
@@ -237,8 +255,6 @@ export interface Product {
imageUrls?: string[]
}
export type CashPaymentStatus = 'pending_review' | 'approved' | 'rejected' | 'expired'
export interface CashPayment {
id: string
orderId: string
@@ -247,7 +263,10 @@ export interface CashPayment {
amount: number
paidAmount: number | null
transferDate: string | null
transferTime?: string
trackingCode: string
receiptImage?: string
notes?: string
expiresAt: string
status: CashPaymentStatus
}
+49
View File
@@ -0,0 +1,49 @@
import type { Product } from '@/types'
export type QuantityMode = 'meter' | 'roll'
export function rollMetersForProduct(product: Product): number {
if (product.rollMeters && product.rollMeters > 0) return product.rollMeters
if (product.minMeterage > 0) return product.minMeterage
return 50
}
export function orderMultiplierForProduct(product: Product): number {
const step = product.orderMultiplier ?? product.orderStep
return step && step > 0 ? step : 10
}
export function meterageFromQuantity(product: Product, mode: QuantityMode, value: number): number {
if (mode === 'roll') return value * rollMetersForProduct(product)
return value
}
export function rollsFromMeterage(product: Product, meterage: number): number {
const rollMeters = rollMetersForProduct(product)
return rollMeters > 0 ? meterage / rollMeters : 0
}
/** همان قواعد سرور هنگام ثبت سفارش */
export function validateOrderMeterage(
product: Product,
meterage: number,
minRollsSetting = 1,
): string | null {
if (!meterage || meterage <= 0) {
return 'مقدار باید بزرگ‌تر از صفر باشد.'
}
if (meterage < product.minMeterage) {
return `حداقل متراژ برای ${product.name} برابر ${product.minMeterage} است`
}
const multiplier = orderMultiplierForProduct(product)
const rem = Math.round((meterage / multiplier) * 1000) / 1000
if (Math.abs(rem - Math.round(rem)) > 1e-6) {
return `متراژ ${product.name} باید مضرب ${multiplier} باشد`
}
const rollMeters = rollMetersForProduct(product)
const minRolls = minRollsSetting > 0 ? minRollsSetting : 1
if (meterage / rollMeters + 1e-9 < minRolls) {
return `حداقل سفارش برای ${product.name} برابر ${minRolls} طاقه است`
}
return null
}
@@ -4,6 +4,7 @@ import { useRoute } from 'vue-router'
import AdminIcon from '@/components/icons/AdminIcon.vue'
import AdminPageSkeleton from '@/components/ui/AdminPageSkeleton.vue'
import AdminSelect from '@/components/ui/AdminSelect.vue'
import AdminImageLightbox from '@/components/ui/AdminImageLightbox.vue'
import { cashPaymentsApi, ordersApi } from '@/services/api'
import { ApiError } from '@/services/http'
import {
@@ -21,6 +22,13 @@ const statusFilter = ref<'all' | CashPayment['status']>('all')
const loading = ref(true)
const toast = useToast()
const busyId = ref<string | null>(null)
const receiptPreviewOpen = ref(false)
const receiptPreviewSrc = ref('')
function openReceiptPreview(src: string) {
receiptPreviewSrc.value = src
receiptPreviewOpen.value = true
}
const statusFilterOptions = [
{ value: 'all', label: 'همه وضعیت‌ها' },
@@ -144,6 +152,7 @@ async function rejectPayment(payment: CashPayment) {
<th>شماره پیگیری</th>
<th>پایان اعتبار</th>
<th>وضعیت</th>
<th>رسید</th>
<th>عملیات</th>
</tr>
</thead>
@@ -161,6 +170,17 @@ async function rejectPayment(payment: CashPayment) {
{{ CASH_PAYMENT_STATUS_LABELS[payment.status] }}
</span>
</td>
<td>
<button
v-if="payment.receiptImage"
type="button"
class="admin-btn admin-btn--outline admin-btn--xs"
@click="openReceiptPreview(payment.receiptImage!)"
>
مشاهده
</button>
<span v-else>—</span>
</td>
<td>
<div v-if="payment.status === 'pending_review'" class="admin-action-group">
<button
@@ -212,6 +232,14 @@ async function rejectPayment(payment: CashPayment) {
<span v-if="payment.paidAmount != null">پرداختی: {{ formatCurrency(payment.paidAmount) }}</span>
<span dir="ltr">{{ payment.trackingCode }}</span>
</div>
<button
v-if="payment.receiptImage"
type="button"
class="admin-btn admin-btn--outline admin-btn--xs cash-payments-page__receipt-btn"
@click="openReceiptPreview(payment.receiptImage!)"
>
مشاهده تصویر رسید
</button>
<div
v-if="payment.status === 'pending_review' || payment.status === 'approved'"
class="admin-card-item__actions"
@@ -247,6 +275,13 @@ async function rejectPayment(payment: CashPayment) {
</article>
</div>
</template>
<AdminImageLightbox
v-if="receiptPreviewSrc"
v-model="receiptPreviewOpen"
:src="receiptPreviewSrc"
alt="تصویر رسید پرداخت"
/>
</div>
</template>
+145 -19
View File
@@ -3,10 +3,17 @@ import { computed, reactive, ref, watch } from 'vue'
import BaseModal from '@/components/ui/BaseModal.vue'
import AdminSelect from '@/components/ui/AdminSelect.vue'
import { useOrdersPageContext } from '@/composables/useOrdersPage'
import { productsApi } from '@/services/api'
import { productsApi, settingsApi } from '@/services/api'
import { ApiError } from '@/services/http'
import { useToast } from '@/composables/useToast'
import { formatNumber } from '@/utils/format'
import {
meterageFromQuantity,
rollMetersForProduct,
rollsFromMeterage,
validateOrderMeterage,
type QuantityMode,
} from '@/utils/orderItemValidation'
import type { Product } from '@/types'
const {
@@ -24,9 +31,11 @@ const {
const toast = useToast()
const products = ref<Product[]>([])
const minOrderRolls = ref(1)
const draft = reactive({
productId: '',
meterage: 0,
quantityMode: 'roll' as QuantityMode,
quantity: 0,
})
const customerOptions = computed(() =>
@@ -53,6 +62,10 @@ const selectedProduct = computed(() =>
products.value.find((product) => product.id === draft.productId) ?? null,
)
const quantityLabel = computed(() =>
draft.quantityMode === 'roll' ? 'تعداد طاقه' : 'متراژ (متر)',
)
watch(
() => form.customerId,
(id) => {
@@ -65,44 +78,85 @@ watch(
},
)
function defaultQuantity(product: Product, mode: QuantityMode) {
const minRolls = minOrderRolls.value > 0 ? minOrderRolls.value : 1
if (mode === 'roll') return minRolls
const rollMeters = rollMetersForProduct(product)
return Math.max(product.minMeterage || 0, minRolls * rollMeters)
}
watch(showAddModal, async (open) => {
if (!open) return
draft.productId = ''
draft.meterage = 0
draft.quantityMode = 'roll'
draft.quantity = 0
formError.value = ''
try {
products.value = await productsApi.list({ activeOnly: true })
const [list, settings] = await Promise.all([
productsApi.list({ activeOnly: true }),
settingsApi.get().catch(() => null),
])
products.value = list
minOrderRolls.value = settings?.minOrderRollsPerProduct ?? 1
} catch (err) {
toast.error(err instanceof ApiError ? err.message : 'بارگذاری محصولات انجام نشد.')
}
})
watch(
() => draft.productId,
(id) => {
() => [draft.productId, draft.quantityMode] as const,
([id, mode]) => {
const product = products.value.find((item) => item.id === id)
if (!product) return
draft.meterage = product.rollMeters || product.minMeterage || product.orderStep || 50
draft.quantity = defaultQuantity(product, mode)
},
)
function addDraftProduct() {
formError.value = ''
const product = selectedProduct.value
if (!product) {
formError.value = 'محصول را انتخاب کنید.'
toast.error(formError.value)
return
}
if (!draft.meterage || draft.meterage <= 0) {
formError.value = 'متراژ باید بزرگ‌تر از صفر باشد.'
if (!draft.quantity || draft.quantity <= 0) {
formError.value = 'مقدار باید بزرگ‌تر از صفر باشد.'
toast.error(formError.value)
return
}
addFormItem({
const meterage = meterageFromQuantity(product, draft.quantityMode, draft.quantity)
const validationError = validateOrderMeterage(product, meterage, minOrderRolls.value)
if (validationError) {
formError.value = validationError
toast.error(validationError)
return
}
const added = addFormItem({
productId: product.id,
productName: product.name,
catalogCode: product.catalogCode,
meterage: draft.meterage,
meterage,
})
if (!added) {
toast.error(formError.value || 'افزودن محصول انجام نشد.')
return
}
draft.productId = ''
draft.meterage = 0
draft.quantityMode = 'roll'
draft.quantity = 0
}
function itemRollsLabel(item: { productId: string; meterage: number }) {
const product = products.value.find((p) => p.id === item.productId)
if (!product) return null
const rolls = rollsFromMeterage(product, item.meterage)
if (!Number.isFinite(rolls)) return null
const rounded = Math.round(rolls * 100) / 100
return rounded % 1 === 0 ? formatNumber(rounded) : formatNumber(rounded)
}
</script>
@@ -133,7 +187,6 @@ function addDraftProduct() {
</p>
</div>
<div class="admin-form__row">
<div class="admin-form__field">
<label>محصول</label>
<AdminSelect
@@ -146,13 +199,37 @@ function addDraftProduct() {
:options="productOptions"
/>
</div>
<div class="admin-form__row order-add__qty-row">
<div class="admin-form__field">
<label for="order-item-meterage">متراژ (متر)</label>
<span class="admin-form__label">واحد سفارش</span>
<div class="order-add__mode" role="group" aria-label="واحد سفارش">
<button
type="button"
class="order-add__mode-btn"
:class="{ 'order-add__mode-btn--active': draft.quantityMode === 'roll' }"
@click="draft.quantityMode = 'roll'"
>
طاقه
</button>
<button
type="button"
class="order-add__mode-btn"
:class="{ 'order-add__mode-btn--active': draft.quantityMode === 'meter' }"
@click="draft.quantityMode = 'meter'"
>
متراژ
</button>
</div>
</div>
<div class="admin-form__field">
<label for="order-item-quantity">{{ quantityLabel }}</label>
<input
id="order-item-meterage"
v-model.number="draft.meterage"
id="order-item-quantity"
v-model.number="draft.quantity"
type="number"
min="1"
min="0"
step="any"
class="admin-input"
/>
</div>
@@ -166,9 +243,19 @@ function addDraftProduct() {
<div v-for="item in form.items" :key="item.productId" class="order-add__item">
<div>
<strong>{{ item.productName }}</strong>
<span>کالیته {{ item.catalogCode }} — {{ formatNumber(item.meterage) }} متر</span>
<span>
کالیته {{ item.catalogCode }} —
{{ formatNumber(item.meterage) }} متر
<template v-if="itemRollsLabel(item)">
({{ itemRollsLabel(item) }} طاقه)
</template>
</span>
</div>
<button type="button" class="admin-btn admin-btn--outline-danger admin-btn--xs" @click="removeFormItem(item.productId)">
<button
type="button"
class="admin-btn admin-btn--outline-danger admin-btn--xs"
@click="removeFormItem(item.productId)"
>
حذف
</button>
</div>
@@ -199,6 +286,45 @@ function addDraftProduct() {
color: var(--color-text-muted);
}
.admin-form__label {
display: block;
margin-bottom: 6px;
font-size: 0.8125rem;
font-weight: 600;
}
.order-add__qty-row {
align-items: end;
}
.order-add__mode {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.order-add__mode-btn {
height: var(--control-height, 40px);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-surface);
color: var(--color-text-muted);
font: inherit;
font-size: 0.8125rem;
font-weight: 600;
cursor: pointer;
transition:
border-color 0.15s,
background 0.15s,
color 0.15s;
}
.order-add__mode-btn--active {
border-color: var(--color-primary);
background: var(--color-primary-soft, rgba(var(--color-primary-rgb), 0.08));
color: var(--color-primary);
}
.order-add__items {
display: flex;
flex-direction: column;
@@ -3,9 +3,10 @@ import { computed, ref, watch } from 'vue'
import AdminIcon from '@/components/icons/AdminIcon.vue'
import AdminSelect from '@/components/ui/AdminSelect.vue'
import StatusBadge from '@/components/ui/StatusBadge.vue'
import { formatCurrency, formatMeterage, formatNumber } from '@/utils/format'
import { CUSTOMER_TYPE_LABELS } from '@/utils/adminLabels'
import { ORDER_STATUS_META, RAW_ORDER_STATUS_LABELS, canFinalApproveOrder, canPriceOrder, rawStatusLabel } from '@/utils/orderStatus'
import { formatCurrency, formatDateTime, formatMeterage, formatNumber } from '@/utils/format'
import { CASH_PAYMENT_STATUS_LABELS, CUSTOMER_TYPE_LABELS } from '@/utils/adminLabels'
import AdminImageLightbox from '@/components/ui/AdminImageLightbox.vue'
import { ORDER_STATUS_META, canFinalApproveOrder, canPriceOrder, rawStatusLabel } from '@/utils/orderStatus'
import type { CustomerType, Order, RawOrderStatus } from '@/types'
const props = withDefaults(
@@ -28,25 +29,19 @@ const emit = defineEmits<{
orderId: string
status: RawOrderStatus
note?: string
reason?: string
force?: boolean
},
]
}>()
const manualMode = ref(false)
const nextStatus = ref<RawOrderStatus | ''>('')
const statusNote = ref('')
const receiptPreviewOpen = ref(false)
const allStatuses = Object.keys(RAW_ORDER_STATUS_LABELS) as RawOrderStatus[]
const cashReceipt = computed(() => props.order.cashReceipt ?? null)
const transitions = computed(() => props.order.allowedTransitions ?? [])
const statusOptions = computed<RawOrderStatus[]>(() =>
manualMode.value
? allStatuses.filter((s) => s !== props.order.rawStatus)
: [...transitions.value],
)
const statusOptions = computed<RawOrderStatus[]>(() => [...transitions.value])
const statusSelectOptions = computed(() => [
{ value: '', label: 'انتخاب کنید…' },
@@ -56,10 +51,7 @@ const statusSelectOptions = computed(() => [
})),
])
const noteRequired = computed(() => manualMode.value)
const canSubmitStatus = computed(
() => !!nextStatus.value && (!noteRequired.value || statusNote.value.trim().length > 0),
)
const canSubmitStatus = computed(() => !!nextStatus.value)
const useTable = computed(() => props.layout === 'desktop')
@@ -100,10 +92,13 @@ const primaryAction = computed<'pricing' | 'final' | 'checks' | 'cash' | null>((
return null
})
watch([() => props.order.id, manualMode], () => {
watch(
() => props.order.id,
() => {
nextStatus.value = ''
statusNote.value = ''
})
},
)
function submitStatus() {
if (!nextStatus.value || !canSubmitStatus.value) return
@@ -112,12 +107,18 @@ function submitStatus() {
orderId: props.order.id,
status: nextStatus.value,
note,
reason: manualMode.value ? note : undefined,
force: manualMode.value || undefined,
})
nextStatus.value = ''
statusNote.value = ''
}
function onCashReceiptAction() {
if (cashReceipt.value?.receiptImage) {
receiptPreviewOpen.value = true
return
}
emit('cashReceipt')
}
</script>
<template>
@@ -157,9 +158,9 @@ function submitStatus() {
type="button"
class="admin-btn admin-btn--sm"
:class="primaryAction === 'cash' ? 'admin-btn--primary' : 'admin-btn--outline'"
@click="emit('cashReceipt')"
@click="onCashReceiptAction"
>
رسید پرداخت
{{ cashReceipt?.receiptImage ? 'مشاهده رسید' : 'رسید پرداخت' }}
</button>
<button
v-if="showFinalApprove"
@@ -275,20 +276,75 @@ function submitStatus() {
</ul>
</section>
<section class="order-detail__section order-detail__status no-print">
<div class="order-detail__status-head">
<h3 class="order-detail__section-title">تغییر وضعیت</h3>
<label class="order-detail__manual">
<input v-model="manualMode" type="checkbox" />
<span>تغییر دستی</span>
</label>
<section v-if="cashReceipt" class="order-detail__section">
<h3 class="order-detail__section-title">رسید پرداخت نقدی</h3>
<div class="order-detail__info">
<div class="order-detail__info-row">
<span class="order-detail__info-label">وضعیت</span>
<span class="order-detail__info-value">
{{ CASH_PAYMENT_STATUS_LABELS[cashReceipt.status] }}
</span>
</div>
<div class="order-detail__info-row">
<span class="order-detail__info-label">مبلغ واریزی</span>
<span class="order-detail__info-value">
{{
cashReceipt.paidAmount != null
? formatCurrency(cashReceipt.paidAmount)
: formatCurrency(cashReceipt.amount)
}}
</span>
</div>
<div v-if="cashReceipt.transferDate" class="order-detail__info-row">
<span class="order-detail__info-label">تاریخ واریز</span>
<span class="order-detail__info-value">
{{ formatDateTime(cashReceipt.transferDate) }}
<template v-if="cashReceipt.transferTime"> · {{ cashReceipt.transferTime }}</template>
</span>
</div>
<div v-if="cashReceipt.trackingNumber || cashReceipt.trackingCode" class="order-detail__info-row">
<span class="order-detail__info-label">پیگیری</span>
<span class="order-detail__info-value" dir="ltr">
{{ cashReceipt.trackingNumber || cashReceipt.trackingCode }}
</span>
</div>
<div v-if="cashReceipt.notes" class="order-detail__info-row">
<span class="order-detail__info-label">یادداشت</span>
<span class="order-detail__info-value">{{ cashReceipt.notes }}</span>
</div>
</div>
<p v-if="manualMode" class="order-detail__status-hint">
این گذر خارج از روال استاندارد است؛ ثبت یادداشت اجباری است.
</p>
<p v-else-if="!statusOptions.length" class="order-detail__status-hint">
در این وضعیت گذر خودکاری وجود ندارد. برای تغییر، حالت دستی را فعال کنید.
<div v-if="cashReceipt.receiptImage" class="order-detail__receipt">
<button
type="button"
class="order-detail__receipt-thumb"
@click="receiptPreviewOpen = true"
>
<img :src="cashReceipt.receiptImage" alt="تصویر رسید پرداخت" />
</button>
<button
type="button"
class="admin-btn admin-btn--outline admin-btn--sm"
@click="receiptPreviewOpen = true"
>
مشاهده تصویر رسید
</button>
</div>
<p v-else class="order-detail__status-hint">تصویر رسید هنوز آپلود نشده است.</p>
</section>
<AdminImageLightbox
v-if="cashReceipt?.receiptImage"
v-model="receiptPreviewOpen"
:src="cashReceipt.receiptImage"
alt="تصویر رسید پرداخت"
/>
<section class="order-detail__section order-detail__status no-print">
<h3 class="order-detail__section-title">تغییر وضعیت</h3>
<p v-if="!statusOptions.length" class="order-detail__status-hint">
در این مرحله گذر مجازی از این بخش نیست؛ از اقدام‌های مرحله‌ای بالا (قیمت‌گذاری، چک، رسید نقدی و …) استفاده کنید.
</p>
<div v-if="statusOptions.length" class="order-detail__status-form">
@@ -304,9 +360,7 @@ function submitStatus() {
</div>
<div class="admin-form__field">
<label for="status-note">
یادداشت{{ noteRequired ? ' (اجباری)' : ' (اختیاری)' }}
</label>
<label for="status-note">یادداشت (اختیاری)</label>
<input
id="status-note"
v-model="statusNote"
@@ -477,31 +531,33 @@ function submitStatus() {
color: var(--color-text);
}
.order-detail__status-head {
.order-detail__receipt {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 8px;
margin-top: 12px;
}
.order-detail__status-head .order-detail__section-title {
margin: 0;
}
.order-detail__manual {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.8125rem;
color: var(--color-text-muted);
.order-detail__receipt-thumb {
padding: 0;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--color-bg);
cursor: pointer;
overflow: hidden;
line-height: 0;
}
.order-detail__manual input {
width: 15px;
height: 15px;
accent-color: var(--color-primary);
.order-detail__receipt-thumb img {
display: block;
width: 120px;
height: 120px;
object-fit: cover;
}
.order-detail__status .order-detail__section-title {
margin: 0 0 8px;
}
.order-detail__status-hint {