changes 1
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
import{A as e,ct as t,et as n,g as r,l as i}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a}from"./http-CTjL79ty.js";import{B as o}from"./index-DWlOII4H.js";import{t as s}from"./BaseSwitch-Dz4ODUhf.js";function c(e=480){return new Promise(t=>{window.setTimeout(t,e)})}function l(e){let t=n(null),r=n(null),i=a();async function o(n,a){if(t.value)return a;let o=!a;if(!o&&e.confirmOff&&!await e.confirmOff())return a;t.value=n,r.value=null;let s=a;try{return await e.onPersist(o),i.success(e.successMessage?.(o)??(o?`وضعیت فعال شد.`:`وضعیت غیرفعال شد.`)),o}catch{return r.value=n,i.error(e.errorMessage??`بهروزرسانی وضعیت انجام نشد.`),s}finally{t.value=null}}function s(e){return t.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(n,{emit:r}){let a=n,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":n.modelValue,loading:t(f)(n.id),error:t(p)(n.id),"onUpdate:modelValue":m},null,8,[`model-value`,`loading`,`error`]))}});export{u as t};
|
||||
import{A as e,ct as t,et as n,g as r,l as i}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a}from"./http-CTjL79ty.js";import{B as o}from"./index-BWgYBNME.js";import{t as s}from"./BaseSwitch-Dz4ODUhf.js";function c(e=480){return new Promise(t=>{window.setTimeout(t,e)})}function l(e){let t=n(null),r=n(null),i=a();async function o(n,a){if(t.value)return a;let o=!a;if(!o&&e.confirmOff&&!await e.confirmOff())return a;t.value=n,r.value=null;let s=a;try{return await e.onPersist(o),i.success(e.successMessage?.(o)??(o?`وضعیت فعال شد.`:`وضعیت غیرفعال شد.`)),o}catch{return r.value=n,i.error(e.errorMessage??`بهروزرسانی وضعیت انجام نشد.`),s}finally{t.value=null}}function s(e){return t.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(n,{emit:r}){let a=n,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":n.modelValue,loading:t(f)(n.id),error:t(p)(n.id),"onUpdate:modelValue":m},null,8,[`model-value`,`loading`,`error`]))}});export{u as t};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{A as e,Ot as t,d as n,g as r,s as i,t as a}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{c as o,r as s}from"./index-DWlOII4H.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};
|
||||
import{A as e,Ot as t,d as n,g as r,s as i,t as a}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{c as o,r as s}from"./index-BWgYBNME.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 +1 @@
|
||||
import{A as e,At as t,N as n,O as r,Ot as i,P as a,V as o,W as s,a as c,c as l,d as u,et as d,g as f,h as p,jt as m,l as h,r as g,s as _,t as v,u as y,w as b}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{d as x,m as S,p as C}from"./http-CTjL79ty.js";import{L as w,M as T}from"./index-DWlOII4H.js";import{n as E,r as D,t as O}from"./selectOptionSearch-BUIO0UgP.js";var k=[`id`],A=[`aria-label`,`aria-expanded`],j={class:`admin-select__trigger-content`},ee={class:`admin-select__value`},te={class:`admin-select__chevron`,"aria-hidden":`true`},M=[`aria-label`],N={key:0,class:`admin-select__search`,role:`presentation`},P=[`placeholder`],F={key:1,class:`admin-select__empty`,role:`presentation`},I=[`aria-selected`,`onClick`,`onKeydown`],L={class:`admin-select__option-label`},R=v(f({__name:`AdminSelect`,props:{modelValue:{},options:{},placeholder:{default:`انتخاب کنید`},ariaLabel:{default:`انتخاب`},block:{type:Boolean,default:!1},searchable:{type:Boolean,default:!0},searchPlaceholder:{default:`جستجو…`},id:{default:void 0}},emits:[`update:modelValue`],setup(f,{emit:v}){let R=f,z=v,B=d(!1),V=d(``),H=d(null),U=d(null),W=d(null),G=d({});T(H,()=>{B.value=!1,V.value=``},{ignore:[U]});let K=_(()=>R.options.find(e=>e.value===R.modelValue)),q=_(()=>K.value?.label??R.placeholder),J=_(()=>O(R.options,V.value));function Y(e){e.key===`ArrowDown`?(e.preventDefault(),D(U.value,`first`)):e.key===`ArrowUp`&&(e.preventDefault(),D(U.value,`last`))}function X(e,t){let n=e.currentTarget;e.key===`ArrowDown`?(e.preventDefault(),E(n,1)):e.key===`ArrowUp`?(e.preventDefault(),E(n,-1)):(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),$(t))}function Z(){let e=H.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));G.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 Q(e){e?(window.addEventListener(`resize`,Z),window.addEventListener(`scroll`,Z,!0)):(window.removeEventListener(`resize`,Z),window.removeEventListener(`scroll`,Z,!0))}async function ne(){B.value=!B.value,B.value&&(V.value=``,await b(),Z(),R.searchable&&(await b(),W.value?.focus()))}function $(e){z(`update:modelValue`,e),B.value=!1,V.value=``}return o(B,e=>{Q(e),e&&b(()=>Z())}),r(()=>{Q(!1)}),(r,o)=>(e(),u(`div`,{id:f.id,ref_key:`rootRef`,ref:H,class:i([`admin-select`,{"admin-select--open":B.value,"admin-select--block":f.block}])},[l(`button`,{type:`button`,class:`admin-select__trigger`,"aria-label":f.ariaLabel,"aria-expanded":B.value,"aria-haspopup":`listbox`,onClick:ne},[l(`span`,j,[a(r.$slots,`option-leading`,{option:K.value},void 0,!0),l(`span`,ee,m(q.value),1)]),l(`span`,te,[p(w,{name:`chevron-down`,size:16})])],8,A),(e(),h(c,{to:`body`},[B.value?(e(),u(`ul`,{key:0,ref_key:`menuRef`,ref:U,class:`admin-select__menu`,"data-select-menu":``,role:`listbox`,"aria-label":f.ariaLabel,style:t(G.value)},[f.searchable?(e(),u(`li`,N,[s(l(`input`,{ref_key:`searchInputRef`,ref:W,"onUpdate:modelValue":o[0]||=e=>V.value=e,type:`search`,class:`admin-select__search-input`,placeholder:f.searchPlaceholder,onClick:o[1]||=S(()=>{},[`stop`]),onKeydown:[o[2]||=C(S(e=>B.value=!1,[`stop`]),[`esc`]),Y]},null,40,P),[[x,V.value]])])):y(``,!0),J.value.length?y(``,!0):(e(),u(`li`,F,` موردی یافت نشد `)),(e(!0),u(g,null,n(J.value,t=>(e(),u(`li`,{key:t.value,role:`presentation`},[l(`button`,{type:`button`,class:i([`admin-select__option`,{"admin-select__option--active":t.value===f.modelValue}]),"data-select-option":``,role:`option`,"aria-selected":t.value===f.modelValue,onClick:e=>$(t.value),onKeydown:e=>X(e,t.value)},[l(`span`,L,[a(r.$slots,`option-leading`,{option:t},void 0,!0),l(`span`,null,m(t.label),1)]),t.value===f.modelValue?(e(),h(w,{key:0,name:`check`,size:16,class:`admin-select__check`})):y(``,!0)],42,I)]))),128))],12,M)):y(``,!0)]))],10,k))}}),[[`__scopeId`,`data-v-4ee349a1`]]);export{R as t};
|
||||
import{A as e,At as t,N as n,O as r,Ot as i,P as a,V as o,W as s,a as c,c as l,d as u,et as d,g as f,h as p,jt as m,l as h,r as g,s as _,t as v,u as y,w as b}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{d as x,m as S,p as C}from"./http-CTjL79ty.js";import{L as w,M as T}from"./index-BWgYBNME.js";import{n as E,r as D,t as O}from"./selectOptionSearch-DNMc9NzZ.js";var k=[`id`],A=[`aria-label`,`aria-expanded`],j={class:`admin-select__trigger-content`},ee={class:`admin-select__value`},te={class:`admin-select__chevron`,"aria-hidden":`true`},M=[`aria-label`],N={key:0,class:`admin-select__search`,role:`presentation`},P=[`placeholder`],F={key:1,class:`admin-select__empty`,role:`presentation`},I=[`aria-selected`,`onClick`,`onKeydown`],L={class:`admin-select__option-label`},R=v(f({__name:`AdminSelect`,props:{modelValue:{},options:{},placeholder:{default:`انتخاب کنید`},ariaLabel:{default:`انتخاب`},block:{type:Boolean,default:!1},searchable:{type:Boolean,default:!0},searchPlaceholder:{default:`جستجو…`},id:{default:void 0}},emits:[`update:modelValue`],setup(f,{emit:v}){let R=f,z=v,B=d(!1),V=d(``),H=d(null),U=d(null),W=d(null),G=d({});T(H,()=>{B.value=!1,V.value=``},{ignore:[U]});let K=_(()=>R.options.find(e=>e.value===R.modelValue)),q=_(()=>K.value?.label??R.placeholder),J=_(()=>O(R.options,V.value));function Y(e){e.key===`ArrowDown`?(e.preventDefault(),D(U.value,`first`)):e.key===`ArrowUp`&&(e.preventDefault(),D(U.value,`last`))}function X(e,t){let n=e.currentTarget;e.key===`ArrowDown`?(e.preventDefault(),E(n,1)):e.key===`ArrowUp`?(e.preventDefault(),E(n,-1)):(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),$(t))}function Z(){let e=H.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));G.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 Q(e){e?(window.addEventListener(`resize`,Z),window.addEventListener(`scroll`,Z,!0)):(window.removeEventListener(`resize`,Z),window.removeEventListener(`scroll`,Z,!0))}async function ne(){B.value=!B.value,B.value&&(V.value=``,await b(),Z(),R.searchable&&(await b(),W.value?.focus()))}function $(e){z(`update:modelValue`,e),B.value=!1,V.value=``}return o(B,e=>{Q(e),e&&b(()=>Z())}),r(()=>{Q(!1)}),(r,o)=>(e(),u(`div`,{id:f.id,ref_key:`rootRef`,ref:H,class:i([`admin-select`,{"admin-select--open":B.value,"admin-select--block":f.block}])},[l(`button`,{type:`button`,class:`admin-select__trigger`,"aria-label":f.ariaLabel,"aria-expanded":B.value,"aria-haspopup":`listbox`,onClick:ne},[l(`span`,j,[a(r.$slots,`option-leading`,{option:K.value},void 0,!0),l(`span`,ee,m(q.value),1)]),l(`span`,te,[p(w,{name:`chevron-down`,size:16})])],8,A),(e(),h(c,{to:`body`},[B.value?(e(),u(`ul`,{key:0,ref_key:`menuRef`,ref:U,class:`admin-select__menu`,"data-select-menu":``,role:`listbox`,"aria-label":f.ariaLabel,style:t(G.value)},[f.searchable?(e(),u(`li`,N,[s(l(`input`,{ref_key:`searchInputRef`,ref:W,"onUpdate:modelValue":o[0]||=e=>V.value=e,type:`search`,class:`admin-select__search-input`,placeholder:f.searchPlaceholder,onClick:o[1]||=S(()=>{},[`stop`]),onKeydown:[o[2]||=C(S(e=>B.value=!1,[`stop`]),[`esc`]),Y]},null,40,P),[[x,V.value]])])):y(``,!0),J.value.length?y(``,!0):(e(),u(`li`,F,` موردی یافت نشد `)),(e(!0),u(g,null,n(J.value,t=>(e(),u(`li`,{key:t.value,role:`presentation`},[l(`button`,{type:`button`,class:i([`admin-select__option`,{"admin-select__option--active":t.value===f.modelValue}]),"data-select-option":``,role:`option`,"aria-selected":t.value===f.modelValue,onClick:e=>$(t.value),onKeydown:e=>X(e,t.value)},[l(`span`,L,[a(r.$slots,`option-leading`,{option:t},void 0,!0),l(`span`,null,m(t.label),1)]),t.value===f.modelValue?(e(),h(w,{key:0,name:`check`,size:16,class:`admin-select__check`})):y(``,!0)],42,I)]))),128))],12,M)):y(``,!0)]))],10,k))}}),[[`__scopeId`,`data-v-4ee349a1`]]);export{R as t};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{A as e,Ot as t,P as n,c as r,d as i,g as a,h as o,jt as s,t as c,u as l}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{L as u}from"./index-DWlOII4H.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)=>(e(),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,s(a.title),1),a.description?(e(),i(`p`,p,s(a.description),1)):l(``,!0),c.$slots.default||c.$slots.secondary?(e(),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};
|
||||
import{A as e,Ot as t,P as n,c as r,d as i,g as a,h as o,jt as s,t as c,u as l}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{L as u}from"./index-BWgYBNME.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)=>(e(),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,s(a.title),1),a.description?(e(),i(`p`,p,s(a.description),1)):l(``,!0),c.$slots.default||c.$slots.secondary?(e(),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
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
.checks-page__order-meta[data-v-af5e25db]{align-items:center;gap:8px;display:flex}.checks-page__stats[data-v-af5e25db]{grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-bottom:14px;display:grid}.checks-page__stat[data-v-af5e25db]{border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);flex-direction:column;gap:2px;padding:10px 12px;display:flex}.checks-page__stat span[data-v-af5e25db]{color:var(--color-text-muted);font-size:.75rem}.checks-page__stat strong[data-v-af5e25db]{font-size:.875rem;font-weight:700}.checks-page__list[data-v-af5e25db]{overflow:hidden}.check-row[data-v-af5e25db]{border-bottom:1px solid var(--color-border-light);grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px 12px;padding:8px 12px;display:grid}.check-row[data-v-af5e25db]:last-child{border-bottom:0}.check-row.open[data-v-af5e25db]{background:color-mix(in srgb, var(--color-primary-soft) 55%, transparent)}.check-row__main[data-v-af5e25db]{min-width:0;color:inherit;text-align:start;cursor:pointer;background:0 0;border:0;align-items:center;gap:10px;padding:4px 0;display:flex}.check-row__chevron[data-v-af5e25db]{width:14px;color:var(--color-text-muted);flex-shrink:0;font-size:.75rem}.check-row__thumb[data-v-af5e25db]{border:1px solid var(--color-border);cursor:zoom-in;background:#111;border-radius:6px;flex-shrink:0;place-items:center;width:44px;height:32px;padding:0;display:grid;overflow:hidden}.check-row__thumb img[data-v-af5e25db]{object-fit:cover;width:100%;height:100%;display:block}.check-row__thumb--empty[data-v-af5e25db]{color:var(--color-text-muted);cursor:default;font-size:.625rem}.check-row__meta[data-v-af5e25db]{flex:1;gap:2px;min-width:0;display:grid}.check-row__meta strong[data-v-af5e25db]{font-size:.875rem;font-weight:700}.check-row__meta small[data-v-af5e25db]{color:var(--color-text-muted);white-space:nowrap;text-overflow:ellipsis;font-size:.75rem;overflow:hidden}.check-row__actions[data-v-af5e25db]{flex-shrink:0;gap:6px;display:flex}.check-row__panel[data-v-af5e25db]{border-top:1px dashed var(--color-border);flex-wrap:wrap;grid-column:1/-1;align-items:flex-start;gap:12px 16px;padding:8px 0 4px 24px;display:flex}.check-row__fields[data-v-af5e25db]{flex-wrap:wrap;flex:1;gap:8px;min-width:200px;display:flex}.check-row__field[data-v-af5e25db]{background:var(--color-border-light);border-radius:999px;align-items:baseline;gap:6px;padding:4px 8px;font-size:.75rem;display:inline-flex}.check-row__field span[data-v-af5e25db]{color:var(--color-text-muted)}.check-row__field strong[data-v-af5e25db]{font-weight:600}.check-row__photos[data-v-af5e25db]{flex-shrink:0;gap:8px;display:flex}.check-row__photo[data-v-af5e25db]{border:1px solid var(--color-border);width:96px;color:inherit;cursor:zoom-in;text-align:center;background:0 0;border-radius:8px;padding:0;overflow:hidden}.check-row__photo img[data-v-af5e25db]{object-fit:cover;background:#111;width:100%;height:60px;display:block}.check-row__photo span[data-v-af5e25db]{color:var(--color-text-muted);padding:4px;font-size:.6875rem;display:block}.check-row__hint[data-v-af5e25db]{color:var(--color-text-muted);margin:0;font-size:.75rem}.checks-page__footer[data-v-af5e25db]{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin-top:14px;display:flex}.checks-page__note[data-v-af5e25db]{color:var(--color-text-muted);margin:0;font-size:.75rem}.checks-page__history[data-v-af5e25db]{gap:8px;display:grid}.checks-page__history-item[data-v-af5e25db]{gap:6px;padding:12px;display:grid}.checks-page__history-item-head[data-v-af5e25db]{flex-wrap:wrap;justify-content:space-between;gap:12px;font-size:.875rem;display:flex}.checks-page__history-meta[data-v-af5e25db],.checks-page__history-note[data-v-af5e25db]{margin:0;font-size:.8125rem;line-height:1.5}.checks-page__history-meta[data-v-af5e25db]{color:var(--color-text-muted)}.checks-page__lightbox[data-v-af5e25db]{z-index:300000;background:#000000d6;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.checks-page__lightbox img[data-v-af5e25db]{object-fit:contain;border-radius:8px;max-width:min(900px,100%);max-height:88vh}.checks-page__lightbox-close[data-v-af5e25db]{top:14px;cursor:pointer;border:0;border-radius:8px;padding:8px 12px;position:absolute;inset-inline-end:14px}@media (width<=800px){.checks-page__stats[data-v-af5e25db]{grid-template-columns:repeat(2,minmax(0,1fr))}.check-row[data-v-af5e25db]{grid-template-columns:1fr}.check-row__actions[data-v-af5e25db]{padding-inline-start:24px}.check-row__panel[data-v-af5e25db]{padding-inline-start:0}}
|
||||
@@ -0,0 +1 @@
|
||||
.checks-page__order-meta[data-v-6ad55e99]{align-items:center;gap:8px;display:flex}.checks-page__stats[data-v-6ad55e99]{grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-bottom:14px;display:grid}.checks-page__stat[data-v-6ad55e99]{border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);flex-direction:column;gap:2px;padding:10px 12px;display:flex}.checks-page__stat span[data-v-6ad55e99]{color:var(--color-text-muted);font-size:.75rem}.checks-page__stat strong[data-v-6ad55e99]{font-size:.875rem;font-weight:700}.checks-page__list[data-v-6ad55e99]{overflow:hidden}.check-row[data-v-6ad55e99]{border-bottom:1px solid var(--color-border-light);grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px 12px;padding:8px 12px;display:grid}.check-row[data-v-6ad55e99]:last-child{border-bottom:0}.check-row.open[data-v-6ad55e99]{background:color-mix(in srgb, var(--color-primary-soft) 55%, transparent)}.check-row__main[data-v-6ad55e99]{min-width:0;color:inherit;text-align:start;cursor:pointer;background:0 0;border:0;align-items:center;gap:10px;padding:4px 0;display:flex}.check-row__chevron[data-v-6ad55e99]{width:14px;color:var(--color-text-muted);flex-shrink:0;font-size:.75rem}.check-row__thumb[data-v-6ad55e99]{border:1px solid var(--color-border);cursor:zoom-in;background:#111;border-radius:6px;flex-shrink:0;place-items:center;width:44px;height:32px;padding:0;display:grid;overflow:hidden}.check-row__thumb img[data-v-6ad55e99]{object-fit:cover;width:100%;height:100%;display:block}.check-row__thumb--empty[data-v-6ad55e99]{color:var(--color-text-muted);cursor:default;font-size:.625rem}.check-row__meta[data-v-6ad55e99]{flex:1;gap:2px;min-width:0;display:grid}.check-row__meta strong[data-v-6ad55e99]{font-size:.875rem;font-weight:700}.check-row__meta small[data-v-6ad55e99]{color:var(--color-text-muted);white-space:nowrap;text-overflow:ellipsis;font-size:.75rem;overflow:hidden}.check-row__actions[data-v-6ad55e99]{flex-shrink:0;gap:6px;display:flex}.check-row__panel[data-v-6ad55e99]{border-top:1px dashed var(--color-border);flex-wrap:wrap;grid-column:1/-1;align-items:flex-start;gap:12px 16px;padding:8px 0 4px 24px;display:flex}.check-row__fields[data-v-6ad55e99]{flex-wrap:wrap;flex:1;gap:8px;min-width:200px;display:flex}.check-row__field[data-v-6ad55e99]{background:var(--color-border-light);border-radius:999px;align-items:baseline;gap:6px;padding:4px 8px;font-size:.75rem;display:inline-flex}.check-row__field span[data-v-6ad55e99]{color:var(--color-text-muted)}.check-row__field strong[data-v-6ad55e99]{font-weight:600}.check-row__photos[data-v-6ad55e99]{flex-shrink:0;gap:8px;display:flex}.check-row__photo[data-v-6ad55e99]{border:1px solid var(--color-border);width:96px;color:inherit;cursor:zoom-in;text-align:center;background:0 0;border-radius:8px;padding:0;overflow:hidden}.check-row__photo img[data-v-6ad55e99]{object-fit:cover;background:#111;width:100%;height:60px;display:block}.check-row__photo span[data-v-6ad55e99]{color:var(--color-text-muted);padding:4px;font-size:.6875rem;display:block}.check-row__hint[data-v-6ad55e99]{color:var(--color-text-muted);margin:0;font-size:.75rem}.checks-page__footer[data-v-6ad55e99]{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin-top:14px;display:flex}.checks-page__note[data-v-6ad55e99]{color:var(--color-text-muted);margin:0;font-size:.75rem}.checks-page__history[data-v-6ad55e99]{gap:8px;display:grid}.checks-page__history-item[data-v-6ad55e99]{gap:6px;padding:12px;display:grid}.checks-page__history-item-head[data-v-6ad55e99]{flex-wrap:wrap;justify-content:space-between;gap:12px;font-size:.875rem;display:flex}.checks-page__history-meta[data-v-6ad55e99],.checks-page__history-note[data-v-6ad55e99]{margin:0;font-size:.8125rem;line-height:1.5}.checks-page__history-meta[data-v-6ad55e99]{color:var(--color-text-muted)}.checks-page__lightbox[data-v-6ad55e99]{z-index:300000;background:#000000d6;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.checks-page__lightbox img[data-v-6ad55e99]{object-fit:contain;border-radius:8px;max-width:min(900px,100%);max-height:88vh}.checks-page__lightbox-close[data-v-6ad55e99]{top:14px;cursor:pointer;border:0;border-radius:8px;padding:8px 12px;position:absolute;inset-inline-end:14px}@media (width<=800px){.checks-page__stats[data-v-6ad55e99]{grid-template-columns:repeat(2,minmax(0,1fr))}.check-row[data-v-6ad55e99]{grid-template-columns:1fr}.check-row__actions[data-v-6ad55e99]{padding-inline-start:24px}.check-row__panel[data-v-6ad55e99]{padding-inline-start:0}}
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
-1
@@ -1 +0,0 @@
|
||||
.checks-list-page__summary[data-v-09633f1f]{color:var(--color-text-muted);flex-direction:column;align-items:flex-end;gap:4px;font-size:.8125rem;display:flex}.checks-list-page__filters[data-v-09633f1f]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;display:flex}.checks-list-page__search[data-v-09633f1f]{border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-border-light);min-width:220px;color:var(--color-text-muted);flex:1;align-items:center;gap:10px;padding:8px 12px;display:flex}.checks-list-page__search-input[data-v-09633f1f]{color:var(--color-text);background:0 0;border:none;outline:none;flex:1;font-size:.875rem}.checks-list-page__status-select[data-v-09633f1f]{flex:0 220px;width:220px}.checks-list-page__table[data-v-09633f1f]{padding:0;overflow:hidden}.checks-list-page__order-link[data-v-09633f1f]{color:var(--color-primary);cursor:pointer;font:inherit;background:0 0;border:none;padding:0}.checks-list-page__order-link[data-v-09633f1f]:hover{text-decoration:underline}.checks-list-page__empty[data-v-09633f1f]{text-align:center;color:var(--color-text-muted);margin:0;padding:24px;font-size:.875rem}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
||||
import{A as e,D as t,N as n,Q as r,U as i,W as a,c as o,d as s,et as c,g as l,h as u,jt as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as _,d as v,t as y}from"./http-CTjL79ty.js";import{S as b,V as x}from"./index-DWlOII4H.js";import{t as S}from"./AdminPageSkeleton-DacAHji8.js";import{t as C}from"./BaseEmptyState-B6cM4bRM.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=c([]),N=c(!0),P=c(!1),F=c(null),I=_(),L=r({code:``,label:``,sortOrder:0,benefitsText:``}),R=h(()=>F.value?`ویرایش سطح`:`سطح جدید`);function z(e){return e.split(`
|
||||
import{A as e,D as t,N as n,Q as r,U as i,W as a,c as o,d as s,et as c,g as l,h as u,jt as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as _,d as v,t as y}from"./http-CTjL79ty.js";import{S as b,V as x}from"./index-BWgYBNME.js";import{t as S}from"./AdminPageSkeleton-DacAHji8.js";import{t as C}from"./BaseEmptyState-88fQ29rO.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=c([]),N=c(!0),P=c(!1),F=c(null),I=_(),L=r({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 b.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 b.update(F.value,e):await b.create(e),P.value=!1,I.success(`ذخیره شد`),await B()}catch(e){I.error(e instanceof y?e.message:`ذخیره ناموفق بود`)}}return t(()=>{B()}),(t,r)=>(e(),s(`div`,w,[o(`header`,{class:`admin-page__head`},[r[5]||=o(`div`,null,[o(`h1`,null,`سطوح و مزایای مشتری`),o(`p`,null,`تعریف Level داخلی CRM و مزایای هر سطح (نمایش فقط در ادمین)`)],-1),o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:V},`سطح جدید`)]),N.value?(e(),f(S,{key:0,variant:`table`})):g.value.length?(e(),s(`table`,T,[r[6]||=o(`thead`,null,[o(`tr`,null,[o(`th`,null,`کد`),o(`th`,null,`عنوان`),o(`th`,null,`مزایا`),o(`th`,null,`مشتریان`),o(`th`)])],-1),o(`tbody`,null,[(e(!0),s(m,null,n(g.value,t=>(e(),s(`tr`,{key:t.id},[o(`td`,E,d(t.code),1),o(`td`,null,d(t.label),1),o(`td`,null,d(t.benefits.map(e=>e.title).join(`، `)||`—`),1),o(`td`,null,d(t.customersCount),1),o(`td`,null,[o(`button`,{type:`button`,class:`link`,onClick:e=>H(t)},`ویرایش`,8,D)])]))),128))])])):(e(),f(C,{key:1,title:`سطحی تعریف نشده`})),u(x,{open:P.value,title:R.value,onClose:r[4]||=e=>P.value=!1},{footer:i(()=>[o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!L.code.trim()||!L.label.trim(),onClick:U},` ذخیره `,8,M)]),default:i(()=>[o(`label`,O,[r[7]||=p(`کد`,-1),a(o(`input`,{"onUpdate:modelValue":r[0]||=e=>L.code=e,class:`admin-input`,dir:`ltr`},null,512),[[v,L.code]])]),o(`label`,k,[r[8]||=p(`عنوان`,-1),a(o(`input`,{"onUpdate:modelValue":r[1]||=e=>L.label=e,class:`admin-input`},null,512),[[v,L.label]])]),o(`label`,A,[r[9]||=p(`ترتیب`,-1),a(o(`input`,{"onUpdate:modelValue":r[2]||=e=>L.sortOrder=e,type:`number`,class:`admin-input`},null,512),[[v,L.sortOrder,void 0,{number:!0}]])]),o(`label`,j,[r[10]||=p(` مزایا (هر خط یک مورد) `,-1),a(o(`textarea`,{"onUpdate:modelValue":r[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 +1 @@
|
||||
import{A as e,W as t,c as n,ct as r,d as i,et as a,g as o,h as s,jt as c,m as l,s as u,t as d,u as f}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as p,d as m,l as h,m as g,u as _}from"./http-CTjL79ty.js";import{F as v,I as y,L as b,P as x,R as S,z as C}from"./index-DWlOII4H.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(o({__name:`LoginView`,setup(o){let d=C(),U=S(),W=x(),G=p(),K=a(y()?v.phone:``),q=a(y()?v.password:``),J=a(!0),Y=a(!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(a,o)=>(e(),i(`div`,w,[n(`div`,T,[n(`div`,E,[n(`div`,D,[o[8]||=n(`h2`,{class:`login-page__title`},`ورود به پنل مدیریت`,-1),o[9]||=n(`p`,{class:`login-page__subtitle`},`برای ادامه، اطلاعات حساب کاربری خود را وارد کنید.`,-1),r(X)?(e(),i(`p`,O,[o[6]||=l(` حالت موک فعال است — `,-1),n(`span`,k,c(r(v).phone),1),o[7]||=l(` / `,-1),n(`span`,A,c(r(v).password),1)])):f(``,!0)]),n(`form`,{class:`admin-form login-page__form`,onSubmit:g($,[`prevent`])},[r(W).error?(e(),i(`p`,j,c(r(W).error),1)):f(``,!0),n(`div`,M,[o[10]||=n(`label`,{for:`login-phone`},`شماره موبایل`,-1),n(`div`,N,[n(`span`,P,[s(b,{name:`phone`,size:18})]),t(n(`input`,{id:`login-phone`,"onUpdate:modelValue":o[0]||=e=>K.value=e,type:`tel`,class:`admin-input login-page__input`,placeholder:`۰۹۱۲۱۱۱۱۲۲۲۲`,autocomplete:`username`,inputmode:`tel`,dir:`ltr`,onInput:o[1]||=e=>r(W).clearError()},null,544),[[m,K.value]])])]),n(`div`,F,[o[11]||=n(`label`,{for:`login-password`},`رمز عبور`,-1),n(`div`,I,[n(`span`,L,[s(b,{name:`lock`,size:18})]),t(n(`input`,{id:`login-password`,"onUpdate:modelValue":o[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:o[3]||=e=>r(W).clearError()},null,40,R),[[_,q.value]]),n(`button`,{type:`button`,class:`login-page__toggle-password`,"aria-label":Y.value?`پنهان کردن رمز`:`نمایش رمز`,onClick:o[4]||=e=>Y.value=!Y.value},[s(b,{name:Y.value?`eye-off`:`eye`,size:18},null,8,[`name`])],8,z)])]),n(`label`,B,[t(n(`input`,{"onUpdate:modelValue":o[5]||=e=>J.value=e,type:`checkbox`},null,512),[[h,J.value]]),o[12]||=n(`span`,null,`مرا به خاطر بسپار`,-1)]),n(`button`,{type:`submit`,class:`admin-btn admin-btn--primary login-page__submit`,disabled:!Z.value||r(W).loading},[r(W).loading?(e(),i(`span`,H)):f(``,!0),o[13]||=l(` ورود به پنل `,-1)],8,V)],32)])]),n(`div`,{class:`login-page__brand`},[n(`div`,{class:`login-page__brand-inner`},[n(`img`,{src:`/admin/brand-logo.png`,alt:`نادمی تکس`,class:`login-page__brand-logo`}),o[14]||=n(`p`,{class:`login-page__brand-badge`},`پارچه`,-1),o[15]||=n(`h1`,{class:`login-page__brand-title`},`پنل مدیریت سفارشهای عمده`,-1),o[16]||=n(`p`,{class:`login-page__brand-text`},` مدیریت سفارشها، مشتریان، قیمتگذاری، چکها و گزارشهای فروش در یک محیط یکپارچه. `,-1)])])]))}}),[[`__scopeId`,`data-v-e708878f`]]);export{U as default};
|
||||
import{A as e,W as t,c as n,ct as r,d as i,et as a,g as o,h as s,jt as c,m as l,s as u,t as d,u as f}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as p,d as m,l as h,m as g,u as _}from"./http-CTjL79ty.js";import{F as v,I as y,L as b,P as x,R as S,z as C}from"./index-BWgYBNME.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(o({__name:`LoginView`,setup(o){let d=C(),U=S(),W=x(),G=p(),K=a(y()?v.phone:``),q=a(y()?v.password:``),J=a(!0),Y=a(!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(a,o)=>(e(),i(`div`,w,[n(`div`,T,[n(`div`,E,[n(`div`,D,[o[8]||=n(`h2`,{class:`login-page__title`},`ورود به پنل مدیریت`,-1),o[9]||=n(`p`,{class:`login-page__subtitle`},`برای ادامه، اطلاعات حساب کاربری خود را وارد کنید.`,-1),r(X)?(e(),i(`p`,O,[o[6]||=l(` حالت موک فعال است — `,-1),n(`span`,k,c(r(v).phone),1),o[7]||=l(` / `,-1),n(`span`,A,c(r(v).password),1)])):f(``,!0)]),n(`form`,{class:`admin-form login-page__form`,onSubmit:g($,[`prevent`])},[r(W).error?(e(),i(`p`,j,c(r(W).error),1)):f(``,!0),n(`div`,M,[o[10]||=n(`label`,{for:`login-phone`},`شماره موبایل`,-1),n(`div`,N,[n(`span`,P,[s(b,{name:`phone`,size:18})]),t(n(`input`,{id:`login-phone`,"onUpdate:modelValue":o[0]||=e=>K.value=e,type:`tel`,class:`admin-input login-page__input`,placeholder:`۰۹۱۲۱۱۱۱۲۲۲۲`,autocomplete:`username`,inputmode:`tel`,dir:`ltr`,onInput:o[1]||=e=>r(W).clearError()},null,544),[[m,K.value]])])]),n(`div`,F,[o[11]||=n(`label`,{for:`login-password`},`رمز عبور`,-1),n(`div`,I,[n(`span`,L,[s(b,{name:`lock`,size:18})]),t(n(`input`,{id:`login-password`,"onUpdate:modelValue":o[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:o[3]||=e=>r(W).clearError()},null,40,R),[[_,q.value]]),n(`button`,{type:`button`,class:`login-page__toggle-password`,"aria-label":Y.value?`پنهان کردن رمز`:`نمایش رمز`,onClick:o[4]||=e=>Y.value=!Y.value},[s(b,{name:Y.value?`eye-off`:`eye`,size:18},null,8,[`name`])],8,z)])]),n(`label`,B,[t(n(`input`,{"onUpdate:modelValue":o[5]||=e=>J.value=e,type:`checkbox`},null,512),[[h,J.value]]),o[12]||=n(`span`,null,`مرا به خاطر بسپار`,-1)]),n(`button`,{type:`submit`,class:`admin-btn admin-btn--primary login-page__submit`,disabled:!Z.value||r(W).loading},[r(W).loading?(e(),i(`span`,H)):f(``,!0),o[13]||=l(` ورود به پنل `,-1)],8,V)],32)])]),n(`div`,{class:`login-page__brand`},[n(`div`,{class:`login-page__brand-inner`},[n(`img`,{src:`/admin/brand-logo.png`,alt:`نادمی تکس`,class:`login-page__brand-logo`}),o[14]||=n(`p`,{class:`login-page__brand-badge`},`پارچه`,-1),o[15]||=n(`h1`,{class:`login-page__brand-title`},`پنل مدیریت سفارشهای عمده`,-1),o[16]||=n(`p`,{class:`login-page__brand-text`},` مدیریت سفارشها، مشتریان، قیمتگذاری، چکها و گزارشهای فروش در یک محیط یکپارچه. `,-1)])])]))}}),[[`__scopeId`,`data-v-e708878f`]]);export{U as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
.products-page__filters[data-v-87b603ef]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;display:flex}.products-page__search[data-v-87b603ef]{min-width:200px;color:var(--color-text-muted);flex:1;align-items:center;gap:10px;display:flex}.products-page__search-input[data-v-87b603ef]{background:0 0;border:none;outline:none;flex:1;font-size:.875rem}.products-page__catalog-filter[data-v-87b603ef]{width:min(260px,100%)}.admin-form__hint[data-v-87b603ef]{color:var(--color-text-muted);margin:6px 0 0;font-size:.75rem;line-height:1.5}.products-page__table[data-v-87b603ef]{overflow:hidden}.product-thumb[data-v-87b603ef]{background:#e8eceb 50%/cover no-repeat;border-radius:8px;width:44px;height:36px;display:block}.product-thumb--empty[data-v-87b603ef]{background:#eef1f0}.color-variants__hint[data-v-87b603ef]{color:var(--color-text-muted);margin:0 0 10px;font-size:.75rem;line-height:1.6}.general-images[data-v-87b603ef],.color-variants[data-v-87b603ef]{flex-direction:column;gap:10px;display:flex}.product-media-row[data-v-87b603ef]{border:1px solid var(--color-border);background:var(--color-elevated,#fff);border-radius:14px;grid-template-columns:1fr auto;align-items:center;gap:12px 14px;padding:12px 14px;display:grid;box-shadow:0 1px 2px #0f172a0a}.product-media-row--color[data-v-87b603ef]{grid-template-columns:auto 1fr auto;align-items:center}.product-media-row[data-v-87b603ef] .image-picker{min-width:0}.product-media-row__input[data-v-87b603ef]{min-width:0;height:44px}.product-media-row__delete[data-v-87b603ef]{width:40px;height:40px;color:var(--color-text-muted);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:12px;flex-shrink:0;justify-content:center;align-items:center;padding:0;transition:color .15s,background .15s,border-color .15s;display:inline-flex}.product-media-row__delete[data-v-87b603ef]:hover{color:#c53030;background:#c5303014;border-color:#c530302e}.product-media-row__delete[data-v-87b603ef]:focus-visible{outline:2px solid var(--color-primary,#2d6a4f);outline-offset:2px}.product-media-add[data-v-87b603ef]{justify-content:center;align-self:stretch}@media (width<=520px){.product-media-row--color[data-v-87b603ef]{grid-template-rows:auto auto;grid-template-columns:1fr auto}.product-media-row--color[data-v-87b603ef] .image-picker{grid-column:1/-1}.product-media-row--color .product-media-row__delete[data-v-87b603ef]{grid-area:2/2}.product-media-row--color .product-media-row__input[data-v-87b603ef]{grid-area:2/1}}
|
||||
-1
@@ -1 +0,0 @@
|
||||
.products-page__filters[data-v-83a6f3f4]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;display:flex}.products-page__search[data-v-83a6f3f4]{min-width:200px;color:var(--color-text-muted);flex:1;align-items:center;gap:10px;display:flex}.products-page__search-input[data-v-83a6f3f4]{background:0 0;border:none;outline:none;flex:1;font-size:.875rem}.products-page__catalog-filter[data-v-83a6f3f4]{width:min(260px,100%)}.admin-form__hint[data-v-83a6f3f4]{color:var(--color-text-muted);margin:6px 0 0;font-size:.75rem;line-height:1.5}.products-page__table[data-v-83a6f3f4]{overflow:hidden}.product-thumb[data-v-83a6f3f4]{background:#e8eceb 50%/cover no-repeat;border-radius:8px;width:44px;height:36px;display:block}.product-thumb--empty[data-v-83a6f3f4]{background:#eef1f0}.color-variants__hint[data-v-83a6f3f4]{color:var(--color-text-muted);margin:0 0 10px;font-size:.75rem;line-height:1.6}.general-images[data-v-83a6f3f4],.color-variants[data-v-83a6f3f4]{flex-direction:column;gap:10px;display:flex}.product-media-row[data-v-83a6f3f4]{border:1px solid var(--color-border);background:var(--color-elevated,#fff);border-radius:14px;grid-template-columns:1fr auto;align-items:center;gap:12px 14px;padding:12px 14px;display:grid;box-shadow:0 1px 2px #0f172a0a}.product-media-row--color[data-v-83a6f3f4]{grid-template-columns:auto 1fr auto;align-items:center}.product-media-row[data-v-83a6f3f4] .image-picker{min-width:0}.product-media-row__input[data-v-83a6f3f4]{min-width:0;height:44px}.product-media-row__delete[data-v-83a6f3f4]{width:40px;height:40px;color:var(--color-text-muted);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:12px;flex-shrink:0;justify-content:center;align-items:center;padding:0;transition:color .15s,background .15s,border-color .15s;display:inline-flex}.product-media-row__delete[data-v-83a6f3f4]:hover{color:#c53030;background:#c5303014;border-color:#c530302e}.product-media-row__delete[data-v-83a6f3f4]:focus-visible{outline:2px solid var(--color-primary,#2d6a4f);outline-offset:2px}.product-media-add[data-v-83a6f3f4]{justify-content:center;align-self:stretch}@media (width<=520px){.product-media-row--color[data-v-83a6f3f4]{grid-template-rows:auto auto;grid-template-columns:1fr auto}.product-media-row--color[data-v-83a6f3f4] .image-picker{grid-column:1/-1}.product-media-row--color .product-media-row__delete[data-v-83a6f3f4]{grid-area:2/2}.product-media-row--color .product-media-row__input[data-v-83a6f3f4]{grid-area:2/1}}
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{A as e,D as t,N as n,Q as r,U as i,W as a,c as o,d as s,et as c,g as l,h as u,jt as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as _,d as v,t as y}from"./http-CTjL79ty.js";import{E as b,V as x,j as S,y as C}from"./index-DWlOII4H.js";import{t as w}from"./AdminPageSkeleton-DacAHji8.js";import{t as T}from"./BaseEmptyState-B6cM4bRM.js";import{t as E}from"./AdminSelect-CWMyO8tk.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=c([]),I=c(!0),L=c([]),R=c([]),z=c(!1),B=_(),V=r({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 t(()=>{W()}),(t,r)=>(e(),s(`div`,D,[o(`header`,O,[r[5]||=o(`div`,null,[o(`h1`,null,`پیشنهاد محصول`),o(`p`,null,`پیشنهاد دستی محصول به مشتری`)],-1),o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:r[0]||=e=>z.value=!0},`پیشنهاد جدید`)]),I.value?(e(),f(w,{key:0,variant:`table`})):g.value.length?(e(),s(`table`,k,[r[6]||=o(`thead`,null,[o(`tr`,null,[o(`th`,null,`مشتری`),o(`th`,null,`محصول`),o(`th`,null,`یادداشت`),o(`th`,null,`وضعیت`),o(`th`)])],-1),o(`tbody`,null,[(e(!0),s(m,null,n(g.value,t=>(e(),s(`tr`,{key:t.id},[o(`td`,null,d(t.customerName),1),o(`td`,null,[p(d(t.productName)+` `,1),o(`span`,A,`(`+d(t.productCode)+`)`,1)]),o(`td`,null,d(t.note||`—`),1),o(`td`,null,d(t.isActive?`فعال`:`غیرفعال`),1),o(`td`,null,[o(`button`,{type:`button`,class:`link`,onClick:e=>K(t)},d(t.isActive?`غیرفعال`:`فعال`),9,j)])]))),128))])])):(e(),f(T,{key:1,title:`پیشنهادی ثبت نشده`})),u(x,{open:z.value,title:`پیشنهاد محصول`,onClose:r[4]||=e=>z.value=!1},{footer:i(()=>[o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!V.customerId||!V.productId,onClick:G},` ثبت `,8,F)]),default:i(()=>[o(`label`,M,[r[7]||=p(`مشتری `,-1),u(E,{modelValue:V.customerId,"onUpdate:modelValue":r[1]||=e=>V.customerId=e,options:H.value},null,8,[`modelValue`,`options`])]),o(`label`,N,[r[8]||=p(`محصول `,-1),u(E,{modelValue:V.productId,"onUpdate:modelValue":r[2]||=e=>V.productId=e,options:U.value},null,8,[`modelValue`,`options`])]),o(`label`,P,[r[9]||=p(`یادداشت`,-1),a(o(`textarea`,{"onUpdate:modelValue":r[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};
|
||||
import{A as e,D as t,N as n,Q as r,U as i,W as a,c as o,d as s,et as c,g as l,h as u,jt as d,l as f,m as p,r as m,s as h,t as g}from"./_plugin-vue_export-helper-vx-p5QAT.js";import{a as _,d as v,t as y}from"./http-CTjL79ty.js";import{E as b,V as x,j as S,y as C}from"./index-BWgYBNME.js";import{t as w}from"./AdminPageSkeleton-DacAHji8.js";import{t as T}from"./BaseEmptyState-88fQ29rO.js";import{t as E}from"./AdminSelect-hgn_nYC2.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=c([]),I=c(!0),L=c([]),R=c([]),z=c(!1),B=_(),V=r({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 t(()=>{W()}),(t,r)=>(e(),s(`div`,D,[o(`header`,O,[r[5]||=o(`div`,null,[o(`h1`,null,`پیشنهاد محصول`),o(`p`,null,`پیشنهاد دستی محصول به مشتری`)],-1),o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,onClick:r[0]||=e=>z.value=!0},`پیشنهاد جدید`)]),I.value?(e(),f(w,{key:0,variant:`table`})):g.value.length?(e(),s(`table`,k,[r[6]||=o(`thead`,null,[o(`tr`,null,[o(`th`,null,`مشتری`),o(`th`,null,`محصول`),o(`th`,null,`یادداشت`),o(`th`,null,`وضعیت`),o(`th`)])],-1),o(`tbody`,null,[(e(!0),s(m,null,n(g.value,t=>(e(),s(`tr`,{key:t.id},[o(`td`,null,d(t.customerName),1),o(`td`,null,[p(d(t.productName)+` `,1),o(`span`,A,`(`+d(t.productCode)+`)`,1)]),o(`td`,null,d(t.note||`—`),1),o(`td`,null,d(t.isActive?`فعال`:`غیرفعال`),1),o(`td`,null,[o(`button`,{type:`button`,class:`link`,onClick:e=>K(t)},d(t.isActive?`غیرفعال`:`فعال`),9,j)])]))),128))])])):(e(),f(T,{key:1,title:`پیشنهادی ثبت نشده`})),u(x,{open:z.value,title:`پیشنهاد محصول`,onClose:r[4]||=e=>z.value=!1},{footer:i(()=>[o(`button`,{type:`button`,class:`admin-btn admin-btn--primary`,disabled:!V.customerId||!V.productId,onClick:G},` ثبت `,8,F)]),default:i(()=>[o(`label`,M,[r[7]||=p(`مشتری `,-1),u(E,{modelValue:V.customerId,"onUpdate:modelValue":r[1]||=e=>V.customerId=e,options:H.value},null,8,[`modelValue`,`options`])]),o(`label`,N,[r[8]||=p(`محصول `,-1),u(E,{modelValue:V.productId,"onUpdate:modelValue":r[2]||=e=>V.productId=e,options:U.value},null,8,[`modelValue`,`options`])]),o(`label`,P,[r[9]||=p(`یادداشت`,-1),a(o(`textarea`,{"onUpdate:modelValue":r[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
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{l as e}from"./index-DWlOII4H.js";function t(t){return e(t).toLowerCase().replace(/ي/g,`ی`).replace(/ك/g,`ک`).normalize(`NFKC`).trim()}function n(e,n){let r=t(n);return!r||t(e).includes(r)}function r(e,t){let r=t.trim();return r?e.filter(e=>n(e.label,r)):e}function i(e,t){if(!e)return;let n=e.querySelectorAll(`[data-select-option]`);(t===`first`?n[0]:n[n.length-1])?.focus()}function a(e,t){let n=e.closest(`[data-select-menu]`);if(!n)return;let r=[...n.querySelectorAll(`[data-select-option]`)],i=r.indexOf(e);i<0||r[i+t]?.focus()}export{a as n,i as r,r as t};
|
||||
import{l as e}from"./index-BWgYBNME.js";function t(t){return e(t).toLowerCase().replace(/ي/g,`ی`).replace(/ك/g,`ک`).normalize(`NFKC`).trim()}function n(e,n){let r=t(n);return!r||t(e).includes(r)}function r(e,t){let r=t.trim();return r?e.filter(e=>n(e.label,r)):e}function i(e,t){if(!e)return;let n=e.querySelectorAll(`[data-select-option]`);(t===`first`?n[0]:n[n.length-1])?.focus()}function a(e,t){let n=e.closest(`[data-select-menu]`);if(!n)return;let r=[...n.querySelectorAll(`[data-select-option]`)],i=r.indexOf(e);i<0||r[i+t]?.focus()}export{a as n,i as r,r as t};
|
||||
Vendored
+2
-2
@@ -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-DWlOII4H.js"></script>
|
||||
<script type="module" crossorigin src="/admin/assets/index-BWgYBNME.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/admin/assets/_plugin-vue_export-helper-vx-p5QAT.js">
|
||||
<link rel="modulepreload" crossorigin href="/admin/assets/http-CTjL79ty.js">
|
||||
<link rel="stylesheet" crossorigin href="/admin/assets/index-Cc10RyA4.css">
|
||||
<link rel="stylesheet" crossorigin href="/admin/assets/index-BsKtmxy-.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -193,6 +193,19 @@ export function useOrdersPage() {
|
||||
showDetailModal.value = false
|
||||
}
|
||||
|
||||
function dismissOrderDetail() {
|
||||
const returnToChecks = route.query.from === 'checks'
|
||||
showDetailModal.value = false
|
||||
showDetailPanel.value = false
|
||||
if (!returnToChecks) return
|
||||
const previous = window.history.state?.back
|
||||
if (typeof previous === 'string') {
|
||||
void router.back()
|
||||
return
|
||||
}
|
||||
void router.replace({ name: 'checks' })
|
||||
}
|
||||
|
||||
function settlementLabel(method?: string | null) {
|
||||
return settlementMethodLabel(method)
|
||||
}
|
||||
@@ -321,6 +334,7 @@ export function useOrdersPage() {
|
||||
openOrderDetail,
|
||||
closeDetailPanel,
|
||||
closeDetailModal,
|
||||
dismissOrderDetail,
|
||||
settlementLabel,
|
||||
changeStatus,
|
||||
statusSaving,
|
||||
|
||||
@@ -251,6 +251,8 @@ export interface Product {
|
||||
subtitle?: string
|
||||
specs?: string
|
||||
rollMeters?: number
|
||||
widthCm?: number | null
|
||||
weightGrams?: number | null
|
||||
isNew?: boolean
|
||||
colors?: string[]
|
||||
colorImages?: Array<string | null>
|
||||
|
||||
@@ -392,7 +392,7 @@ async function finalApproveOrder() {
|
||||
<template v-else-if="order?.checkRassDate">
|
||||
راس: {{ formatDate(order.checkRassDate) }}
|
||||
</template>
|
||||
<template v-else>راس بر اساس تاریخ ثبت سفارش محاسبه میشود.</template>
|
||||
<template v-else>راس نسبت به تاریخ صدور فاکتور ثابت است.</template>
|
||||
</p>
|
||||
<div class="admin-action-group">
|
||||
<button
|
||||
|
||||
+669
-171
@@ -5,20 +5,52 @@ import AdminIcon from '@/components/icons/AdminIcon.vue'
|
||||
import AdminPageSkeleton from '@/components/ui/AdminPageSkeleton.vue'
|
||||
import AdminSelect from '@/components/ui/AdminSelect.vue'
|
||||
import StatusBadge from '@/components/ui/StatusBadge.vue'
|
||||
import { checksApi, ordersApi } from '@/services/api'
|
||||
import { checksApi, ordersApi, type ApiOrder } from '@/services/api'
|
||||
import { ApiError } from '@/services/http'
|
||||
import { formatCurrency, formatDateTime } from '@/utils/format'
|
||||
import { formatCurrency, formatDate, formatMeterage, formatNumber, toPersianDigits } from '@/utils/format'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import type { Check } from '@/types'
|
||||
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
type GoodsLine = {
|
||||
productName: string
|
||||
color: string
|
||||
meterage: number
|
||||
}
|
||||
|
||||
type OrderCheckMeta = {
|
||||
orderNumber: string
|
||||
customerName: string
|
||||
invoiceAmount: number | null
|
||||
rassDate: string | null
|
||||
rassDays: number | null
|
||||
goods: GoodsLine[]
|
||||
}
|
||||
|
||||
type CheckGroup = {
|
||||
orderId: string
|
||||
customerName: string
|
||||
orderNumber: string
|
||||
invoiceAmount: number | null
|
||||
rassDate: string | null
|
||||
rassDays: number | null
|
||||
goodsLabel: string
|
||||
totalCheckAmount: number
|
||||
hasPending: boolean
|
||||
latestAt: number
|
||||
checks: Check[]
|
||||
}
|
||||
|
||||
const checkList = ref<Check[]>([])
|
||||
const orderMeta = ref(new Map<string, OrderCheckMeta>())
|
||||
const loading = ref(true)
|
||||
const searchQuery = ref('')
|
||||
const statusFilter = ref<'all' | Check['status']>('all')
|
||||
const busyId = ref<string | null>(null)
|
||||
const previewImage = ref<string | null>(null)
|
||||
const openGroups = ref<Record<string, boolean>>({})
|
||||
|
||||
const statusFilterOptions = [
|
||||
{ value: 'all', label: 'همه وضعیتها' },
|
||||
@@ -27,57 +59,189 @@ const statusFilterOptions = [
|
||||
{ value: 'rejected', label: 'رد شده' },
|
||||
]
|
||||
|
||||
const filteredChecks = computed(() => {
|
||||
let list = checkList.value
|
||||
if (statusFilter.value !== 'all') {
|
||||
list = list.filter((c) => c.status === statusFilter.value)
|
||||
}
|
||||
const q = searchQuery.value.trim()
|
||||
if (q) {
|
||||
list = list.filter(
|
||||
(c) =>
|
||||
(c.orderNumber ?? '').includes(q) ||
|
||||
(c.customerName ?? '').includes(q) ||
|
||||
(c.bankName ?? '').includes(q) ||
|
||||
(c.sayadId ?? '').includes(q),
|
||||
)
|
||||
}
|
||||
return list
|
||||
})
|
||||
const invoiceCount = computed(() => new Set(checkList.value.map((check) => check.orderId)).size)
|
||||
|
||||
const pendingCount = computed(
|
||||
() => checkList.value.filter((c) => c.status === 'pending_review').length,
|
||||
() => checkList.value.filter((check) => check.status === 'pending_review').length,
|
||||
)
|
||||
|
||||
const groups = computed(() => buildGroups())
|
||||
|
||||
function metaFromOrder(order: ApiOrder): OrderCheckMeta {
|
||||
return {
|
||||
orderNumber: order.orderNumber,
|
||||
customerName: order.customerName,
|
||||
invoiceAmount: order.finalAmount ?? order.totalAmount ?? null,
|
||||
rassDate: order.checkRassDate ?? null,
|
||||
rassDays: order.checkRassDays ?? null,
|
||||
goods: (order.items ?? []).map((item) => ({
|
||||
productName: item.productName,
|
||||
color: item.color,
|
||||
meterage: item.confirmedMeterage ?? item.requestedMeterage,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
function goodsLabel(goods: GoodsLine[]): string {
|
||||
if (!goods.length) return '—'
|
||||
const shown = goods.slice(0, 2).map((item) => {
|
||||
const name = [item.productName, item.color].filter(Boolean).join(' ')
|
||||
return item.meterage ? `${name} (${formatMeterage(item.meterage)})` : name
|
||||
})
|
||||
const rest = goods.length - shown.length
|
||||
if (rest > 0) return `${shown.join(' · ')} و ${toPersianDigits(rest)} قلم دیگر`
|
||||
return shown.join(' · ')
|
||||
}
|
||||
|
||||
function matchesQuery(check: Check, query: string): boolean {
|
||||
if (!query) return true
|
||||
const meta = orderMeta.value.get(check.orderId)
|
||||
const goods = (meta?.goods ?? []).map((item) => `${item.productName} ${item.color}`).join(' ')
|
||||
const haystack = [
|
||||
check.orderNumber,
|
||||
meta?.orderNumber,
|
||||
check.customerName,
|
||||
meta?.customerName,
|
||||
check.bankName,
|
||||
check.sayadId,
|
||||
goods,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
return haystack.includes(query.toLowerCase())
|
||||
}
|
||||
|
||||
function buildGroups(): CheckGroup[] {
|
||||
const byOrder = new Map<string, Check[]>()
|
||||
for (const check of checkList.value) {
|
||||
const list = byOrder.get(check.orderId) ?? []
|
||||
list.push(check)
|
||||
byOrder.set(check.orderId, list)
|
||||
}
|
||||
|
||||
const query = searchQuery.value.trim()
|
||||
const result: CheckGroup[] = []
|
||||
|
||||
for (const [orderId, checks] of byOrder) {
|
||||
const visible = checks.some((check) => {
|
||||
if (statusFilter.value !== 'all' && check.status !== statusFilter.value) return false
|
||||
return matchesQuery(check, query)
|
||||
})
|
||||
if (!visible) continue
|
||||
|
||||
const sorted = [...checks].sort((a, b) => a.row - b.row)
|
||||
const meta = orderMeta.value.get(orderId)
|
||||
const first = sorted[0]!
|
||||
const latestAt = Math.max(
|
||||
0,
|
||||
...sorted.map((check) => (check.createdAt ? new Date(check.createdAt).getTime() : 0)),
|
||||
)
|
||||
|
||||
result.push({
|
||||
orderId,
|
||||
customerName: first.customerName || meta?.customerName || '',
|
||||
orderNumber: first.orderNumber || meta?.orderNumber || '',
|
||||
invoiceAmount: meta?.invoiceAmount ?? null,
|
||||
rassDate: meta?.rassDate ?? null,
|
||||
rassDays: meta?.rassDays ?? null,
|
||||
goodsLabel: goodsLabel(meta?.goods ?? []),
|
||||
totalCheckAmount: sorted.reduce((sum, check) => sum + check.amount, 0),
|
||||
hasPending: sorted.some((check) => check.status === 'pending_review'),
|
||||
latestAt,
|
||||
checks: sorted,
|
||||
})
|
||||
}
|
||||
|
||||
result.sort((a, b) => {
|
||||
if (a.hasPending !== b.hasPending) return a.hasPending ? -1 : 1
|
||||
return b.latestAt - a.latestAt
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
function rassLabel(group: CheckGroup): string {
|
||||
if (group.rassDate) return formatDate(group.rassDate)
|
||||
if (group.rassDays != null) return `${formatNumber(group.rassDays)} روز`
|
||||
return '—'
|
||||
}
|
||||
|
||||
function invoiceLabel(group: CheckGroup): string {
|
||||
return group.invoiceAmount != null ? formatCurrency(group.invoiceAmount) : '—'
|
||||
}
|
||||
|
||||
function isGroupOpen(orderId: string) {
|
||||
return openGroups.value[orderId] === true
|
||||
}
|
||||
|
||||
function toggleGroup(orderId: string) {
|
||||
openGroups.value = {
|
||||
...openGroups.value,
|
||||
[orderId]: !openGroups.value[orderId],
|
||||
}
|
||||
}
|
||||
|
||||
function groupBadgeStatus(group: CheckGroup) {
|
||||
if (group.checks.some((check) => check.status === 'pending_review')) return 'pending_check_review'
|
||||
if (group.checks.some((check) => check.status === 'rejected')) return 'needs_correction'
|
||||
return 'final_approval'
|
||||
}
|
||||
|
||||
function checkBadgeStatus(status: Check['status']) {
|
||||
if (status === 'approved') return 'final_approval'
|
||||
if (status === 'rejected') return 'needs_correction'
|
||||
return 'pending_check_review'
|
||||
}
|
||||
|
||||
async function loadChecksFromOrders() {
|
||||
const orders = await ordersApi.list()
|
||||
checkList.value = orders.flatMap((order) =>
|
||||
(order.checks ?? []).map((check) => ({
|
||||
...check,
|
||||
orderNumber: order.orderNumber,
|
||||
customerName: order.customerName,
|
||||
orderStatus: order.status,
|
||||
settlementType: order.settlementMethod ?? order.settlementType ?? null,
|
||||
})),
|
||||
)
|
||||
function checkImage(check: Check): string | null {
|
||||
return check.frontImage || check.backImage || null
|
||||
}
|
||||
|
||||
function openOrderDetail(orderId: string) {
|
||||
router.push({ name: 'orders', query: { order: orderId, from: 'checks' } })
|
||||
}
|
||||
|
||||
async function loadChecks() {
|
||||
loading.value = true
|
||||
try {
|
||||
checkList.value = await checksApi.list()
|
||||
} catch {
|
||||
try {
|
||||
await loadChecksFromOrders()
|
||||
} catch (err) {
|
||||
toast.error(err instanceof ApiError ? err.message : 'بارگذاری چکها انجام نشد.')
|
||||
const [checksResult, ordersResult] = await Promise.allSettled([
|
||||
checksApi.list(),
|
||||
ordersApi.list(),
|
||||
])
|
||||
|
||||
const orders = ordersResult.status === 'fulfilled' ? ordersResult.value : []
|
||||
const meta = new Map<string, OrderCheckMeta>()
|
||||
for (const order of orders) meta.set(order.id, metaFromOrder(order))
|
||||
orderMeta.value = meta
|
||||
|
||||
if (checksResult.status === 'fulfilled') {
|
||||
checkList.value = checksResult.value.map((check) => {
|
||||
const info = meta.get(check.orderId)
|
||||
if (!info) return check
|
||||
return {
|
||||
...check,
|
||||
orderNumber: check.orderNumber || info.orderNumber,
|
||||
customerName: check.customerName || info.customerName,
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (ordersResult.status === 'fulfilled') {
|
||||
checkList.value = orders.flatMap((order) =>
|
||||
(order.checks ?? []).map((check) => ({
|
||||
...check,
|
||||
orderNumber: order.orderNumber,
|
||||
customerName: order.customerName,
|
||||
orderStatus: order.status,
|
||||
settlementType: order.settlementMethod ?? order.settlementType ?? null,
|
||||
})),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const err = checksResult.reason
|
||||
toast.error(err instanceof ApiError ? err.message : 'بارگذاری چکها انجام نشد.')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -87,15 +251,11 @@ onMounted(() => {
|
||||
void loadChecks()
|
||||
})
|
||||
|
||||
function openOrderChecks(check: Check) {
|
||||
router.push(`/orders/${check.orderId}/checks`)
|
||||
}
|
||||
|
||||
async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
busyId.value = check.id
|
||||
try {
|
||||
const updated = await checksApi.updateStatus(check.id, { status })
|
||||
const index = checkList.value.findIndex((c) => c.id === check.id)
|
||||
const index = checkList.value.findIndex((item) => item.id === check.id)
|
||||
if (index !== -1) {
|
||||
checkList.value[index] = {
|
||||
...checkList.value[index]!,
|
||||
@@ -122,8 +282,9 @@ async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
<h1 class="admin-page-header__title">چکها</h1>
|
||||
</div>
|
||||
<div class="checks-list-page__summary">
|
||||
<span>{{ checkList.length }} چک</span>
|
||||
<span v-if="pendingCount">{{ pendingCount }} در انتظار بررسی</span>
|
||||
<span>{{ toPersianDigits(invoiceCount) }} فاکتور</span>
|
||||
<span>{{ toPersianDigits(checkList.length) }} چک</span>
|
||||
<span v-if="pendingCount">{{ toPersianDigits(pendingCount) }} در انتظار بررسی</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,7 +295,7 @@ async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
v-model="searchQuery"
|
||||
type="search"
|
||||
class="checks-list-page__search-input"
|
||||
placeholder="جستجو در شماره سفارش، مشتری، بانک، صیاد..."
|
||||
placeholder="جستجو در شماره فاکتور، مشتری، جنس، بانک، صیاد..."
|
||||
/>
|
||||
</div>
|
||||
<AdminSelect
|
||||
@@ -147,126 +308,143 @@ async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
|
||||
<AdminPageSkeleton v-if="loading" variant="table" />
|
||||
<template v-else>
|
||||
<div class="checks-list-page__table admin-card desktop-only">
|
||||
<div class="admin-table-wrap">
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>شماره سفارش</th>
|
||||
<th>مشتری</th>
|
||||
<th>ردیف</th>
|
||||
<th>مبلغ</th>
|
||||
<th>بانک</th>
|
||||
<th>شناسه صیادی</th>
|
||||
<th>سررسید</th>
|
||||
<th>وضعیت</th>
|
||||
<th>عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="check in filteredChecks" :key="check.id">
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
class="checks-list-page__order-link"
|
||||
@click="openOrderChecks(check)"
|
||||
>
|
||||
{{ check.orderNumber || check.orderId }}
|
||||
</button>
|
||||
</td>
|
||||
<td>{{ check.customerName || '—' }}</td>
|
||||
<td>{{ check.row }}</td>
|
||||
<td>{{ formatCurrency(check.amount) }}</td>
|
||||
<td>{{ check.bankName || '—' }}</td>
|
||||
<td dir="ltr">{{ check.sayadId || '—' }}</td>
|
||||
<td>{{ check.dueDate.slice(0, 10) }}</td>
|
||||
<td><StatusBadge :status="checkBadgeStatus(check.status)" /></td>
|
||||
<td>
|
||||
<div class="admin-action-group">
|
||||
<template v-if="check.status === 'pending_review'">
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-success admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'approved')"
|
||||
>
|
||||
تأیید
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-danger admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'rejected')"
|
||||
>
|
||||
رد
|
||||
</button>
|
||||
</template>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline admin-btn--xs"
|
||||
@click="openOrderChecks(check)"
|
||||
>
|
||||
جزئیات سفارش
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p v-if="!filteredChecks.length" class="checks-list-page__empty">
|
||||
چکی با این فیلتر یافت نشد.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="compact-only admin-card-list">
|
||||
<article v-for="check in filteredChecks" :key="check.id" class="admin-card-item">
|
||||
<div class="admin-card-item__header">
|
||||
<p class="admin-card-item__title">
|
||||
{{ check.orderNumber || check.orderId }} — چک {{ check.row }}
|
||||
</p>
|
||||
<StatusBadge :status="checkBadgeStatus(check.status)" />
|
||||
</div>
|
||||
<div class="admin-card-item__meta">
|
||||
<span>{{ check.customerName || '—' }}</span>
|
||||
<span>{{ formatCurrency(check.amount) }}</span>
|
||||
<span>{{ check.bankName || '—' }}</span>
|
||||
<span>سررسید {{ check.dueDate.slice(0, 10) }}</span>
|
||||
<span v-if="check.createdAt">ثبت {{ formatDateTime(check.createdAt) }}</span>
|
||||
</div>
|
||||
<div class="admin-card-item__actions">
|
||||
<template v-if="check.status === 'pending_review'">
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-success admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'approved')"
|
||||
>
|
||||
تأیید
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-danger admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'rejected')"
|
||||
>
|
||||
رد
|
||||
</button>
|
||||
</template>
|
||||
<div v-if="groups.length" class="check-groups">
|
||||
<article
|
||||
v-for="group in groups"
|
||||
:key="group.orderId"
|
||||
class="check-group admin-card"
|
||||
:class="{ 'is-open': isGroupOpen(group.orderId) }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline admin-btn--xs"
|
||||
@click="openOrderChecks(check)"
|
||||
class="check-group__detail"
|
||||
aria-label="جزئیات سفارش"
|
||||
title="جزئیات سفارش"
|
||||
@click.stop="openOrderDetail(group.orderId)"
|
||||
>
|
||||
جزئیات سفارش
|
||||
<AdminIcon name="eye" :size="18" />
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
<p v-if="!filteredChecks.length" class="checks-list-page__empty">
|
||||
چکی با این فیلتر یافت نشد.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="check-group__summary"
|
||||
:aria-expanded="isGroupOpen(group.orderId)"
|
||||
@click="toggleGroup(group.orderId)"
|
||||
>
|
||||
<AdminIcon
|
||||
class="check-group__chevron"
|
||||
:name="isGroupOpen(group.orderId) ? 'chevron-down' : 'chevron-left'"
|
||||
:size="16"
|
||||
/>
|
||||
<strong class="check-group__summary-name">{{ group.customerName || '—' }}</strong>
|
||||
<span class="check-group__summary-invoice">{{ group.orderNumber || '—' }}</span>
|
||||
<span class="check-group__summary-meta">{{ toPersianDigits(group.checks.length) }} چک</span>
|
||||
<span class="check-group__summary-meta">{{ formatCurrency(group.totalCheckAmount) }}</span>
|
||||
<span class="check-group__summary-meta">راس {{ rassLabel(group) }}</span>
|
||||
<StatusBadge :status="groupBadgeStatus(group)" />
|
||||
</button>
|
||||
<div v-if="isGroupOpen(group.orderId)" class="check-group__body">
|
||||
<header class="check-group__head">
|
||||
<div class="check-group__col">
|
||||
<div class="check-group__field">
|
||||
<span>نام مشتری</span>
|
||||
<strong>{{ group.customerName || '—' }}</strong>
|
||||
</div>
|
||||
<div class="check-group__field">
|
||||
<span>شماره فاکتور</span>
|
||||
<strong class="check-group__ltr">{{ group.orderNumber || '—' }}</strong>
|
||||
</div>
|
||||
<div class="check-group__field">
|
||||
<span>جنس سفارش</span>
|
||||
<strong>{{ group.goodsLabel }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="check-group__col">
|
||||
<div class="check-group__field">
|
||||
<span>مبلغ فاکتور</span>
|
||||
<strong>{{ invoiceLabel(group) }}</strong>
|
||||
</div>
|
||||
<div class="check-group__field">
|
||||
<span>مبلغ مجموع چکها</span>
|
||||
<strong>{{ formatCurrency(group.totalCheckAmount) }}</strong>
|
||||
</div>
|
||||
<div class="check-group__field">
|
||||
<span>راس چکها</span>
|
||||
<strong>{{ rassLabel(group) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="check-lines">
|
||||
<div class="check-line check-line--head" aria-hidden="true">
|
||||
<span>ردیف</span>
|
||||
<span>مبلغ</span>
|
||||
<span>سررسید</span>
|
||||
<span>عکس</span>
|
||||
<span>وضعیت</span>
|
||||
<span>عملیات</span>
|
||||
</div>
|
||||
|
||||
<div v-for="check in group.checks" :key="check.id" class="check-line">
|
||||
<span class="check-line__row">{{ toPersianDigits(check.row) }}</span>
|
||||
<span class="check-line__amount">
|
||||
<strong>{{ formatCurrency(check.amount) }}</strong>
|
||||
<small v-if="check.bankName">{{ check.bankName }}</small>
|
||||
</span>
|
||||
<span class="check-line__due">
|
||||
<strong>{{ formatDate(check.dueDate) }}</strong>
|
||||
<small v-if="check.sayadId" class="check-line__sayad">{{ check.sayadId }}</small>
|
||||
</span>
|
||||
<button
|
||||
v-if="checkImage(check)"
|
||||
type="button"
|
||||
class="check-line__photo"
|
||||
aria-label="عکس چک"
|
||||
@click="previewImage = checkImage(check)"
|
||||
>
|
||||
<img :src="checkImage(check)!" alt="" />
|
||||
</button>
|
||||
<span v-else class="check-line__photo check-line__photo--empty" aria-hidden="true"></span>
|
||||
<div class="check-line__foot">
|
||||
<span class="check-line__status">
|
||||
<StatusBadge :status="checkBadgeStatus(check.status)" />
|
||||
</span>
|
||||
<div class="check-line__actions">
|
||||
<template v-if="check.status === 'pending_review'">
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-success admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'approved')"
|
||||
>
|
||||
تأیید
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline-danger admin-btn--xs"
|
||||
:disabled="busyId === check.id"
|
||||
@click="updateCheckStatus(check, 'rejected')"
|
||||
>
|
||||
رد
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<p v-else class="checks-list-page__empty admin-card">چکی با این فیلتر یافت نشد.</p>
|
||||
</template>
|
||||
|
||||
<Teleport to="body">
|
||||
<div v-if="previewImage" class="checks-list-page__lightbox" @click.self="previewImage = null">
|
||||
<button type="button" class="checks-list-page__lightbox-close" @click="previewImage = null">
|
||||
بستن
|
||||
</button>
|
||||
<img :src="previewImage" alt="عکس چک" />
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -316,22 +494,236 @@ async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.checks-list-page__table {
|
||||
padding: 0;
|
||||
.check-groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.check-group {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
container-type: inline-size;
|
||||
container-name: check-group;
|
||||
}
|
||||
|
||||
.check-group__head {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: 12px 28px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background: color-mix(in srgb, var(--color-primary-soft) 70%, var(--color-surface));
|
||||
}
|
||||
|
||||
.check-group__col {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.check-group__field {
|
||||
display: grid;
|
||||
grid-template-columns: 8.25rem minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
align-items: start;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.check-group__field > span {
|
||||
color: var(--color-text-muted);
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.check-group__field strong {
|
||||
min-width: 0;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.check-group__ltr {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.check-group__summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 16px;
|
||||
width: 100%;
|
||||
min-height: 52px;
|
||||
padding: 10px 14px 10px 52px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
text-align: start;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.check-group.is-open .check-group__summary {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background: color-mix(in srgb, var(--color-primary-soft) 45%, var(--color-surface));
|
||||
}
|
||||
|
||||
.check-group__chevron {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.check-group__summary-name {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.check-group__summary-invoice {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.check-group__summary-meta {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.check-group__detail {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 8px;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.check-group__detail:hover {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.check-lines {
|
||||
display: grid;
|
||||
grid-template-columns: 3rem repeat(5, minmax(0, 1fr));
|
||||
column-gap: 16px;
|
||||
}
|
||||
|
||||
.check-line {
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
grid-column: 1 / -1;
|
||||
align-items: center;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
}
|
||||
|
||||
.check-line:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.check-line--head {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-border-light);
|
||||
}
|
||||
|
||||
.check-line--head > span {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.check-line__row {
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.check-line__amount,
|
||||
.check-line__due {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.checks-list-page__order-link {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--color-primary);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
.check-line__amount strong,
|
||||
.check-line__due strong {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.checks-list-page__order-link:hover {
|
||||
text-decoration: underline;
|
||||
.check-line__amount small,
|
||||
.check-line__due small {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.check-line__sayad {
|
||||
display: block;
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.check-line__photo {
|
||||
width: 48px;
|
||||
height: 34px;
|
||||
justify-self: start;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--color-border);
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
background: var(--color-border-light);
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.check-line__photo img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.check-line__photo--empty {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.check-line__foot {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.check-line__actions {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 6px;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.check-line__actions .admin-btn {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.check-line__status {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.check-line__status :deep(.admin-badge) {
|
||||
max-width: 100%;
|
||||
white-space: normal;
|
||||
line-height: 1.35;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.checks-list-page__empty {
|
||||
@@ -341,4 +733,110 @@ async function updateCheckStatus(check: Check, status: Check['status']) {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.checks-list-page__lightbox {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 300000;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: rgba(0, 0, 0, 0.84);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.checks-list-page__lightbox img {
|
||||
max-width: min(900px, 100%);
|
||||
max-height: 88vh;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.checks-list-page__lightbox-close {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
inset-inline-end: 14px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@container check-group (max-width: 760px) {
|
||||
.check-lines {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.check-line--head {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.check-line:not(.check-line--head) {
|
||||
grid-column: auto;
|
||||
grid-template-columns: 1.75rem minmax(0, 1fr) 48px;
|
||||
grid-template-areas:
|
||||
'row amount photo'
|
||||
'due due photo'
|
||||
'foot foot foot';
|
||||
row-gap: 6px;
|
||||
column-gap: 10px;
|
||||
align-items: center;
|
||||
padding-inline: 16px;
|
||||
}
|
||||
|
||||
.check-line__foot {
|
||||
display: flex;
|
||||
grid-area: foot;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.check-line__row {
|
||||
grid-area: row;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.check-line__amount {
|
||||
grid-area: amount;
|
||||
}
|
||||
|
||||
.check-line__due {
|
||||
grid-area: due;
|
||||
}
|
||||
|
||||
.check-line__photo {
|
||||
grid-area: photo;
|
||||
justify-self: end;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.check-line__actions {
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@container check-group (max-width: 640px) {
|
||||
.check-group__head {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@container check-group (max-width: 420px) {
|
||||
.check-group__summary {
|
||||
padding: 10px 12px 10px 48px;
|
||||
}
|
||||
|
||||
.check-line {
|
||||
padding-inline: 12px;
|
||||
}
|
||||
|
||||
.check-group__field {
|
||||
grid-template-columns: 6.25rem minmax(0, 1fr);
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,6 +25,7 @@ const {
|
||||
openOrderDetail,
|
||||
closeDetailPanel,
|
||||
closeDetailModal,
|
||||
dismissOrderDetail,
|
||||
settlementLabel,
|
||||
goPricing,
|
||||
goChecks,
|
||||
@@ -214,7 +215,7 @@ function handleFinalApprove() {
|
||||
type="button"
|
||||
class="admin-detail-panel__back"
|
||||
aria-label="بازگشت به لیست"
|
||||
@click="closeDetailPanel"
|
||||
@click="dismissOrderDetail"
|
||||
>
|
||||
<AdminIcon name="chevron-back" :size="20" />
|
||||
</button>
|
||||
@@ -240,7 +241,7 @@ function handleFinalApprove() {
|
||||
:open="isCompactLayout && !isMobile && showDetailModal && !!selectedOrder"
|
||||
title="جزئیات سفارش"
|
||||
size="xl"
|
||||
@close="closeDetailModal"
|
||||
@close="dismissOrderDetail"
|
||||
>
|
||||
<template v-if="selectedOrder">
|
||||
<OrderDetailContent
|
||||
|
||||
@@ -23,6 +23,7 @@ const {
|
||||
showDetailModal,
|
||||
openOrderDetail,
|
||||
closeDetailModal,
|
||||
dismissOrderDetail,
|
||||
settlementLabel,
|
||||
goPricing,
|
||||
goChecks,
|
||||
@@ -303,7 +304,7 @@ function runMenuAction(action: 'detail' | 'pricing' | 'checks' | 'cash' | 'final
|
||||
:open="isDesktopLayout && showDetailModal && !!selectedOrder"
|
||||
title="جزئیات سفارش"
|
||||
size="xl"
|
||||
@close="closeDetailModal"
|
||||
@close="dismissOrderDetail"
|
||||
>
|
||||
<template v-if="selectedOrder">
|
||||
<OrderDetailContent
|
||||
|
||||
+142
-149
@@ -14,7 +14,6 @@ import { useToast } from '@/composables/useToast'
|
||||
import { confirm } from '@/composables/useConfirm'
|
||||
import { formatCurrency, formatNumber } from '@/utils/format'
|
||||
import type { Company, Product } from '@/types'
|
||||
import AdminCurrencyInput from '@/components/ui/AdminCurrencyInput.vue'
|
||||
import { toCssBackgroundUrl } from '@/utils/catalogImage'
|
||||
import {
|
||||
PAYMENT_RECIPIENT_COMPANY_SLUG,
|
||||
@@ -64,18 +63,15 @@ const companyFormOptions = computed(() => {
|
||||
const emptyForm = () => ({
|
||||
companyId: '',
|
||||
name: '',
|
||||
color: '',
|
||||
productCode: '',
|
||||
minMeterage: 100,
|
||||
orderStep: 50,
|
||||
price: null as number | null,
|
||||
internalStock: 0,
|
||||
widthCm: null as number | null,
|
||||
weightGrams: null as number | null,
|
||||
inStock: true,
|
||||
isActive: true,
|
||||
usageCategory: 'other',
|
||||
season: 'all_season',
|
||||
composition: '',
|
||||
weaveType: '',
|
||||
subtitle: '',
|
||||
specs: '',
|
||||
rollMeters: 50,
|
||||
isNew: false,
|
||||
@@ -91,7 +87,7 @@ const form = reactive(emptyForm())
|
||||
|
||||
const isModalOpen = computed(() => modalMode.value !== null)
|
||||
const modalTitle = computed(() => (modalMode.value === 'edit' ? 'ویرایش محصول' : 'افزودن محصول'))
|
||||
const isFormValid = computed(() => form.name.trim() && form.minMeterage > 0)
|
||||
const isFormValid = computed(() => form.name.trim().length > 0 && form.rollMeters > 0)
|
||||
const hasActiveFilters = computed(
|
||||
() => searchQuery.value.trim().length > 0 || companyFilter.value !== 'all',
|
||||
)
|
||||
@@ -167,18 +163,15 @@ async function openEditModal(product: Product) {
|
||||
}
|
||||
form.companyId = productCompanyIdForForm(product.companyId, companies.value)
|
||||
form.name = product.name
|
||||
form.color = product.color
|
||||
form.productCode = product.productCode
|
||||
form.minMeterage = product.minMeterage
|
||||
form.orderStep = product.orderStep
|
||||
form.price = product.price
|
||||
form.internalStock = product.internalStock
|
||||
form.widthCm = product.widthCm ?? null
|
||||
form.weightGrams = product.weightGrams ?? null
|
||||
form.inStock = product.internalStock == null || product.internalStock > 0
|
||||
form.isActive = product.isActive
|
||||
form.usageCategory = (product as { usageCategory?: string }).usageCategory ?? 'other'
|
||||
form.season = (product as { season?: string }).season ?? 'all_season'
|
||||
form.composition = (product as { composition?: string }).composition ?? ''
|
||||
form.weaveType = (product as { weaveType?: string }).weaveType ?? ''
|
||||
form.subtitle = (product as { subtitle?: string }).subtitle ?? ''
|
||||
form.specs = (product as { specs?: string }).specs ?? ''
|
||||
form.rollMeters = (product as { rollMeters?: number }).rollMeters ?? 50
|
||||
form.isNew = (product as { isNew?: boolean }).isNew ?? false
|
||||
@@ -246,10 +239,7 @@ function buildProductMedia() {
|
||||
|
||||
form.colorRows.forEach((row, index) => {
|
||||
const imageUrl = row.imageUrl.trim() || undefined
|
||||
const name =
|
||||
row.name.trim() ||
|
||||
(index === 0 ? form.color.trim() : '') ||
|
||||
(imageUrl ? `رنگ ${index + 1}` : '')
|
||||
const name = row.name.trim() || (imageUrl ? `رنگ ${index + 1}` : '')
|
||||
if (!name && !imageUrl) return
|
||||
if (!name) return
|
||||
colorEntries.push({
|
||||
@@ -270,7 +260,7 @@ function closeModal() {
|
||||
|
||||
async function submitProduct() {
|
||||
if (!isFormValid.value) {
|
||||
formError.value = 'نام محصول و حداقل متراژ الزامی هستند.'
|
||||
formError.value = 'نام محصول و متراژ هر طاقه الزامی هستند.'
|
||||
return
|
||||
}
|
||||
|
||||
@@ -284,32 +274,39 @@ async function submitProduct() {
|
||||
}
|
||||
|
||||
const { colorEntries, imageUrls } = buildProductMedia()
|
||||
const rollMeters = form.rollMeters
|
||||
const catalogPayload = {
|
||||
usageCategory: form.usageCategory,
|
||||
season: form.season,
|
||||
composition: form.composition.trim() || null,
|
||||
weaveType: form.weaveType.trim() || null,
|
||||
subtitle: form.subtitle.trim() || null,
|
||||
specs: form.specs.trim() || undefined,
|
||||
rollMeters: form.rollMeters,
|
||||
rollMeters,
|
||||
widthCm: form.widthCm,
|
||||
weightGrams: form.weightGrams,
|
||||
isNew: form.isNew,
|
||||
colorsJson: colorEntries,
|
||||
imageUrlsJson: imageUrls,
|
||||
}
|
||||
const productCode = form.productCode.trim() || `PRD-${Date.now()}`
|
||||
const colorLabel = colorEntries[0]?.name || '—'
|
||||
const meteragePayload = {
|
||||
minMeterage: rollMeters,
|
||||
orderStep: rollMeters,
|
||||
orderMultiplier: rollMeters,
|
||||
}
|
||||
const stockPayload = { internalStock: form.inStock ? null : 0 }
|
||||
saving.value = true
|
||||
try {
|
||||
if (modalMode.value === 'edit' && editingId.value) {
|
||||
await productsApi.update(editingId.value, {
|
||||
companyId: companyIdPayload,
|
||||
name: form.name.trim(),
|
||||
color: form.color.trim() || colorEntries[0]?.name || '—',
|
||||
color: colorLabel,
|
||||
code: productCode,
|
||||
productCode,
|
||||
minMeterage: form.minMeterage,
|
||||
orderStep: form.orderStep,
|
||||
price: form.price,
|
||||
internalStock: form.internalStock,
|
||||
...meteragePayload,
|
||||
...stockPayload,
|
||||
isActive: form.isActive,
|
||||
...catalogPayload,
|
||||
})
|
||||
@@ -321,13 +318,11 @@ async function submitProduct() {
|
||||
const created = await productsApi.create({
|
||||
companyId: companyIdPayload,
|
||||
name: form.name.trim(),
|
||||
color: form.color.trim() || colorEntries[0]?.name || '—',
|
||||
color: colorLabel,
|
||||
code: productCode,
|
||||
productCode,
|
||||
minMeterage: form.minMeterage,
|
||||
orderStep: form.orderStep,
|
||||
price: form.price,
|
||||
internalStock: form.internalStock,
|
||||
...meteragePayload,
|
||||
...stockPayload,
|
||||
isActive: form.isActive,
|
||||
...catalogPayload,
|
||||
})
|
||||
@@ -524,120 +519,9 @@ function clearFilters() {
|
||||
<p v-if="formError" class="admin-form__error" role="alert">{{ formError }}</p>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label>شرکت مرتبط با محصول</label>
|
||||
<AdminSelect
|
||||
v-model="form.companyId"
|
||||
block
|
||||
aria-label="انتخاب شرکت مرتبط با محصول"
|
||||
placeholder="نادمی تکس (پیشفرض)"
|
||||
:options="companyFormOptions"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-name">نام محصول <span class="admin-form__required">*</span></label>
|
||||
<input id="product-name" v-model="form.name" type="text" class="admin-input" />
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-color">رنگ / نوع</label>
|
||||
<input id="product-color" v-model="form.color" type="text" class="admin-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-code">کد محصول</label>
|
||||
<input id="product-code" v-model="form.productCode" type="text" class="admin-input" dir="ltr" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-min">حداقل متراژ</label>
|
||||
<input id="product-min" v-model.number="form.minMeterage" type="number" min="1" class="admin-input" />
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-step">ضریب سفارش</label>
|
||||
<input id="product-step" v-model.number="form.orderStep" type="number" min="1" class="admin-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-price">قیمت هر متر (تومان)</label>
|
||||
<AdminCurrencyInput id="product-price" v-model="form.price" placeholder="مثلاً ۲۵۰٬۰۰۰" />
|
||||
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-stock">موجودی داخلی (متر)</label>
|
||||
<input id="product-stock" v-model.number="form.internalStock" type="number" min="0" class="admin-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-usage">کاربرد</label>
|
||||
<AdminSelect
|
||||
id="product-usage"
|
||||
v-model="form.usageCategory"
|
||||
block
|
||||
aria-label="کاربرد محصول"
|
||||
placeholder="انتخاب کاربرد"
|
||||
:options="usageOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-season">فصل</label>
|
||||
<AdminSelect
|
||||
id="product-season"
|
||||
v-model="form.season"
|
||||
block
|
||||
aria-label="فصل محصول"
|
||||
placeholder="انتخاب فصل"
|
||||
:options="seasonOptions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-composition">جنس / ترکیب</label>
|
||||
<input id="product-composition" v-model="form.composition" type="text" class="admin-input" />
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-weave">نوع بافت</label>
|
||||
<input id="product-weave" v-model="form.weaveType" type="text" class="admin-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-subtitle">زیرعنوان</label>
|
||||
<input id="product-subtitle" v-model="form.subtitle" type="text" class="admin-input" />
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-roll">متراژ طاقه</label>
|
||||
<input id="product-roll" v-model.number="form.rollMeters" type="number" min="1" class="admin-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-specs">مشخصات محصول</label>
|
||||
<p class="admin-form__hint">
|
||||
متن آزاد؛ در بخش «مشاهده همه مشخصات» صفحه محصول در اپ نمایش داده میشود.
|
||||
</p>
|
||||
<textarea
|
||||
id="product-specs"
|
||||
v-model="form.specs"
|
||||
class="admin-form__textarea"
|
||||
rows="5"
|
||||
placeholder="مثلاً جنس، عرض، وزن و نکات نگهداری — هر خط یک بند"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label>تصاویر عمومی محصول</label>
|
||||
<label>عکس اسلایدی محصول</label>
|
||||
<p class="color-variants__hint">
|
||||
فقط برای گالری اصلی در اپ کاربر (بدون وابستگی به رنگ). با «ثبت تغییرات» ثبت میشود.
|
||||
تصاویر گالری اصلی در اپ کاربر. با «ثبت محصول» یا «ثبت تغییرات» ذخیره میشود.
|
||||
</p>
|
||||
<div class="general-images">
|
||||
<div
|
||||
@@ -645,7 +529,7 @@ function clearFilters() {
|
||||
:key="`general-${gIdx}`"
|
||||
class="product-media-row"
|
||||
role="group"
|
||||
:aria-label="`تصویر عمومی ${gIdx + 1}`"
|
||||
:aria-label="`تصویر اسلاید ${gIdx + 1}`"
|
||||
>
|
||||
<AdminImagePicker
|
||||
compact
|
||||
@@ -664,15 +548,75 @@ function clearFilters() {
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="admin-btn admin-btn--outline product-media-add" @click="addGeneralImageSlot">
|
||||
+ افزودن تصویر عمومی
|
||||
+ افزودن تصویر اسلاید
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label>رنگبندیها</label>
|
||||
<label for="product-name">نام محصول <span class="admin-form__required">*</span></label>
|
||||
<input id="product-name" v-model="form.name" type="text" class="admin-input" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-code">کد محصول</label>
|
||||
<input id="product-code" v-model="form.productCode" type="text" class="admin-input" dir="ltr" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-width">عرض (سانتیمتر)</label>
|
||||
<input
|
||||
id="product-width"
|
||||
v-model.number="form.widthCm"
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.1"
|
||||
class="admin-input"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-weight">وزن (گرم)</label>
|
||||
<input
|
||||
id="product-weight"
|
||||
v-model.number="form.weightGrams"
|
||||
type="number"
|
||||
min="0"
|
||||
step="1"
|
||||
class="admin-input"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-composition">جنس</label>
|
||||
<input id="product-composition" v-model="form.composition" type="text" class="admin-input" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-weave">نوع بافت</label>
|
||||
<input id="product-weave" v-model="form.weaveType" type="text" class="admin-input" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-specs">توضیح اضافه و تکمیلی برای مشخصه فنی</label>
|
||||
<p class="admin-form__hint">
|
||||
در بخش «مشاهده همه مشخصات» صفحه محصول در اپ نمایش داده میشود.
|
||||
</p>
|
||||
<textarea
|
||||
id="product-specs"
|
||||
v-model="form.specs"
|
||||
class="admin-form__textarea"
|
||||
rows="5"
|
||||
placeholder="نکات تکمیلی مشخصات فنی — هر خط یک بند"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label>رنگبندی</label>
|
||||
<p class="color-variants__hint">
|
||||
برای هر رنگ یک نام و یک تصویر بگذارید. تصویر رنگ در بخش رنگبندی اپ نمایش داده میشود، نه در گالری عمومی.
|
||||
برای هر رنگ یک نام و یک تصویر بگذارید. تصویر رنگ در بخش رنگبندی اپ نمایش داده میشود.
|
||||
</p>
|
||||
<div class="color-variants">
|
||||
<div
|
||||
@@ -711,12 +655,61 @@ function clearFilters() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__row">
|
||||
<div class="admin-form__field">
|
||||
<label for="product-usage">دستهبندی</label>
|
||||
<AdminSelect
|
||||
id="product-usage"
|
||||
v-model="form.usageCategory"
|
||||
block
|
||||
aria-label="دستهبندی محصول"
|
||||
placeholder="انتخاب دستهبندی"
|
||||
:options="usageOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="admin-form__field">
|
||||
<label for="product-season">فصل</label>
|
||||
<AdminSelect
|
||||
id="product-season"
|
||||
v-model="form.season"
|
||||
block
|
||||
aria-label="فصل محصول"
|
||||
placeholder="انتخاب فصل"
|
||||
:options="seasonOptions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="product-roll">متراژ هر طاقه <span class="admin-form__required">*</span></label>
|
||||
<p class="admin-form__hint">
|
||||
حداقل متراژ و ضریب سفارش بهصورت خودکار برابر با همین مقدار تنظیم میشود.
|
||||
</p>
|
||||
<input id="product-roll" v-model.number="form.rollMeters" type="number" min="1" class="admin-input" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<BaseSwitch v-model="form.inStock" label="موجود در انبار" />
|
||||
<p class="admin-form__hint">در صورت اتمام موجودی، خاموش کنید؛ نیازی به ثبت متراژ دقیق نیست.</p>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label>شرکت مرتبط با محصول</label>
|
||||
<AdminSelect
|
||||
v-model="form.companyId"
|
||||
block
|
||||
aria-label="انتخاب شرکت مرتبط با محصول"
|
||||
placeholder="نادمی تکس (پیشفرض)"
|
||||
:options="companyFormOptions"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<BaseSwitch v-model="form.isNew" label="محصول جدید" />
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<BaseSwitch v-model="form.isActive" label="وضعیت" />
|
||||
<BaseSwitch v-model="form.isActive" label="فعال در فروشگاه" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user