admin user and ui panel

This commit is contained in:
s.esmaeili
2026-09-21 08:32:31 +03:30
parent 79226c9f13
commit ef1d4638cc
341 changed files with 2270 additions and 657 deletions
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{d as f,o as v,c as s,k as e,q as u,g as m,h as p,i as o,F as g,r as y,I as k,b as P,f as C,s as b,J as h,v as x,_ as B}from"./index-CBZSLIgu.js";import{P as V}from"./PageBar-BrfQrql1.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-DQwH-Xdy.js";import{S as I}from"./SectionHead-QOHixgma.js";import{P as N}from"./ProductCard-Dj_Eu2VB.js";import{a as q}from"./client-CJxy5iKa.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-DssXZ7g8.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-BZS-5R5g.js";import"./DialogVant.vue_vue_type_style_index_0_lang-CINs34e0.js";import"./cartStore-CAFgxy6H.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-CUVFR_Bx.js";import"./classCallCheck-R2Fkn3Yh.js";const F={class:"coll"},S={key:0,class:"coll__grid"},z={key:1,class:"coll__empty"},E=f({__name:"CollectionView",setup(H){const l=h(),t=m(!1),n=m([]),d=p(()=>l.query.page||"مجموعه"),r=p(()=>n.value.filter(i=>i.collections.some(a=>a.collectionId===l.params.id)));return v(async()=>{t.value=!0;try{n.value=await q.listProducts()}finally{t.value=!1}}),(i,a)=>{const _=b("container");return o(),s("div",F,[e(V,{title:d.value,"back-to":"search"},null,8,["title"]),e(w,{spinning:t.value,tip:"درحال دریافت اطلاعات"},{default:u(()=>[e(_,{class:"coll__body"},{default:u(()=>[e(I,{title:"محصولات این مجموعه",subtitle:"برای دیدن جزئیات، روی محصول ضربه بزنید"}),r.value.length?(o(),s("div",S,[(o(!0),s(g,null,y(r.value,c=>(o(),x(N,{key:c.id,value:c},null,8,["value"]))),128))])):t.value?C("",!0):(o(),s("section",z,[e(k,{icon:"vuesax-linear:box",size:"26"}),a[0]||(a[0]=P("p",null,"در این مجموعه محصولی ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"])])}}}),W=B(E,[["__scopeId","data-v-4e05d52b"]]);export{W as default};
-1
View File
@@ -1 +0,0 @@
import{d as f,o as v,c as s,e,w as u,j as m,l as p,g as o,F as g,r as y,I as P,b as k,f as C,q as b,J as x,s as h,_ as w}from"./index-CXDP73fh.js";import{P as B}from"./PageBar-DGocjVpH.js";import{a as V}from"./Spinner.vue_vue_type_style_index_0_lang-Cw01MXb5.js";import{S as I}from"./SectionHead-BpYVXEql.js";import{P as N}from"./ProductCard-BLK42sSQ.js";import{a as q}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-c159xuqF.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-CJQoykcb.js";import"./DialogVant.vue_vue_type_style_index_0_lang-NTcY_W-M.js";import"./cartStore-DyCvrw6I.js";import"./dialogEmpty1-E3h_JfwQ.js";import"./index-BYO8JY_f.js";import"./classCallCheck-BI0ic3HN.js";const F={class:"coll"},S={key:0,class:"coll__grid"},j={key:1,class:"coll__empty"},z=f({__name:"CollectionView",setup(E){const l=x(),t=m(!1),n=m([]),d=p(()=>l.query.page||"مجموعه"),r=p(()=>n.value.filter(i=>i.collections.some(a=>a.collectionId===l.params.id)));return v(async()=>{t.value=!0;try{n.value=await q.listProducts()}finally{t.value=!1}}),(i,a)=>{const _=b("container");return o(),s("div",F,[e(B,{title:d.value,"back-to":"search"},null,8,["title"]),e(V,{spinning:t.value,tip:"درحال دریافت اطلاعات"},{default:u(()=>[e(_,{class:"coll__body"},{default:u(()=>[e(I,{title:"محصولات این مجموعه",subtitle:"برای دیدن جزئیات، روی محصول ضربه بزنید"}),r.value.length?(o(),s("div",S,[(o(!0),s(g,null,y(r.value,c=>(o(),h(N,{key:c.id,value:c},null,8,["value"]))),128))])):t.value?C("",!0):(o(),s("section",j,[e(P,{icon:"vuesax-linear:box",size:"26"}),a[0]||(a[0]=k("p",null,"در این مجموعه محصولی ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"])])}}}),W=w(z,[["__scopeId","data-v-4e05d52b"]]);export{W as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{d as l,v as n,q as r,u as d,ao as c,i as x,b as t,A as o,D as a,t as i}from"./index-CBZSLIgu.js";const f={class:"my-4"},u={class:"w-full flex justify-center"},m={class:"w-full flex justify-center text-[18px] font-semibold"},_={class:"grid grid-cols-2 border-t border-solid border-[#E5E7EB] pt-4 mx-2 mt-6 font-semibold text-[15px]"},g=l({__name:"DialogVant",props:{timeOut:{},text1:{},text2:{},text3:{}},setup(e){return(s,b)=>(x(),n(d(c),null,{default:r(()=>[t("div",f,[t("div",u,[o(s.$slots,"img",{},()=>[a(i(e.text2),1)])]),t("div",m,[o(s.$slots,"title",{},()=>[a(i(e.text1),1)])]),t("div",_,[o(s.$slots,"button",{},()=>[a(i(e.text3),1)])])])]),_:3}))}});export{g as _};
@@ -1 +0,0 @@
import{d as l,s as n,w as r,u as d,am as c,g as x,b as t,B as o,i as a,t as i}from"./index-CXDP73fh.js";const f={class:"my-4"},m={class:"w-full flex justify-center"},u={class:"w-full flex justify-center text-[18px] font-semibold"},_={class:"grid grid-cols-2 border-t border-solid border-[#E5E7EB] pt-4 mx-2 mt-6 font-semibold text-[15px]"},p=l({__name:"DialogVant",props:{timeOut:{},text1:{},text2:{},text3:{}},setup(e){return(s,b)=>(x(),n(d(c),null,{default:r(()=>[t("div",f,[t("div",m,[o(s.$slots,"img",{},()=>[a(i(e.text2),1)])]),t("div",u,[o(s.$slots,"title",{},()=>[a(i(e.text1),1)])]),t("div",_,[o(s.$slots,"button",{},()=>[a(i(e.text3),1)])])])]),_:3}))}});export{p as _};
-1
View File
@@ -1 +0,0 @@
import{d as v,o as b,c as o,e,w as c,j as m,g as t,F as p,b as i,r as g,I as y,u as k,f as P,x as h,l as C,q as x,s as F,_ as w}from"./index-CXDP73fh.js";import{P as B}from"./PageBar-DGocjVpH.js";import{a as V}from"./Spinner.vue_vue_type_style_index_0_lang-Cw01MXb5.js";import{S}from"./SectionHead-BpYVXEql.js";import{P as I}from"./ProductCard-BLK42sSQ.js";import{u as N}from"./SingleProduct-c159xuqF.js";import{a as $}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./cartStore-DyCvrw6I.js";import"./index-BYO8JY_f.js";import"./classCallCheck-BI0ic3HN.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-CJQoykcb.js";import"./DialogVant.vue_vue_type_style_index_0_lang-NTcY_W-M.js";import"./dialogEmpty1-E3h_JfwQ.js";const R={class:"favs"},j={class:"favs__grid"},q={key:1,class:"favs__empty"},z=v({__name:"FavoritesView",setup(E){const d=h(),_=N(),a=m(!1),l=m([]),r=C(()=>l.value.filter(u=>_.isFavorite(u.id)));return b(async()=>{a.value=!0;try{l.value=await $.listProducts()}finally{a.value=!1}}),(u,s)=>{const f=x("container");return t(),o("div",R,[e(B,{title:"علاقه‌مندی","back-to":"userPage::hasSubRoute"}),e(V,{spinning:a.value,tip:"در حال دریافت اطلاعات"},{default:c(()=>[e(f,{class:"favs__body"},{default:c(()=>[r.value.length?(t(),o(p,{key:0},[e(S,{title:"ذخیره‌شده‌ها",subtitle:`${r.value.length} محصول`},null,8,["subtitle"]),i("div",j,[(t(!0),o(p,null,g(r.value,n=>(t(),F(I,{key:n.id,value:n},null,8,["value"]))),128))])],64)):a.value?P("",!0):(t(),o("section",q,[e(y,{icon:"vuesax-linear:heart",size:"26"}),s[1]||(s[1]=i("p",null,"هنوز محصولی را به علاقه‌مندی‌ها اضافه نکرده‌اید.",-1)),i("button",{type:"button",class:"favs__emptyCta",onClick:s[0]||(s[0]=n=>k(d).push({name:"home"}))}," دیدن محصولات ")]))]),_:1})]),_:1},8,["spinning"])])}}}),Y=w(z,[["__scopeId","data-v-93bb7c6a"]]);export{Y as default};
+1
View File
@@ -0,0 +1 @@
import{d as f,o as b,c as o,k as e,q as c,g as m,i as t,F as p,b as i,r as g,I as y,u as k,f as h,x as P,h as C,s as x,v as F,_ as B}from"./index-CBZSLIgu.js";import{P as V}from"./PageBar-BrfQrql1.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-DQwH-Xdy.js";import{S}from"./SectionHead-QOHixgma.js";import{P as I}from"./ProductCard-Dj_Eu2VB.js";import{u as N}from"./SingleProduct-DssXZ7g8.js";import{a as $}from"./client-CJxy5iKa.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./cartStore-CAFgxy6H.js";import"./index-CUVFR_Bx.js";import"./classCallCheck-R2Fkn3Yh.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-BZS-5R5g.js";import"./DialogVant.vue_vue_type_style_index_0_lang-CINs34e0.js";import"./dialogEmpty1-Caw7F5KL.js";const R={class:"favs"},q={class:"favs__grid"},z={key:1,class:"favs__empty"},E=f({__name:"FavoritesView",setup(H){const d=P(),v=N(),a=m(!1),l=m([]),r=C(()=>l.value.filter(u=>v.isFavorite(u.id)));return b(async()=>{a.value=!0;try{l.value=await $.listProducts()}finally{a.value=!1}}),(u,s)=>{const _=x("container");return t(),o("div",R,[e(V,{title:"علاقه‌مندی","back-to":"userPage::hasSubRoute"}),e(w,{spinning:a.value,tip:"در حال دریافت اطلاعات"},{default:c(()=>[e(_,{class:"favs__body"},{default:c(()=>[r.value.length?(t(),o(p,{key:0},[e(S,{title:"ذخیره‌شده‌ها",subtitle:`${r.value.length} محصول`},null,8,["subtitle"]),i("div",q,[(t(!0),o(p,null,g(r.value,n=>(t(),F(I,{key:n.id,value:n},null,8,["value"]))),128))])],64)):a.value?h("",!0):(t(),o("section",z,[e(y,{icon:"vuesax-linear:heart",size:"26"}),s[1]||(s[1]=i("p",null,"هنوز محصولی را به علاقه‌مندی‌ها اضافه نکرده‌اید.",-1)),i("button",{type:"button",class:"favs__emptyCta",onClick:s[0]||(s[0]=n=>k(d).push({name:"home"}))}," دیدن محصولات ")]))]),_:1})]),_:1},8,["spinning"])])}}}),Y=B(E,[["__scopeId","data-v-93bb7c6a"]]);export{Y as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
import{P as x}from"./PageBar-DGocjVpH.js";import{E as P,a as _}from"./Spinner.vue_vue_type_style_index_0_lang-Cw01MXb5.js";import{S}from"./SectionHead-BpYVXEql.js";import{P as k}from"./ProductCard-BLK42sSQ.js";import{d,g as n,c as l,e as o,u as c,y as b,z as B,A as E,B as C,s as v,f as y,j as u,C as L,D as A,w as p,F as $,r as F,l as N,q as V,_ as D}from"./index-CXDP73fh.js";import{a as I}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-c159xuqF.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-CJQoykcb.js";import"./DialogVant.vue_vue_type_style_index_0_lang-NTcY_W-M.js";import"./cartStore-DyCvrw6I.js";import"./dialogEmpty1-E3h_JfwQ.js";import"./index-BYO8JY_f.js";import"./classCallCheck-BI0ic3HN.js";const j={class:"flex justify-center items-center empty"},z=d({__name:"EmptyState",props:{description:{},image:{}},setup(t){return(e,a)=>(n(),l("div",j,[o(c(P),{description:"موردی یافت نشد",image:t.image,class:"h-[200px] w-[200px] opacity-70"},null,8,["image"])]))}}),H="/assets/favoritEmpty-kbtPAdi5.svg",T=d({__name:"ScrollFetchSearch",props:{loading:{type:Boolean},flag:{type:Boolean},padding:{}},emits:["fetch"],setup(t,{emit:e}){const a=e,r=b(),s=u(null);return B(s,()=>{a("fetch")},{distance:50}),(i,m)=>(n(),l("main",{class:"flex flex-col flex-1 overflow-auto no-scrollbar w-[100vw] max-w-screen-md m-auto",style:E({paddingTop:t.padding||c(r).headerHeight+"px"}),ref_key:"scrollArea",ref:s},[C(i.$slots,"default"),o(_,{cls:"my-[10px]",spinning:t.loading,indicator:!0,tip:"درحال دریافت اطلاعات"},null,8,["spinning"]),t.flag?(n(),v(z,{key:0,image:c(H)},null,8,["image"])):y("",!0)],4))}});function q(){const t=L({totalPages:0,productList:[],flag:!1});return{productsData:t,getProducts:async(a,r=!1)=>{if(!r){a.value=!0;try{t.productList=await I.listProducts(),t.flag=t.productList.length<1}catch(s){console.log(s)}finally{a.value=!1}}}}}const G={class:"newest"},M={key:0,class:"newest__grid"},g=20,Z=d({__name:"NewestView",setup(t){const{productsData:e,getProducts:a}=q(),r=u(!1),s=u(!1),i=u(g),m=N(()=>e.productList.slice(0,i.value));A(async()=>{await a(r,!1)});const h=async()=>{if(i.value<e.productList.length){i.value+=g;return}await a(s,!0)};return(J,K)=>{const w=V("container");return n(),l("div",G,[o(x,{title:"جدیدترین محصولات","back-to":"home"}),o(_,{spinning:r.value,tip:"درحال دریافت اطلاعات"},{default:p(()=>[o(T,{class:"newest__scroll",loading:s.value,flag:c(e).flag,padding:"0px",onFetch:h},{default:p(()=>[o(w,{class:"newest__body"},{default:p(()=>[o(S,{title:"تازه‌ها",subtitle:"آخرین افزوده‌های مجموعه"}),c(e).productList.length?(n(),l("div",M,[(n(!0),l($,null,F(m.value,f=>(n(),v(k,{key:f.id,value:f},null,8,["value"]))),128))])):y("",!0)]),_:1})]),_:1},8,["loading","flag"])]),_:1},8,["spinning"])])}}}),it=D(Z,[["__scopeId","data-v-62cb523e"]]);export{it as default};
+1
View File
@@ -0,0 +1 @@
import{P as x}from"./PageBar-BrfQrql1.js";import{E as P,a as _}from"./Spinner.vue_vue_type_style_index_0_lang-DQwH-Xdy.js";import{S}from"./SectionHead-QOHixgma.js";import{P as k}from"./ProductCard-Dj_Eu2VB.js";import{d,i as n,c,k as o,u as l,y as B,z as C,n as E,A as b,v,f as y,g as u,B as L,C as $,q as p,F as A,r as F,h as I,s as N,_ as V}from"./index-CBZSLIgu.js";import{a as q}from"./client-CJxy5iKa.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-DssXZ7g8.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-BZS-5R5g.js";import"./DialogVant.vue_vue_type_style_index_0_lang-CINs34e0.js";import"./cartStore-CAFgxy6H.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-CUVFR_Bx.js";import"./classCallCheck-R2Fkn3Yh.js";const z={class:"flex justify-center items-center empty"},D=d({__name:"EmptyState",props:{description:{},image:{}},setup(t){return(e,a)=>(n(),c("div",z,[o(l(P),{description:"موردی یافت نشد",image:t.image,class:"h-[200px] w-[200px] opacity-70"},null,8,["image"])]))}}),H="/assets/favoritEmpty-CIK7qR49.svg",T=d({__name:"ScrollFetchSearch",props:{loading:{type:Boolean},flag:{type:Boolean},padding:{}},emits:["fetch"],setup(t,{emit:e}){const a=e,r=B(),s=u(null);return C(s,()=>{a("fetch")},{distance:50}),(i,m)=>(n(),c("main",{class:"flex flex-col flex-1 overflow-auto no-scrollbar w-[100vw] max-w-screen-md m-auto",style:E({paddingTop:t.padding||l(r).headerHeight+"px"}),ref_key:"scrollArea",ref:s},[b(i.$slots,"default"),o(_,{cls:"my-[10px]",spinning:t.loading,indicator:!0,tip:"درحال دریافت اطلاعات"},null,8,["spinning"]),t.flag?(n(),v(D,{key:0,image:l(H)},null,8,["image"])):y("",!0)],4))}});function j(){const t=L({totalPages:0,productList:[],flag:!1});return{productsData:t,getProducts:async(a,r=!1)=>{if(!r){a.value=!0;try{t.productList=await q.listProducts(),t.flag=t.productList.length<1}catch(s){console.log(s)}finally{a.value=!1}}}}}const G={class:"newest"},K={key:0,class:"newest__grid"},g=20,M=d({__name:"NewestView",setup(t){const{productsData:e,getProducts:a}=j(),r=u(!1),s=u(!1),i=u(g),m=I(()=>e.productList.slice(0,i.value));$(async()=>{await a(r,!1)});const h=async()=>{if(i.value<e.productList.length){i.value+=g;return}await a(s,!0)};return(R,Z)=>{const w=N("container");return n(),c("div",G,[o(x,{title:"جدیدترین محصولات","back-to":"home"}),o(_,{spinning:r.value,tip:"درحال دریافت اطلاعات"},{default:p(()=>[o(T,{class:"newest__scroll",loading:s.value,flag:l(e).flag,padding:"0px",onFetch:h},{default:p(()=>[o(w,{class:"newest__body"},{default:p(()=>[o(S,{title:"تازه‌ها",subtitle:"آخرین افزوده‌های مجموعه"}),l(e).productList.length?(n(),c("div",K,[(n(!0),c(A,null,F(m.value,f=>(n(),v(k,{key:f.id,value:f},null,8,["value"]))),128))])):y("",!0)]),_:1})]),_:1},8,["loading","flag"])]),_:1},8,["spinning"])])}}}),it=V(M,[["__scopeId","data-v-62cb523e"]]);export{it as default};
@@ -1 +1 @@
import{d as a,c as n,e as o,w as i,q as c,g as _,b as e,I as r,_ as p}from"./index-CXDP73fh.js";import{P as d}from"./PageBar-DGocjVpH.js";const f={class:"notif"},l={class:"notif__empty"},m=a({__name:"NotificationsView",setup(u){return(x,t)=>{const s=c("container");return _(),n("div",f,[o(d,{title:"اعلان‌ها","back-to":"home"}),o(s,{class:"notif__body"},{default:i(()=>[e("section",l,[o(r,{icon:"vuesax-linear:notification",size:"26"}),t[0]||(t[0]=e("p",null,"اعلانی برای نمایش وجود ندارد.",-1))])]),_:1})])}}}),B=p(m,[["__scopeId","data-v-44d0c9a5"]]);export{B as default};
import{d as a,c as n,k as o,q as i,s as c,i as _,b as e,I as r,_ as p}from"./index-CBZSLIgu.js";import{P as d}from"./PageBar-BrfQrql1.js";const f={class:"notif"},l={class:"notif__empty"},m=a({__name:"NotificationsView",setup(u){return(x,t)=>{const s=c("container");return _(),n("div",f,[o(d,{title:"اعلان‌ها","back-to":"home"}),o(s,{class:"notif__body"},{default:i(()=>[e("section",l,[o(r,{icon:"vuesax-linear:notification",size:"26"}),t[0]||(t[0]=e("p",null,"اعلانی برای نمایش وجود ندارد.",-1))])]),_:1})])}}}),B=p(m,[["__scopeId","data-v-44d0c9a5"]]);export{B as default};
@@ -0,0 +1 @@
import{d as r,k as n,ah as p,ai as f,aj as h,ak as w,al as y,am as k,a6 as x,an as c,a5 as g,ad as N,G as S,i as V,c as v,u as P,n as _,q as b,b as l,I as B,A as I,D as z,t as C,f as O,g as D}from"./index-CBZSLIgu.js";const[T,U]=g("notify"),j=["lockScroll","position","show","teleport","zIndex"],q=w({},y,{type:c("danger"),color:String,message:x,position:c("top"),className:k,background:String,lockScroll:Boolean});var A=r({name:T,props:q,emits:["update:show"],setup(e,{emit:o,slots:t}){const a=s=>o("update:show",s);return()=>n(h,p({class:[U([e.type]),e.className],style:{color:e.color,background:e.background},overlay:!1,duration:.2,"onUpdate:show":a},f(e,j)),{default:()=>[t.default?t.default():e.message]})}});const E=N(A),G={key:0,class:"flex"},$={class:"w-full text-white my-2"},F={class:"w-full flex content-end"},J=r({__name:"NotifyVant",props:{modelValue:{type:Boolean},timeOut:{},text:{},color:{}},emits:["update:modelValue"],setup(e,{emit:o}){const t=D(!0),a=e,s=o;S(()=>a.modelValue,()=>{a.timeOut!==-1&&u()});const u=()=>{setTimeout(()=>{s("update:modelValue",!1)},a.timeOut)};return(d,i)=>e.modelValue?(V(),v("div",G,[n(P(E),{show:t.value,"onUpdate:show":i[0]||(i[0]=m=>t.value=m),style:_(e.color)},{default:b(()=>[l("div",$,[l("div",F,[n(B,{icon:"vuesax-linear:info-circle",class:"ml-[20px] text-white",size:"25"}),l("div",null,[I(d.$slots,"default",{},()=>[z(C(e.text),1)])])])])]),_:3},8,["show","style"])])):O("",!0)}});export{J as _};
@@ -1 +0,0 @@
import{d as r,e as n,af as p,ag as f,ah as h,ai as w,aj as y,ak as g,a4 as x,al as c,a3 as k,ab as N,G as S,g as V,c as v,u as P,A as b,w as B,b as l,I as _,B as I,i as z,t as C,f as O,j}from"./index-CXDP73fh.js";const[T,U]=k("notify"),A=["lockScroll","position","show","teleport","zIndex"],D=w({},y,{type:c("danger"),color:String,message:x,position:c("top"),className:g,background:String,lockScroll:Boolean});var E=r({name:T,props:D,emits:["update:show"],setup(e,{emit:o,slots:t}){const a=s=>o("update:show",s);return()=>n(h,p({class:[U([e.type]),e.className],style:{color:e.color,background:e.background},overlay:!1,duration:.2,"onUpdate:show":a},f(e,A)),{default:()=>[t.default?t.default():e.message]})}});const G=N(E),$={key:0,class:"flex"},q={class:"w-full text-white my-2"},F={class:"w-full flex content-end"},J=r({__name:"NotifyVant",props:{modelValue:{type:Boolean},timeOut:{},text:{},color:{}},emits:["update:modelValue"],setup(e,{emit:o}){const t=j(!0),a=e,s=o;S(()=>a.modelValue,()=>{a.timeOut!==-1&&u()});const u=()=>{setTimeout(()=>{s("update:modelValue",!1)},a.timeOut)};return(d,i)=>e.modelValue?(V(),v("div",$,[n(P(G),{show:t.value,"onUpdate:show":i[0]||(i[0]=m=>t.value=m),style:b(e.color)},{default:B(()=>[l("div",q,[l("div",F,[n(_,{icon:"vuesax-linear:info-circle",class:"ml-[20px] text-white",size:"25"}),l("div",null,[I(d.$slots,"default",{},()=>[z(C(e.text),1)])])])])]),_:3},8,["show","style"])])):O("",!0)}});export{J as _};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{d as _,c as s,b as a,e as d,I as b,t as u,B as i,g as t,x as p,_ as k}from"./index-CXDP73fh.js";const h={class:"bar"},f={class:"bar__inner"},B={key:1,class:"bar__spacer","aria-hidden":"true"},g={class:"bar__title"},m={class:"bar__trailing"},v=_({__name:"PageBar",props:{title:{},back:{type:Boolean,default:!0},backTo:{}},setup(e){const o=e,r=p();function l(){o.backTo?r.push({name:o.backTo}):r.back()}return(n,c)=>(t(),s("header",h,[a("div",f,[e.back?(t(),s("button",{key:0,type:"button",class:"bar__btn","aria-label":"بازگشت",onClick:l},[d(b,{icon:"vuesax-linear:arrow-right-1",size:"20"})])):(t(),s("span",B)),a("h1",g,u(e.title),1),a("div",m,[i(n.$slots,"trailing",{},()=>[c[0]||(c[0]=a("span",{class:"bar__spacer","aria-hidden":"true"},null,-1))],!0)])]),i(n.$slots,"below",{},void 0,!0)]))}}),x=k(v,[["__scopeId","data-v-d2d3dfeb"]]);export{x as P};
import{d as _,c as s,b as a,k as d,I as b,t as u,A as i,i as t,x as p,_ as k}from"./index-CBZSLIgu.js";const h={class:"bar"},f={class:"bar__inner"},m={key:1,class:"bar__spacer","aria-hidden":"true"},B={class:"bar__title"},g={class:"bar__trailing"},v=_({__name:"PageBar",props:{title:{},back:{type:Boolean,default:!0},backTo:{}},setup(e){const o=e,r=p();function l(){o.backTo?r.push({name:o.backTo}):r.back()}return(n,c)=>(t(),s("header",h,[a("div",f,[e.back?(t(),s("button",{key:0,type:"button",class:"bar__btn","aria-label":"بازگشت",onClick:l},[d(b,{icon:"vuesax-linear:arrow-right-1",size:"20"})])):(t(),s("span",m)),a("h1",B,u(e.title),1),a("div",g,[i(n.$slots,"trailing",{},()=>[c[0]||(c[0]=a("span",{class:"bar__spacer","aria-hidden":"true"},null,-1))],!0)])]),i(n.$slots,"below",{},void 0,!0)]))}}),x=k(v,[["__scopeId","data-v-d2d3dfeb"]]);export{x as P};
@@ -1 +1 @@
import{d as D,m as P,g as s,c as i,F as S,b as t,u as e,h as z,e as _,I as f,k as B,n as I,f as d,t as u,w as N,s as V,j as E,l as $,_ as j}from"./index-CXDP73fh.js";import{u as q,S as L}from"./SingleProduct-c159xuqF.js";import{u as M}from"./cartStore-DyCvrw6I.js";import{D as O}from"./index-BYO8JY_f.js";const U={class:"pc__art"},A=["alt"],G={key:1,class:"pc__artEmpty","aria-hidden":"true"},H=["aria-label"],J={key:2,class:"pc__flag"},K={key:3,class:"pc__flag pc__flag--soft"},Q={class:"pc__body"},R={class:"pc__title"},T={class:"pc__meta"},W={class:"pc__weight"},X={key:0,class:"pc__wage"},Y=D({__name:"ProductCard",props:{value:{}},setup(g){const h=g,n=q(),{image:p,id:a,title:v,min_gram:y,wage:m,is_exist:b,qty:k,isPreOrder:w}=M(h.value),l=E(!1);function x(){l.value=!0}const C=$(()=>{const r=m.value;return r==null?"":r%1===0?String(r):r.toFixed(2)});return(r,o)=>{const F=P("lazy");return s(),i(S,null,[t("article",{class:"pc",onClick:x},[t("div",U,[e(p)?z((s(),i("img",{key:0,alt:e(v)},null,8,A)),[[F,e(p)]]):(s(),i("div",G,[_(f,{icon:"vuesax-linear:diamonds",size:"26"})])),t("button",{type:"button",class:I(["pc__fav",{"is-on":e(n).isFavorite(e(a))}]),"aria-label":e(n).isFavorite(e(a))?"حذف از علاقه‌مندی":"افزودن به علاقه‌مندی",onClick:o[0]||(o[0]=B(c=>e(n).toggle(e(a)),["stop"]))},[_(f,{icon:e(n).isFavorite(e(a))?"vuesax-linear:heart-fill":"vuesax-linear:heart",size:"16"},null,8,["icon"])],10,H),e(b)?e(w)&&e(k)===0?(s(),i("span",K,"پیش‌سفارش")):d("",!0):(s(),i("span",J,"ناموجود"))]),t("div",Q,[t("h3",R,u(e(v)),1),t("div",T,[t("span",W,u(e(y))+" گرم",1),e(m)!=null?(s(),i("span",X,"اجرت "+u(C.value)+"٪",1)):d("",!0)])])]),_(e(O),{visible:l.value,"onUpdate:visible":o[2]||(o[2]=c=>l.value=c),placement:"bottom",closable:!1,class:"rtl",height:"100vh",bodyStyle:{padding:0,position:"relative"}},{default:N(()=>[l.value?(s(),V(L,{id:e(a),key:e(a),onCloseDrawer:o[1]||(o[1]=c=>l.value=!1)},null,8,["id"])):d("",!0)]),_:1},8,["visible"])],64)}}}),ae=j(Y,[["__scopeId","data-v-5658bc04"]]);export{ae as P};
import{d as D,l as P,i as s,c as i,F as S,b as t,u as e,w as z,k as _,I as f,j as B,e as I,f as d,t as u,q as N,v as V,g as q,h as E,_ as $}from"./index-CBZSLIgu.js";import{u as j,S as L}from"./SingleProduct-DssXZ7g8.js";import{u as M}from"./cartStore-CAFgxy6H.js";import{D as O}from"./index-CUVFR_Bx.js";const U={class:"pc__art"},A=["alt"],G={key:1,class:"pc__artEmpty","aria-hidden":"true"},H=["aria-label"],J={key:2,class:"pc__flag"},K={key:3,class:"pc__flag pc__flag--soft"},Q={class:"pc__body"},R={class:"pc__title"},T={class:"pc__meta"},W={class:"pc__weight"},X={key:0,class:"pc__wage"},Y=D({__name:"ProductCard",props:{value:{}},setup(g){const h=g,n=j(),{image:p,id:a,title:v,min_gram:y,wage:m,is_exist:b,qty:k,isPreOrder:w}=M(h.value),l=q(!1);function x(){l.value=!0}const C=E(()=>{const r=m.value;return r==null?"":r%1===0?String(r):r.toFixed(2)});return(r,o)=>{const F=P("lazy");return s(),i(S,null,[t("article",{class:"pc",onClick:x},[t("div",U,[e(p)?z((s(),i("img",{key:0,alt:e(v)},null,8,A)),[[F,e(p)]]):(s(),i("div",G,[_(f,{icon:"vuesax-linear:diamonds",size:"26"})])),t("button",{type:"button",class:I(["pc__fav",{"is-on":e(n).isFavorite(e(a))}]),"aria-label":e(n).isFavorite(e(a))?"حذف از علاقه‌مندی":"افزودن به علاقه‌مندی",onClick:o[0]||(o[0]=B(c=>e(n).toggle(e(a)),["stop"]))},[_(f,{icon:e(n).isFavorite(e(a))?"vuesax-linear:heart-fill":"vuesax-linear:heart",size:"16"},null,8,["icon"])],10,H),e(b)?e(w)&&e(k)===0?(s(),i("span",K,"پیش‌سفارش")):d("",!0):(s(),i("span",J,"ناموجود"))]),t("div",Q,[t("h3",R,u(e(v)),1),t("div",T,[t("span",W,u(e(y))+" گرم",1),e(m)!=null?(s(),i("span",X,"اجرت "+u(C.value)+"٪",1)):d("",!0)])])]),_(e(O),{visible:l.value,"onUpdate:visible":o[2]||(o[2]=c=>l.value=c),placement:"bottom",closable:!1,class:"rtl",height:"100vh",bodyStyle:{padding:0,position:"relative"}},{default:N(()=>[l.value?(s(),V(L,{id:e(a),key:e(a),onCloseDrawer:o[1]||(o[1]=c=>l.value=!1)},null,8,["id"])):d("",!0)]),_:1},8,["visible"])],64)}}}),ae=$(Y,[["__scopeId","data-v-5658bc04"]]);export{ae as P};
@@ -1 +1 @@
import{d as I,E as S,o as E,c as a,e as l,w as y,j as p,q as V,g as i,b as e,I as f,t,f as _,n as b,l as k,_ as C}from"./index-CXDP73fh.js";import{P as N}from"./PageBar-DGocjVpH.js";import{S as T}from"./SectionHead-BpYVXEql.js";import{a as g}from"./client-WIBW0tF5.js";const h={class:"prof"},B={class:"prof__identity"},P={class:"prof__avatar","aria-hidden":"true"},x={class:"prof__name"},D={key:0,class:"prof__mobile"},w={key:0,class:"prof__block"},R={class:"prof__specs"},F={class:"prof__spec"},z={class:"prof__spec"},M={class:"prof__spec"},O={class:"prof__spec"},U={key:1,class:"prof__empty"},A=I({__name:"ProfileView",setup(L){const c={UNVERIFIED:"احراز نشده",STEP_ONE_SUBMITTED:"مرحله اول ثبت شده",STEP_TWO_SUBMITTED:"مرحله دوم ثبت شده",VERIFIED:"تایید شده"},u=S(),s=p(null),n=p(!1),v=k(()=>{var r;return((r=s.value)==null?void 0:r.verificationStep)==="VERIFIED"});return E(async()=>{if(u.customerId){n.value=!0;try{s.value=await g.getCustomer(u.customerId)}finally{n.value=!1}}}),(r,o)=>{const m=V("container");return i(),a("div",h,[l(N,{title:"اطلاعات کاربری","back-to":"userPage::hasSubRoute"}),l(m,{class:"prof__body"},{default:y(()=>{var d;return[e("section",B,[e("div",P,[l(f,{icon:"vuesax-linear:user",size:"30"})]),e("h2",x,t(((d=s.value)==null?void 0:d.fullName)??"—"),1),s.value?(i(),a("p",D,t(s.value.mobile),1)):_("",!0),s.value?(i(),a("span",{key:1,class:b(["prof__seal",v.value?"is-ok":"is-pending"])},t(c[s.value.verificationStep]??s.value.verificationStep),3)):_("",!0)]),s.value?(i(),a("section",w,[l(T,{title:"مشخصات",subtitle:"اطلاعات ثبت‌شده حساب شما"}),e("dl",R,[e("div",F,[o[0]||(o[0]=e("dt",null,"نام و نام خانوادگی",-1)),e("dd",null,t(s.value.fullName),1)]),e("div",z,[o[1]||(o[1]=e("dt",null,"تلفن همراه",-1)),e("dd",null,t(s.value.mobile),1)]),e("div",M,[o[2]||(o[2]=e("dt",null,"کد ملی",-1)),e("dd",null,t(s.value.nationalCode),1)]),e("div",O,[o[3]||(o[3]=e("dt",null,"وضعیت احراز هویت",-1)),e("dd",null,t(c[s.value.verificationStep]??s.value.verificationStep),1)])])])):n.value?_("",!0):(i(),a("section",U,[l(f,{icon:"vuesax-linear:user",size:"26"}),o[4]||(o[4]=e("p",null,"اطلاعات حساب در دسترس نیست.",-1))]))]}),_:1})])}}}),G=C(A,[["__scopeId","data-v-7c544fc5"]]);export{G as default};
import{d as I,E as S,o as E,c as a,k as i,q as y,g as p,s as k,i as l,b as e,I as f,t,f as _,e as V,h as b,_ as h}from"./index-CBZSLIgu.js";import{P as C}from"./PageBar-BrfQrql1.js";import{S as N}from"./SectionHead-QOHixgma.js";import{a as T}from"./client-CJxy5iKa.js";const g={class:"prof"},B={class:"prof__identity"},P={class:"prof__avatar","aria-hidden":"true"},x={class:"prof__name"},D={key:0,class:"prof__mobile"},R={key:0,class:"prof__block"},w={class:"prof__specs"},F={class:"prof__spec"},z={class:"prof__spec"},M={class:"prof__spec"},O={class:"prof__spec"},U={key:1,class:"prof__empty"},A=I({__name:"ProfileView",setup(L){const c={UNVERIFIED:"احراز نشده",STEP_ONE_SUBMITTED:"مرحله اول ثبت شده",STEP_TWO_SUBMITTED:"مرحله دوم ثبت شده",VERIFIED:"تایید شده"},u=S(),s=p(null),n=p(!1),v=b(()=>{var r;return((r=s.value)==null?void 0:r.verificationStep)==="VERIFIED"});return E(async()=>{if(u.customerId){n.value=!0;try{s.value=await T.getCustomer(u.customerId)}finally{n.value=!1}}}),(r,o)=>{const m=k("container");return l(),a("div",g,[i(C,{title:"اطلاعات کاربری","back-to":"userPage::hasSubRoute"}),i(m,{class:"prof__body"},{default:y(()=>{var d;return[e("section",B,[e("div",P,[i(f,{icon:"vuesax-linear:user",size:"30"})]),e("h2",x,t(((d=s.value)==null?void 0:d.fullName)??"—"),1),s.value?(l(),a("p",D,t(s.value.mobile),1)):_("",!0),s.value?(l(),a("span",{key:1,class:V(["prof__seal",v.value?"is-ok":"is-pending"])},t(c[s.value.verificationStep]??s.value.verificationStep),3)):_("",!0)]),s.value?(l(),a("section",R,[i(N,{title:"مشخصات",subtitle:"اطلاعات ثبت‌شده حساب شما"}),e("dl",w,[e("div",F,[o[0]||(o[0]=e("dt",null,"نام و نام خانوادگی",-1)),e("dd",null,t(s.value.fullName),1)]),e("div",z,[o[1]||(o[1]=e("dt",null,"تلفن همراه",-1)),e("dd",null,t(s.value.mobile),1)]),e("div",M,[o[2]||(o[2]=e("dt",null,"کد ملی",-1)),e("dd",null,t(s.value.nationalCode),1)]),e("div",O,[o[3]||(o[3]=e("dt",null,"وضعیت احراز هویت",-1)),e("dd",null,t(c[s.value.verificationStep]??s.value.verificationStep),1)])])])):n.value?_("",!0):(l(),a("section",U,[i(f,{icon:"vuesax-linear:user",size:"26"}),o[4]||(o[4]=e("p",null,"اطلاعات حساب در دسترس نیست.",-1))]))]}),_:1})])}}}),G=h(A,[["__scopeId","data-v-7c544fc5"]]);export{G as default};
@@ -1 +1 @@
import{p as c,j as d}from"./filters-CLL9nGZ2.js";import{d as l,c as s,n as u,b as a,i as _,t as i,u as n,f as m,l as v,g as r,_ as q}from"./index-CXDP73fh.js";const f={key:0,class:"rate-strip__value"},k={class:"rate-strip__num"},y={key:1,class:"rate-strip__value rate-strip__value--muted"},x={key:2,class:"rate-strip__time"},R=l({__name:"RateStrip",props:{quote:{}},setup(t){const o=t,p=v(()=>o.quote?o.quote.pricePerGramRial.split(".")[0]:"");return(b,e)=>(r(),s("div",{class:u(["rate-strip",{"is-empty":!t.quote}])},[e[1]||(e[1]=a("div",{class:"rate-strip__label"},[a("span",{class:"rate-strip__dot","aria-hidden":"true"}),_(" نرخ طلای ۱۸ عیار ")],-1)),t.quote?(r(),s("div",f,[a("span",k,i(n(c)(p.value)),1),e[0]||(e[0]=a("span",{class:"rate-strip__unit"},"ریال / گرم",-1))])):(r(),s("div",y,"در انتظار اعلام نرخ")),t.quote?(r(),s("div",x,i(n(d)(t.quote.quotedAt)),1)):m("",!0)],2))}}),N=q(R,[["__scopeId","data-v-16b4c8d5"]]);export{N as R};
import{p as c,j as d}from"./filters-CLL9nGZ2.js";import{d as u,c as s,e as _,b as a,D as l,t as i,u as n,f as m,h as v,i as r,_ as q}from"./index-CBZSLIgu.js";const f={key:0,class:"rate-strip__value"},k={class:"rate-strip__num"},y={key:1,class:"rate-strip__value rate-strip__value--muted"},x={key:2,class:"rate-strip__time"},R=u({__name:"RateStrip",props:{quote:{}},setup(t){const o=t,p=v(()=>o.quote?o.quote.pricePerGramRial.split(".")[0]:"");return(b,e)=>(r(),s("div",{class:_(["rate-strip",{"is-empty":!t.quote}])},[e[1]||(e[1]=a("div",{class:"rate-strip__label"},[a("span",{class:"rate-strip__dot","aria-hidden":"true"}),l(" نرخ طلای ۱۸ عیار ")],-1)),t.quote?(r(),s("div",f,[a("span",k,i(n(c)(p.value)),1),e[0]||(e[0]=a("span",{class:"rate-strip__unit"},"ریال / گرم",-1))])):(r(),s("div",y,"در انتظار اعلام نرخ")),t.quote?(r(),s("div",x,i(n(d)(t.quote.quotedAt)),1)):m("",!0)],2))}}),C=q(R,[["__scopeId","data-v-16b4c8d5"]]);export{C as R};
-1
View File
@@ -1 +0,0 @@
import{d as v,a0 as h,G as m,g as t,c as l,e as n,I as r,h as f,a1 as b,b as x,a2 as k,f as C,C as I,j as y,_ as S}from"./index-CXDP73fh.js";const V={class:"si"},w=["placeholder"],B=v({__name:"SearchInput",props:{placeHolder:{}},emits:["search"],setup(i,{emit:d}){const c=d,a=I({clear:!1}),e=y(void 0),s=()=>{c("search",e.value)},u=()=>{e.value=void 0,a.clear=!1,c("search",void 0)},p=h(e,700);return m(p,()=>{e?a.clear=!0:a.clear=!1,s()}),(N,o)=>(t(),l("div",V,[n(r,{icon:"vuesax-linear:search-normal-1",class:"si__icon",size:"18",onClick:s}),f(x("input",{"onUpdate:modelValue":o[0]||(o[0]=_=>e.value=_),class:"si__input",placeholder:i.placeHolder,onKeyup:k(s,["enter"])},null,40,w),[[b,e.value]]),a.clear?(t(),l("button",{key:0,type:"button",class:"si__clear","aria-label":"پاک کردن",onClick:u},[n(r,{icon:"vuesax-linear:add",size:"16"})])):C("",!0)]))}}),D=S(B,[["__scopeId","data-v-4c50067a"]]);export{D as S};
+1
View File
@@ -0,0 +1 @@
import{d as v,a2 as h,G as m,i as t,c as l,k as n,I as r,w as f,a3 as b,b as k,a4 as x,f as I,B as w,g as y,_ as B}from"./index-CBZSLIgu.js";const C={class:"si"},S=["placeholder"],V=v({__name:"SearchInput",props:{placeHolder:{}},emits:["search"],setup(i,{emit:d}){const c=d,a=w({clear:!1}),e=y(void 0),s=()=>{c("search",e.value)},u=()=>{e.value=void 0,a.clear=!1,c("search",void 0)},p=h(e,700);return m(p,()=>{e?a.clear=!0:a.clear=!1,s()}),(N,o)=>(t(),l("div",C,[n(r,{icon:"vuesax-linear:search-normal-1",class:"si__icon",size:"18",onClick:s}),f(k("input",{"onUpdate:modelValue":o[0]||(o[0]=_=>e.value=_),class:"si__input",placeholder:i.placeHolder,onKeyup:x(s,["enter"])},null,40,S),[[b,e.value]]),a.clear?(t(),l("button",{key:0,type:"button",class:"si__clear","aria-label":"پاک کردن",onClick:u},[n(r,{icon:"vuesax-linear:add",size:"16"})])):I("",!0)]))}}),D=B(V,[["__scopeId","data-v-4c50067a"]]);export{D as S};
@@ -1 +1 @@
.dd[data-v-9e57de56]{padding:15px;border:1px solid #ECEDEF;border-radius:16px;background:#fff}.dd.is-open[data-v-9e57de56]{border-color:#a33c55}.dd__head[data-v-9e57de56]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;border:0;padding:0;cursor:pointer;background:none;font-family:inherit;text-align:start}.dd__title[data-v-9e57de56]{margin:0;font-size:13px;font-weight:700;color:#14161a}.dd__chevron[data-v-9e57de56]{flex:0 0 auto;color:#8a909c;transition:transform .2s ease}.dd.is-open .dd__chevron[data-v-9e57de56]{transform:rotate(180deg);color:#7a1b33}.dd__body[data-v-9e57de56]{overflow:hidden;padding-top:15px}.drop-enter-active{animation:drop .2s cubic-bezier(.33,1,.68,1)}.drop-leave-to{animation:drop .2s cubic-bezier(.33,1,.68,1) reverse}@keyframes drop{0%{max-height:0}to{max-height:240px}}.filt[data-v-9651e9da]{background:#fff;min-height:100vh}.filt__body[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:120px 16px 110px;display:flex;flex-direction:column;gap:12px}.filt__chips[data-v-9651e9da]{display:flex;flex-wrap:wrap;gap:8px}.filt__chip[data-v-9651e9da]{padding:8px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.filt__chip.is-on[data-v-9651e9da]{color:#fff;background:#14161a;border-color:#14161a}.filt__chip[data-v-9651e9da]:active{transform:scale(.97)}.filt__empty[data-v-9651e9da]{margin:0;font-size:12px;color:#8a909c}.filt__gram[data-v-9651e9da]{padding:4px 6px 0}.filt__gram[data-v-9651e9da] .ant-slider-track{background-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-handle{border-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-rail{background-color:#ecedef}.filt__gramFigures[data-v-9651e9da]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:18px}.filt__gramFigure[data-v-9651e9da]{font-size:12px;font-weight:700;color:#14161a}.filt__gramFigure i[data-v-9651e9da]{font-style:normal;font-size:11px;font-weight:600;color:#8a909c;padding-inline-end:4px}.filt__bar[data-v-9651e9da]{position:fixed;bottom:0;left:0;right:0;z-index:5;background:#ffffffeb;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-top:1px solid #ECEDEF;padding-bottom:16px}.filt__barInner[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:12px 16px;display:flex;align-items:center;gap:10px}.filt__clear[data-v-9651e9da],.filt__apply[data-v-9651e9da]{flex:1;padding:13px 18px;border:0;cursor:pointer;border-radius:14px;font-family:inherit;font-size:13px;font-weight:700;transition:transform .15s ease}.filt__clear[data-v-9651e9da]{color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF}.filt__apply[data-v-9651e9da]{color:#fff;background:#14161a}.filt__clear[data-v-9651e9da]:active,.filt__apply[data-v-9651e9da]:active{transform:scale(.98)}.search[data-v-64596986]{background:#fff;min-height:100vh}.search__barExtra[data-v-64596986]{max-width:768px;margin:0 auto;padding:0 16px}.search__chips[data-v-64596986]{display:flex;gap:4px;overflow-x:auto;margin:8px 0 8px -16px;scroll-snap-type:x proximity}.search__chips[data-v-64596986]:before,.search__chips[data-v-64596986]:after{content:"";flex:0 0 16px}.search__chip[data-v-64596986]{scroll-snap-align:start;flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:600;white-space:nowrap;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.search__chip.is-on[data-v-64596986]{color:#fff;background:#14161a;border-color:#14161a}.search__chip--filter.is-on[data-v-64596986]{background:#7a1b33;border-color:#7a1b33}.search__chip[data-v-64596986]:active{transform:scale(.97)}.search__body[data-v-64596986]{padding-top:160px;padding-bottom:90px}.search__body[data-v-64596986]>*:first-child{margin-top:16px}.search__collections[data-v-64596986]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-bottom:22px}.search__collection[data-v-64596986]{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 10px;border-radius:14px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:700;color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF;transition:all .2s ease}.search__collection[data-v-64596986]:active{transform:scale(.98)}.search__grid[data-v-64596986]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}.search__more[data-v-64596986]{display:flex;justify-content:center;padding:18px 0 4px}.search__empty[data-v-64596986]{margin-top:8px;padding:34px 20px;border:1px dashed #ECEDEF;border-radius:18px;display:flex;flex-direction:column;align-items:center;gap:10px;color:#8a909c}.search__empty p[data-v-64596986]{margin:0;font-size:12.5px}
.dd[data-v-9e57de56]{padding:15px;border:1px solid #ECEDEF;border-radius:16px;background:#fff}.dd.is-open[data-v-9e57de56]{border-color:#a33c55}.dd__head[data-v-9e57de56]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;border:0;padding:0;cursor:pointer;background:none;font-family:inherit;text-align:start}.dd__title[data-v-9e57de56]{margin:0;font-size:13px;font-weight:700;color:#14161a}.dd__chevron[data-v-9e57de56]{flex:0 0 auto;color:#8a909c;transition:transform .2s ease}.dd.is-open .dd__chevron[data-v-9e57de56]{transform:rotate(180deg);color:#7a1b33}.dd__body[data-v-9e57de56]{overflow:hidden;padding-top:15px}.drop-enter-active{animation:drop .2s cubic-bezier(.33,1,.68,1)}.drop-leave-to{animation:drop .2s cubic-bezier(.33,1,.68,1) reverse}@keyframes drop{0%{max-height:0}to{max-height:240px}}.filt[data-v-9651e9da]{background:#fff;min-height:100vh}.filt__body[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:120px 16px 110px;display:flex;flex-direction:column;gap:12px}.filt__chips[data-v-9651e9da]{display:flex;flex-wrap:wrap;gap:8px}.filt__chip[data-v-9651e9da]{padding:8px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.filt__chip.is-on[data-v-9651e9da]{color:#fff;background:#14161a;border-color:#14161a}.filt__chip[data-v-9651e9da]:active{transform:scale(.97)}.filt__empty[data-v-9651e9da]{margin:0;font-size:12px;color:#8a909c}.filt__gram[data-v-9651e9da]{padding:4px 6px 0}.filt__gram[data-v-9651e9da] .ant-slider-track{background-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-handle{border-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-rail{background-color:#ecedef}.filt__gramFigures[data-v-9651e9da]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:18px}.filt__gramFigure[data-v-9651e9da]{font-size:12px;font-weight:700;color:#14161a}.filt__gramFigure i[data-v-9651e9da]{font-style:normal;font-size:11px;font-weight:600;color:#8a909c;padding-inline-end:4px}.filt__bar[data-v-9651e9da]{position:fixed;bottom:0;left:0;right:0;z-index:5;background:#ffffffeb;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-top:1px solid #ECEDEF;padding-bottom:16px}.filt__barInner[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:12px 16px;display:flex;align-items:center;gap:10px}.filt__clear[data-v-9651e9da],.filt__apply[data-v-9651e9da]{flex:1;padding:13px 18px;border:0;cursor:pointer;border-radius:14px;font-family:inherit;font-size:13px;font-weight:700;transition:transform .15s ease}.filt__clear[data-v-9651e9da]{color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF}.filt__apply[data-v-9651e9da]{color:#fff;background:#14161a}.filt__clear[data-v-9651e9da]:active,.filt__apply[data-v-9651e9da]:active{transform:scale(.98)}.search[data-v-0d6eddd7]{background:#fff;min-height:100vh}.search__barExtra[data-v-0d6eddd7]{max-width:768px;margin:0 auto;padding:0 16px}.search__chips[data-v-0d6eddd7]{display:flex;gap:4px;overflow-x:auto;margin:8px 0 8px -16px;scroll-snap-type:x proximity}.search__chips[data-v-0d6eddd7]:before,.search__chips[data-v-0d6eddd7]:after{content:"";flex:0 0 16px}.search__chip[data-v-0d6eddd7]{scroll-snap-align:start;flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:600;white-space:nowrap;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.search__chip.is-on[data-v-0d6eddd7]{color:#fff;background:#14161a;border-color:#14161a}.search__chip--filter.is-on[data-v-0d6eddd7]{background:#7a1b33;border-color:#7a1b33}.search__chip[data-v-0d6eddd7]:active{transform:scale(.97)}.search__body[data-v-0d6eddd7]{padding-top:160px;padding-bottom:90px}.search__body[data-v-0d6eddd7]>*:first-child{margin-top:16px}.search__collections[data-v-0d6eddd7]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-bottom:22px}.search__collection[data-v-0d6eddd7]{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 10px;border-radius:14px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:700;color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF;transition:all .2s ease}.search__collection[data-v-0d6eddd7]:active{transform:scale(.98)}.search__grid[data-v-0d6eddd7]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}.search__more[data-v-0d6eddd7]{display:flex;justify-content:center;padding:18px 0 4px}.search__empty[data-v-0d6eddd7]{margin-top:8px;padding:34px 20px;border:1px dashed #ECEDEF;border-radius:18px;display:flex;flex-direction:column;align-items:center;gap:10px;color:#8a909c}.search__empty p[data-v-0d6eddd7]{margin:0;font-size:12.5px}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
import{d as r,c as t,b as o,t as s,f as n,i as _,e as d,I as u,g as a,_ as b}from"./index-CXDP73fh.js";const m={class:"sec"},f={class:"sec__text"},x={class:"sec__title"},h={key:0,class:"sec__sub"},k=r({__name:"SectionHead",props:{title:{},subtitle:{},actionLabel:{}},emits:["action"],setup(e,{emit:i}){const l=i;return(p,c)=>(a(),t("header",m,[o("div",f,[o("h2",x,s(e.title),1),e.subtitle?(a(),t("p",h,s(e.subtitle),1)):n("",!0)]),e.actionLabel?(a(),t("button",{key:0,type:"button",class:"sec__action",onClick:c[0]||(c[0]=v=>l("action"))},[_(s(e.actionLabel)+" ",1),d(u,{icon:"vuesax-linear:arrow-left-2",size:"15"})])):n("",!0)]))}}),N=b(k,[["__scopeId","data-v-e5c65b7c"]]);export{N as S};
+1
View File
@@ -0,0 +1 @@
import{d as r,c as t,b as o,t as s,f as n,D as _,k as d,I as u,i as a,_ as b}from"./index-CBZSLIgu.js";const m={class:"sec"},f={class:"sec__text"},k={class:"sec__title"},x={key:0,class:"sec__sub"},h=r({__name:"SectionHead",props:{title:{},subtitle:{},actionLabel:{}},emits:["action"],setup(e,{emit:i}){const l=i;return(p,c)=>(a(),t("header",m,[o("div",f,[o("h2",k,s(e.title),1),e.subtitle?(a(),t("p",x,s(e.subtitle),1)):n("",!0)]),e.actionLabel?(a(),t("button",{key:0,type:"button",class:"sec__action",onClick:c[0]||(c[0]=v=>l("action"))},[_(s(e.actionLabel)+" ",1),d(u,{icon:"vuesax-linear:arrow-left-2",size:"15"})])):n("",!0)]))}}),N=b(h,[["__scopeId","data-v-e5c65b7c"]]);export{N as S};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{d as k,E as A,o as C,c as i,e as r,w as f,s as w,u as m,f as E,j as u,g as l,F as R,b as s,r as D,I as T,t as o,n as p,q as N,_ as L}from"./index-CXDP73fh.js";import{P}from"./PageBar-DGocjVpH.js";import{a as M}from"./Spinner.vue_vue_type_style_index_0_lang-Cw01MXb5.js";import{S as O}from"./SectionHead-BpYVXEql.js";import{j as g,p as B}from"./filters-CLL9nGZ2.js";import{a as I}from"./client-WIBW0tF5.js";import{D as U}from"./index-BYO8JY_f.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./classCallCheck-BI0ic3HN.js";const V={class:"tx"},$={class:"tx__list"},Y=["onClick"],j={class:"tx__main"},z={class:"tx__head"},F={class:"tx__kind"},G={key:0,class:"tx__note"},H={class:"tx__foot"},q={class:"tx__date"},J={key:1,class:"tx__empty"},K={class:"sheet"},Q={class:"sheet__specs"},W={class:"sheet__spec"},X={class:"sheet__spec"},Z={class:"sheet__spec"},ss={class:"sheet__spec"},es={class:"sheet__spec"},ts=k({__name:"TransactionsView",setup(os){const x={ORDER_STOCK:"سفارش",ORDER_PRE_ORDER:"سفارش ساخت",REPAYMENT_MELTED_GOLD:"طلای آب‌شده",REPAYMENT_TRANSFER:"حواله",REPAYMENT_CHEQUE:"چک",REPAYMENT_CASH:"پولی",WALLET_BONUS:"پاداش",ADJUSTMENT:"اصلاحیه"},h=A(),_=u(!1),d=u([]),v=u(!1),n=u(null),c=a=>a.direction==="CREDIT",y=a=>a.currency==="GOLD_GRAM"?`${a.amount} گرم`:`${B(a.amount)} ریال`,S=a=>{n.value=a,v.value=!0};return C(async()=>{if(h.customerId){_.value=!0;try{d.value=await I.getLedgerEntries(h.customerId)}finally{_.value=!1}}}),(a,e)=>{const b=N("container");return l(),i("div",V,[r(P,{title:"اسناد","back-to":"userPage::hasSubRoute"}),r(M,{spinning:_.value,tip:"درحال دریافت اطلاعات"},{default:f(()=>[r(b,{class:"tx__body"},{default:f(()=>[d.value.length?(l(),i(R,{key:0},[r(O,{title:"گردش حساب",subtitle:`${d.value.length} سند`},null,8,["subtitle"]),s("div",$,[(l(!0),i(R,null,D(d.value,t=>(l(),i("article",{key:t.id,class:"tx__row",onClick:ns=>S(t)},[s("span",{class:p(["tx__mark",c(t)?"is-in":"is-out"]),"aria-hidden":"true"},[r(T,{icon:c(t)?"vuesax-linear:arrow-down":"vuesax-linear:arrow-up",size:"16"},null,8,["icon"])],2),s("div",j,[s("div",z,[s("h3",F,o(x[t.sourceType]??t.sourceType),1),s("span",{class:p(["tx__amount",c(t)?"is-in":"is-out"])},o(y(t)),3)]),t.note?(l(),i("p",G,o(t.note),1)):E("",!0),s("div",H,[s("span",q,o(m(g)(t.createdAt)),1),s("span",{class:p(["tx__state",{"is-pending":!t.confirmed}])},o(t.confirmed?"تایید شده":"در انتظار تایید"),3)])])],8,Y))),128))])],64)):_.value?E("",!0):(l(),i("section",J,[r(T,{icon:"vuesax-linear:receipt-text",size:"26"}),e[1]||(e[1]=s("p",null,"سندی برای حساب شما ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"]),n.value?(l(),w(m(U),{key:0,visible:v.value,"onUpdate:visible":e[0]||(e[0]=t=>v.value=t),placement:"bottom",closable:!1,height:"420px",class:"rtl",bodyStyle:{padding:0}},{default:f(()=>[s("div",K,[e[7]||(e[7]=s("h3",{class:"sheet__title"},"جزئیات سند",-1)),s("dl",Q,[s("div",W,[e[2]||(e[2]=s("dt",null,"نوع سند",-1)),s("dd",null,o(x[n.value.sourceType]??n.value.sourceType),1)]),s("div",X,[e[3]||(e[3]=s("dt",null,"مبلغ",-1)),s("dd",{class:p(c(n.value)?"is-in":"is-out")},o(y(n.value)),3)]),s("div",Z,[e[4]||(e[4]=s("dt",null,"وضعیت",-1)),s("dd",null,o(n.value.confirmed?"تایید شده":"در انتظار تایید"),1)]),s("div",ss,[e[5]||(e[5]=s("dt",null,"تاریخ",-1)),s("dd",null,o(m(g)(n.value.createdAt)),1)]),s("div",es,[e[6]||(e[6]=s("dt",null,"توضیحات",-1)),s("dd",null,o(n.value.note||"—"),1)])])])]),_:1},8,["visible"])):E("",!0)])}}}),vs=L(ts,[["__scopeId","data-v-83b037a9"]]);export{vs as default};
import{d as b,E as A,o as C,c as i,k as r,q as f,v as D,u as m,f as E,g as u,i as l,F as R,b as s,r as w,I as T,t as o,e as p,s as N,_ as L}from"./index-CBZSLIgu.js";import{P}from"./PageBar-BrfQrql1.js";import{a as M}from"./Spinner.vue_vue_type_style_index_0_lang-DQwH-Xdy.js";import{S as O}from"./SectionHead-QOHixgma.js";import{j as g,p as B}from"./filters-CLL9nGZ2.js";import{a as I}from"./client-CJxy5iKa.js";import{D as U}from"./index-CUVFR_Bx.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./classCallCheck-R2Fkn3Yh.js";const V={class:"tx"},$={class:"tx__list"},Y=["onClick"],z={class:"tx__main"},F={class:"tx__head"},G={class:"tx__kind"},H={key:0,class:"tx__note"},j={class:"tx__foot"},q={class:"tx__date"},J={key:1,class:"tx__empty"},K={class:"sheet"},Q={class:"sheet__specs"},W={class:"sheet__spec"},X={class:"sheet__spec"},Z={class:"sheet__spec"},ss={class:"sheet__spec"},es={class:"sheet__spec"},ts=b({__name:"TransactionsView",setup(os){const x={ORDER_STOCK:"سفارش",ORDER_PRE_ORDER:"سفارش ساخت",REPAYMENT_MELTED_GOLD:"طلای آب‌شده",REPAYMENT_TRANSFER:"حواله",REPAYMENT_CHEQUE:"چک",REPAYMENT_CASH:"پولی",WALLET_BONUS:"پاداش",ADJUSTMENT:"اصلاحیه"},h=A(),_=u(!1),d=u([]),v=u(!1),n=u(null),c=a=>a.direction==="CREDIT",y=a=>a.currency==="GOLD_GRAM"?`${a.amount} گرم`:`${B(a.amount)} ریال`,k=a=>{n.value=a,v.value=!0};return C(async()=>{if(h.customerId){_.value=!0;try{d.value=await I.getLedgerEntries(h.customerId)}finally{_.value=!1}}}),(a,e)=>{const S=N("container");return l(),i("div",V,[r(P,{title:"اسناد","back-to":"userPage::hasSubRoute"}),r(M,{spinning:_.value,tip:"درحال دریافت اطلاعات"},{default:f(()=>[r(S,{class:"tx__body"},{default:f(()=>[d.value.length?(l(),i(R,{key:0},[r(O,{title:"گردش حساب",subtitle:`${d.value.length} سند`},null,8,["subtitle"]),s("div",$,[(l(!0),i(R,null,w(d.value,t=>(l(),i("article",{key:t.id,class:"tx__row",onClick:ns=>k(t)},[s("span",{class:p(["tx__mark",c(t)?"is-in":"is-out"]),"aria-hidden":"true"},[r(T,{icon:c(t)?"vuesax-linear:arrow-down":"vuesax-linear:arrow-up",size:"16"},null,8,["icon"])],2),s("div",z,[s("div",F,[s("h3",G,o(x[t.sourceType]??t.sourceType),1),s("span",{class:p(["tx__amount",c(t)?"is-in":"is-out"])},o(y(t)),3)]),t.note?(l(),i("p",H,o(t.note),1)):E("",!0),s("div",j,[s("span",q,o(m(g)(t.createdAt)),1),s("span",{class:p(["tx__state",{"is-pending":!t.confirmed}])},o(t.confirmed?"تایید شده":"در انتظار تایید"),3)])])],8,Y))),128))])],64)):_.value?E("",!0):(l(),i("section",J,[r(T,{icon:"vuesax-linear:receipt-text",size:"26"}),e[1]||(e[1]=s("p",null,"سندی برای حساب شما ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"]),n.value?(l(),D(m(U),{key:0,visible:v.value,"onUpdate:visible":e[0]||(e[0]=t=>v.value=t),placement:"bottom",closable:!1,height:"420px",class:"rtl",bodyStyle:{padding:0}},{default:f(()=>[s("div",K,[e[7]||(e[7]=s("h3",{class:"sheet__title"},"جزئیات سند",-1)),s("dl",Q,[s("div",W,[e[2]||(e[2]=s("dt",null,"نوع سند",-1)),s("dd",null,o(x[n.value.sourceType]??n.value.sourceType),1)]),s("div",X,[e[3]||(e[3]=s("dt",null,"مبلغ",-1)),s("dd",{class:p(c(n.value)?"is-in":"is-out")},o(y(n.value)),3)]),s("div",Z,[e[4]||(e[4]=s("dt",null,"وضعیت",-1)),s("dd",null,o(n.value.confirmed?"تایید شده":"در انتظار تایید"),1)]),s("div",ss,[e[5]||(e[5]=s("dt",null,"تاریخ",-1)),s("dd",null,o(m(g)(n.value.createdAt)),1)]),s("div",es,[e[6]||(e[6]=s("dt",null,"توضیحات",-1)),s("dd",null,o(n.value.note||"—"),1)])])])]),_:1},8,["visible"])):E("",!0)])}}}),vs=L(ts,[["__scopeId","data-v-83b037a9"]]);export{vs as default};
@@ -1 +1 @@
import{j as d,u as F,l as i,p as S}from"./index-CXDP73fh.js";import{a as P}from"./client-WIBW0tF5.js";function W(t){return!t||t.length===0?null:t.reduce((e,s)=>parseFloat(s.defaultWagePercent)<parseFloat(e.defaultWagePercent)?s:e)}function I(t,e){const s=d(t),r=i(()=>{var n,p;return(p=(n=s.value.images)==null?void 0:n[0])==null?void 0:p.url}),o=i(()=>s.value.id),u=i(()=>s.value.title),l=i(()=>s.value.variants),a=d(e??W(F(l))),v=i(()=>a.value?parseFloat(a.value.rashWeightGrams):0),g=i(()=>a.value?parseFloat(a.value.defaultWagePercent):null),x=d(null),f=i(()=>{var n;return((n=a.value)==null?void 0:n.qty)??0}),h=i(()=>{var n;return((n=a.value)==null?void 0:n.isPreOrder)??!1}),y=i(()=>f.value>0||h.value),_=i(()=>s.value.productCode??null),C=d(!1);return{product:s,image:r,id:o,title:u,productCode:_,variants:l,selectedVariant:a,min_gram:v,wage:g,hasDiscountWage:x,qty:f,isPreOrder:h,is_exist:y,has_warranty:C}}const m="appCart";function q(){try{const t=localStorage.getItem(m);return t?JSON.parse(t):[]}catch{return[]}}function c(t){localStorage.setItem(m,JSON.stringify(t))}const G=S("cart",{state:()=>({items:q()}),actions:{async init(){try{const t=await P.listProducts(),e=[];for(const s of this.items){const r=t.find(u=>u.id===s.pid),o=r==null?void 0:r.variants.find(u=>u.id===s.vid);r&&o&&e.push({...s,product:r})}this.items=e,c(this.items)}catch(t){console.log(t)}},addToCart(t){const e=this.find_index(t);e===-1?this.items.push(t):(this.items[e].product=t.product,this.items[e].qty=t.qty),c(this.items)},remove(t){const e=this.find_index(t);e>-1&&this.items.splice(e,1),c(this.items)},updateFeild(t,e,s,r){if(!this.isInCart(s))return!1;const o=e??this.find_index(s);return this.items[o][r]=t,c(this.items),!0},find_index(t){return this.items.findIndex(e=>e.pid===t.pid&&e.vid===t.vid)},isInCart(t){return this.find_index(t)>-1},variant(t){return t.product.variants.find(e=>e.id===t.vid)},total(){return this.items.reduce((t,e)=>{const s=this.variant(e);return t+(s?parseFloat(s.rashWeightGrams)*e.qty:0)},0).toFixed(2)},clear(){this.items=[],c(this.items)}}});export{G as a,I as u};
import{g as d,u as F,h as i,m as S}from"./index-CBZSLIgu.js";import{a as P}from"./client-CJxy5iKa.js";function W(t){return!t||t.length===0?null:t.reduce((e,s)=>parseFloat(s.defaultWagePercent)<parseFloat(e.defaultWagePercent)?s:e)}function I(t,e){const s=d(t),r=i(()=>{var n,m;return(m=(n=s.value.images)==null?void 0:n[0])==null?void 0:m.url}),o=i(()=>s.value.id),u=i(()=>s.value.title),l=i(()=>s.value.variants),a=d(e??W(F(l))),v=i(()=>a.value?parseFloat(a.value.rashWeightGrams):0),g=i(()=>a.value?parseFloat(a.value.defaultWagePercent):null),x=d(null),h=i(()=>{var n;return((n=a.value)==null?void 0:n.qty)??0}),f=i(()=>{var n;return((n=a.value)==null?void 0:n.isPreOrder)??!1}),y=i(()=>h.value>0||f.value),_=i(()=>s.value.productCode??null),C=d(!1);return{product:s,image:r,id:o,title:u,productCode:_,variants:l,selectedVariant:a,min_gram:v,wage:g,hasDiscountWage:x,qty:h,isPreOrder:f,is_exist:y,has_warranty:C}}const p="appCart";function q(){try{const t=localStorage.getItem(p);return t?JSON.parse(t):[]}catch{return[]}}function c(t){localStorage.setItem(p,JSON.stringify(t))}const G=S("cart",{state:()=>({items:q()}),actions:{async init(){try{const t=await P.listProducts(),e=[];for(const s of this.items){const r=t.find(u=>u.id===s.pid),o=r==null?void 0:r.variants.find(u=>u.id===s.vid);r&&o&&e.push({...s,product:r})}this.items=e,c(this.items)}catch(t){console.log(t)}},addToCart(t){const e=this.find_index(t);e===-1?this.items.push(t):(this.items[e].product=t.product,this.items[e].qty=t.qty),c(this.items)},remove(t){const e=this.find_index(t);e>-1&&this.items.splice(e,1),c(this.items)},updateFeild(t,e,s,r){if(!this.isInCart(s))return!1;const o=e??this.find_index(s);return this.items[o][r]=t,c(this.items),!0},find_index(t){return this.items.findIndex(e=>e.pid===t.pid&&e.vid===t.vid)},isInCart(t){return this.find_index(t)>-1},variant(t){return t.product.variants.find(e=>e.id===t.vid)},total(){return this.items.reduce((t,e)=>{const s=this.variant(e);return t+(s?parseFloat(s.rashWeightGrams)*e.qty:0)},0).toFixed(2)},clear(){this.items=[],c(this.items)}}});export{G as a,I as u};
@@ -1 +1 @@
import{c as l}from"./Spinner.vue_vue_type_style_index_0_lang-Cw01MXb5.js";var f=function(n){return setTimeout(n,16)},c=function(n){return clearTimeout(n)};typeof window<"u"&&"requestAnimationFrame"in window&&(f=function(n){return window.requestAnimationFrame(n)},c=function(n){return window.cancelAnimationFrame(n)});var i=0,o=new Map;function u(e){o.delete(e)}function w(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1;i+=1;var r=i;function a(t){if(t===0)u(r),e();else{var s=f(function(){a(t-1)});o.set(r,s)}}return a(n),r}w.cancel=function(e){var n=o.get(e);return u(n),c(n)};function m(e,n){for(var r=l({},e),a=0;a<n.length;a+=1){var t=n[a];delete r[t]}return r}function p(e,n,r){return Object.defineProperty(e,"prototype",{writable:!1}),e}function v(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}export{p as _,v as a,m as o,w};
import{c as l}from"./Spinner.vue_vue_type_style_index_0_lang-DQwH-Xdy.js";var f=function(n){return setTimeout(n,16)},c=function(n){return clearTimeout(n)};typeof window<"u"&&"requestAnimationFrame"in window&&(f=function(n){return window.requestAnimationFrame(n)},c=function(n){return window.cancelAnimationFrame(n)});var i=0,o=new Map;function u(e){o.delete(e)}function w(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1;i+=1;var r=i;function a(t){if(t===0)u(r),e();else{var s=f(function(){a(t-1)});o.set(r,s)}}return a(n),r}w.cancel=function(e){var n=o.get(e);return u(n),c(n)};function m(e,n){for(var r=l({},e),a=0;a<n.length;a+=1){var t=n[a];delete r[t]}return r}function p(e,n,r){return Object.defineProperty(e,"prototype",{writable:!1}),e}function v(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}export{p as _,v as a,m as o,w};
+1
View File
@@ -0,0 +1 @@
const a="/api";async function t(e,s){const r=await fetch(`${a}${e}`,{headers:{"Content-Type":"application/json"},...s});if(!r.ok){const o=await r.text();throw new Error(`API ${e} failed (${r.status}): ${o}`)}return r.json()}const c={listProducts:()=>t("/catalog/products"),listCustomers:()=>t("/customers"),getCustomer:e=>t(`/customers/${e}`),getBalance:e=>t(`/accounting/customers/${e}/balance`),getLedgerEntries:e=>t(`/customers/${e}/ledger-entries`),createOrder:e=>t("/orders",{method:"POST",body:JSON.stringify(e)}),getCustomerOrders:e=>t(`/customers/${e}/orders`),getLatestGoldPrice:(e=750)=>t(`/pricing/latest?karatPerMille=${e}`),getHomeSlider:()=>t("/home/slider")};export{c as a};
-1
View File
@@ -1 +0,0 @@
const a="/api";async function t(e,r){const s=await fetch(`${a}${e}`,{headers:{"Content-Type":"application/json"},...r});if(!s.ok){const o=await s.text();throw new Error(`API ${e} failed (${s.status}): ${o}`)}return s.json()}const c={listProducts:()=>t("/catalog/products"),listCustomers:()=>t("/customers"),getCustomer:e=>t(`/customers/${e}`),getBalance:e=>t(`/accounting/customers/${e}/balance`),getLedgerEntries:e=>t(`/customers/${e}/ledger-entries`),createOrder:e=>t("/orders",{method:"POST",body:JSON.stringify(e)}),getCustomerOrders:e=>t(`/customers/${e}/orders`),getLatestGoldPrice:(e=750)=>t(`/pricing/latest?karatPerMille=${e}`)};export{c as a};
+1
View File
@@ -0,0 +1 @@
const s="/assets/dialogEmpty1-DRc_s2oB.svg";export{s as l};

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

-1
View File
@@ -1 +0,0 @@
const s="/assets/dialogEmpty1-B2m57R6G.svg";export{s as l};

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

@@ -1 +1 @@
import{p as e}from"./index-CXDP73fh.js";const t={colors:[],brands:[],ciny_id:[],limit_percent:[],limit_gram:[],has_discount:!1,text:void 0,cats:void 0,page:0},i=e("filters",{state:()=>({query:{...t}}),actions:{reset(){this.query={...t}}}});export{i as u};
import{m as e}from"./index-CBZSLIgu.js";const t={colors:[],brands:[],ciny_id:[],limit_percent:[],limit_gram:[],has_discount:!1,text:void 0,cats:void 0,page:0},i=e("filters",{state:()=>({query:{...t}}),actions:{reset(){this.query={...t}}}});export{i as u};
+1
View File
@@ -0,0 +1 @@
import{a5 as y,d as L,a6 as $,a7 as w,G as A,a8 as B,k as l,g as D,B as M,L as N,a9 as p,M as G,aa as f,ab as I,ac as R,ad as U}from"./index-CBZSLIgu.js";const[Y,r,C]=y("pull-refresh"),x=50,F=["pulling","loosing","success"],X={disabled:Boolean,modelValue:Boolean,headHeight:f(x),successText:String,pullingText:String,loosingText:String,loadingText:String,pullDistance:$,successDuration:f(500),animationDuration:f(300)};var j=L({name:Y,props:X,emits:["change","refresh","update:modelValue"],setup(s,{emit:d,slots:o}){let u;const g=D(),T=D(),H=w(g),e=M({status:"normal",distance:0,duration:0}),i=R(),P=()=>{if(s.headHeight!==x)return{height:`${s.headHeight}px`}},h=()=>e.status!=="loading"&&e.status!=="success"&&!s.disabled,k=t=>{const a=+(s.pullDistance||s.headHeight);return t>a&&(t<a*2?t=a+(t-a)/2:t=a*1.5+(t-a*2)/4),Math.round(t)},n=(t,a)=>{const c=+(s.pullDistance||s.headHeight);e.distance=t,a?e.status="loading":t===0?e.status="normal":t<c?e.status="pulling":e.status="loosing",d("change",{status:e.status,distance:t})},m=()=>{const{status:t}=e;return t==="normal"?"":s[`${t}Text`]||C(t)},E=()=>{const{status:t,distance:a}=e;if(o[t])return o[t]({distance:a});const c=[];return F.includes(t)&&c.push(l("div",{class:r("text")},[m()])),t==="loading"&&c.push(l(N,{class:r("loading")},{default:m})),c},V=()=>{e.status="success",setTimeout(()=>{n(0)},+s.successDuration)},v=t=>{u=I(H.value)===0,u&&(e.duration=0,i.start(t))},b=t=>{h()&&v(t)},_=t=>{if(h()){u||v(t);const{deltaY:a}=i;i.move(t),u&&a.value>=0&&i.isVertical()&&(p(t),n(k(a.value)))}},S=()=>{u&&i.deltaY.value&&h()&&(e.duration=+s.animationDuration,e.status==="loosing"?(n(+s.headHeight,!0),d("update:modelValue",!0),G(()=>d("refresh"))):n(0))};return A(()=>s.modelValue,t=>{e.duration=+s.animationDuration,t?n(+s.headHeight,!0):o.success||s.successText?V():n(0,!1)}),B("touchmove",_,{target:T}),()=>{var t;const a={transitionDuration:`${e.duration}ms`,transform:e.distance?`translate3d(0,${e.distance}px, 0)`:""};return l("div",{ref:g,class:r()},[l("div",{ref:T,class:r("track"),style:a,onTouchstartPassive:b,onTouchend:S,onTouchcancel:S},[l("div",{class:r("head"),style:P()},[E()]),(t=o.default)==null?void 0:t.call(o)])])}}});const z=U(j);export{z as P};
-1
View File
@@ -1 +0,0 @@
import{a3 as y,d as L,a4 as $,a5 as w,G as A,a6 as N,e as c,j as D,C as p,L as B,a7 as C,K as G,a8 as f,a9 as I,aa as M,ab as R}from"./index-CXDP73fh.js";const[U,r,Y]=y("pull-refresh"),x=50,j=["pulling","loosing","success"],F={disabled:Boolean,modelValue:Boolean,headHeight:f(x),successText:String,pullingText:String,loosingText:String,loadingText:String,pullDistance:$,successDuration:f(500),animationDuration:f(300)};var K=L({name:U,props:F,emits:["change","refresh","update:modelValue"],setup(s,{emit:d,slots:o}){let u;const g=D(),T=D(),H=w(g),e=p({status:"normal",distance:0,duration:0}),i=M(),P=()=>{if(s.headHeight!==x)return{height:`${s.headHeight}px`}},h=()=>e.status!=="loading"&&e.status!=="success"&&!s.disabled,k=t=>{const a=+(s.pullDistance||s.headHeight);return t>a&&(t<a*2?t=a+(t-a)/2:t=a*1.5+(t-a*2)/4),Math.round(t)},n=(t,a)=>{const l=+(s.pullDistance||s.headHeight);e.distance=t,a?e.status="loading":t===0?e.status="normal":t<l?e.status="pulling":e.status="loosing",d("change",{status:e.status,distance:t})},m=()=>{const{status:t}=e;return t==="normal"?"":s[`${t}Text`]||Y(t)},E=()=>{const{status:t,distance:a}=e;if(o[t])return o[t]({distance:a});const l=[];return j.includes(t)&&l.push(c("div",{class:r("text")},[m()])),t==="loading"&&l.push(c(B,{class:r("loading")},{default:m})),l},V=()=>{e.status="success",setTimeout(()=>{n(0)},+s.successDuration)},v=t=>{u=I(H.value)===0,u&&(e.duration=0,i.start(t))},b=t=>{h()&&v(t)},_=t=>{if(h()){u||v(t);const{deltaY:a}=i;i.move(t),u&&a.value>=0&&i.isVertical()&&(C(t),n(k(a.value)))}},S=()=>{u&&i.deltaY.value&&h()&&(e.duration=+s.animationDuration,e.status==="loosing"?(n(+s.headHeight,!0),d("update:modelValue",!0),G(()=>d("refresh"))):n(0))};return A(()=>s.modelValue,t=>{e.duration=+s.animationDuration,t?n(+s.headHeight,!0):o.success||s.successText?V():n(0,!1)}),N("touchmove",_,{target:T}),()=>{var t;const a={transitionDuration:`${e.duration}ms`,transform:e.distance?`translate3d(0,${e.distance}px, 0)`:""};return c("div",{ref:g,class:r()},[c("div",{ref:T,class:r("track"),style:a,onTouchstartPassive:b,onTouchend:S,onTouchcancel:S},[c("div",{class:r("head"),style:P()},[E()]),(t=o.default)==null?void 0:t.call(o)])])}}});const q=R(K);export{q as P};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

+3 -3
View File
@@ -9,10 +9,10 @@
<meta name="background-color" content="#1C2D56" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<title>طلای منتزر</title>
<script type="module" crossorigin src="/assets/index-CXDP73fh.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BaaK6U_u.css">
<script type="module" crossorigin src="/assets/index-CBZSLIgu.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CpQh57KC.css">
<link rel="manifest" href="/manifest.webmanifest"></head>
<body style="background-color: #1C2D56">
<body style="background-color: #fff">
<div class="bg-white w-screen h-screen fixed"></div>
<div id="app"></div>␍
</body>
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -10,7 +10,7 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<title>طلای منتزر</title>
</head>
<body style="background-color: #1C2D56">
<body style="background-color: #fff">
<div class="bg-white w-screen h-screen fixed"></div>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
+26 -1
View File
@@ -14,6 +14,13 @@ async function request<T>(path: string, options?: RequestInit): Promise<T> {
return res.json();
}
export interface ProductImageSummary {
id: string;
url: string;
sortOrder: number;
role: 'FEATURED' | 'FEATURED_MOBILE' | 'GALLERY' | 'GALLERY_MOBILE';
}
export interface ProductVariantSummary {
id: string;
title: string;
@@ -25,6 +32,12 @@ export interface ProductVariantSummary {
/// can read them.
qty?: number;
isPreOrder?: boolean;
/// The gallery image chosen for this variant in the admin panel. It is one of
/// the product's OWN images — the same ProductImage row, not a copy — so
/// several variants (e.g. different weights of one design) may share it.
/// Null when no picture was picked; callers fall back to the product image.
imageId?: string | null;
image?: ProductImageSummary | null;
}
export interface CategorySummary {
@@ -53,7 +66,9 @@ export interface ProductSummary {
/// GET /catalog/products.
productCode?: string | null;
variants: ProductVariantSummary[];
images: Array<{ url: string }>;
/// Returned sorted by sortOrder, so images[0] really is the product's main
/// photo rather than whichever row the database happened to hand back.
images: ProductImageSummary[];
category: CategorySummary | null;
brand: BrandSummary | null;
collections: Array<{ collectionId: string; collection: CollectionSummary }>;
@@ -132,6 +147,13 @@ export interface GoldPriceQuote {
quotedAt: string;
}
/** One admin-uploaded home banner slide — raw shape as saved by the admin
* panel's manage/Const.vue "اسلایدر موبایل" tab (image + optional link). */
export interface AdminSlide {
image: string;
link: string;
}
export const api = {
listProducts: () => request<ProductSummary[]>('/catalog/products'),
listCustomers: () => request<CustomerSummary[]>('/customers'),
@@ -141,4 +163,7 @@ export const api = {
createOrder: (dto: CreateOrderDto) => request<OrderSummary>('/orders', { method: 'POST', body: JSON.stringify(dto) }),
getCustomerOrders: (customerId: string) => request<OrderDetail[]>(`/customers/${customerId}/orders`),
getLatestGoldPrice: (karatPerMille = 750) => request<GoldPriceQuote>(`/pricing/latest?karatPerMille=${karatPerMille}`),
/** GET /home/slider — public, no auth. Empty array when the admin hasn't
* configured any slides (the caller falls back to a derived hero). */
getHomeSlider: () => request<AdminSlide[]>('/home/slider'),
};
@@ -1,27 +1,38 @@
<!--
Editorial hero for the home screen. Replaces the legacy swiper banner with a
self-contained, dependency-free slider: no swiper CSS to fight, no autoplay
jitter, and it keeps working when a slide has no artwork.
Editorial hero for the home screen. Self-contained, dependency-free slider:
no swiper CSS to fight, no autoplay jitter, and it keeps working when a
slide has no artwork.
Swipe support: the app sets `direction: rtl !important` on #app (see
src/App.vue), so — same fix as GallerySlider.vue — the track is an isolated
`direction: ltr` subtree (.showcase__track). Inside it, index 0 is first and
a positive translateX moves right, plain LTR arithmetic, regardless of the
page's own direction. The drag gesture itself is still read in screen space
(dragging left = next slide) so it feels natural to an RTL user; only the
track's internal layout/maths is pinned to LTR.
-->
<template>
<section class="showcase" v-if="slides.length">
<div class="showcase__frame">
<transition-group name="showcase-fade" tag="div" class="showcase__stage">
<article v-for="(slide, i) in slides" :key="slide.key" v-show="i === index" class="showcase__slide">
<img v-if="slide.image" :src="slide.image" alt="" class="showcase__art" />
<div class="showcase__scrim" aria-hidden="true"></div>
<div class="showcase__copy">
<span class="showcase__eyebrow">{{ slide.eyebrow }}</span>
<h2 class="showcase__title">{{ slide.title }}</h2>
<p class="showcase__sub">{{ slide.subtitle }}</p>
<button type="button" class="showcase__cta" @click="emit('select', slide)">
{{ slide.cta }}
<Icon icon="vuesax-linear:arrow-left-2" size="17" />
</button>
</div>
<div
ref="root"
class="showcase__frame"
:class="{ 'is-dragging': dragging }"
@pointerdown="onPointerDown"
@pointermove="onPointerMove"
@pointerup="onPointerUp"
@pointercancel="onPointerCancel"
>
<div class="showcase__track" :style="trackStyle">
<article
v-for="(slide, i) in slides"
:key="slide.key"
class="showcase__slide"
:class="{ 'is-active': i === index }"
@click="onSlideClick(slide)"
>
<img v-if="slide.image" :src="slide.image" alt="" class="showcase__art" draggable="false" />
</article>
</transition-group>
</div>
</div>
<div class="showcase__dots" v-if="slides.length > 1">
@@ -39,8 +50,7 @@
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import Icon from '../icon/Icon.vue'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
export interface ShowcaseSlide {
key: string
@@ -50,6 +60,9 @@ export interface ShowcaseSlide {
cta: string
image?: string
categoryId?: string
/** Admin-uploaded slide's own destination (manage/Const.vue), when it has
* one. Takes priority over `categoryId` in the click handler. */
link?: string
}
const props = defineProps<{ slides: ShowcaseSlide[] }>()
@@ -75,6 +88,98 @@ onMounted(restart)
onBeforeUnmount(() => {
if (timer) clearInterval(timer)
})
// ── Drag / swipe ─────────────────────────────────────────────
const root = ref<HTMLElement | null>(null)
const dragging = ref(false)
const dragX = ref(0)
let pointerId: number | null = null
let startX = 0
let startY = 0
let trackWidth = 0
let isSwipe = false
const DRAG_COMMIT_RATIO = 0.18
const TAP_MAX_PX = 6
function onPointerDown(e: PointerEvent) {
if (props.slides.length < 2 || pointerId !== null) return
const el = root.value
if (!el) return
pointerId = e.pointerId
startX = e.clientX
startY = e.clientY
trackWidth = el.getBoundingClientRect().width || 1
dragX.value = 0
dragging.value = true
isSwipe = false
el.setPointerCapture?.(e.pointerId)
}
function onPointerMove(e: PointerEvent) {
if (!dragging.value || e.pointerId !== pointerId) return
const dx = e.clientX - startX
const dy = e.clientY - startY
if (!isSwipe && Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > TAP_MAX_PX) isSwipe = true
if (isSwipe) dragX.value = dx
}
function endDrag() {
if (!dragging.value) return
const dx = dragX.value
const ratio = dx / trackWidth
dragging.value = false
pointerId = null
dragX.value = 0
// Screen-space drag direction: dragging left (negative dx) is "next slide",
// matching what the gesture means to the person doing it.
if (ratio <= -DRAG_COMMIT_RATIO && index.value < props.slides.length - 1) index.value++
else if (ratio >= DRAG_COMMIT_RATIO && index.value > 0) index.value--
if (isSwipe) restart()
isSwipe = false
}
function onPointerUp(e: PointerEvent) {
if (e.pointerId !== pointerId) return
endDrag()
}
function onPointerCancel(e: PointerEvent) {
if (e.pointerId !== pointerId) return
dragging.value = false
pointerId = null
dragX.value = 0
isSwipe = false
}
function onSlideClick(slide: ShowcaseSlide) {
// A drag also fires a trailing click on release; only treat it as a tap
// (i.e. open the slide) when the gesture never turned into a swipe.
if (isSwipe) return
emit('select', slide)
}
const trackStyle = computed(() => {
const base = -index.value * 100
const dragPercent = trackWidth ? (dragX.value / trackWidth) * 100 : 0
return {
transform: `translate3d(${base + dragPercent}%, 0, 0)`,
transition: dragging.value ? 'none' : undefined,
}
})
onBeforeUnmount(() => {
if (pointerId !== null && root.value) {
try {
root.value.releasePointerCapture(pointerId)
} catch {
/* element may already be detached */
}
}
})
</script>
<style scoped lang="less">
@@ -82,90 +187,80 @@ onBeforeUnmount(() => {
position: relative;
border-radius: 22px;
overflow: hidden;
background: @ink;
// Neutral rather than @ink: this only shows before artwork loads, and a
// dark fill read as an unwanted border wherever it was visible at all.
background: @hairlineSoft;
box-shadow: 0 26px 50px -34px rgba(20, 22, 26, 0.85);
aspect-ratio: 320 / 208;
touch-action: pan-y;
user-select: none;
-webkit-user-select: none;
// Forces its own compositing layer so `overflow: hidden` actually clips the
// translated track on Safari/iOS — without this, a sliver of the next
// slide peeks past the rounded edge because the browser composites the
// transformed child (.showcase__track) on a layer that ignores the
// parent's clip until it's promoted the same way.
transform: translateZ(0);
-webkit-transform: translateZ(0);
}
.showcase__stage {
position: relative;
display: block;
aspect-ratio: 320 / 208;
// Isolated from the page's `direction: rtl` — see the file header. Everything
// under this node uses plain LTR layout and LTR-signed transforms.
.showcase__track {
direction: ltr;
display: flex;
height: 100%;
width: 100%;
// A gentle, slightly-overshooting ease — softer settle than a linear/
// ease-out curve, which is what makes the swipe feel "alive" rather than
// mechanical. Slowed down a touch from the old 0.42s so the motion reads
// as a deliberate glide instead of a snap.
transition: transform 0.56s cubic-bezier(0.16, 0.86, 0.3, 1);
will-change: transform;
}
.showcase__frame.is-dragging .showcase__track {
transition: none;
}
.showcase__slide {
position: absolute;
inset: 0;
position: relative;
flex: 0 0 100%;
width: 100%;
height: 100%;
cursor: pointer;
// Clips its own image's scale-in (.showcase__art below) to this slide's own
// box, so the 1.06x zoom never bleeds into the neighbouring slide.
overflow: hidden;
}
.showcase__art {
position: absolute;
inset: 0;
// A plain block filling the slide, NOT an absolutely-positioned box.
// `position: absolute` + `inset` made the image's own box a second,
// independently-rounded measurement of the same area the frame already
// sizes via `aspect-ratio`; on real devices the two disagreed by a
// fraction of a pixel and the frame's dark background showed through as a
// hairline border around the artwork. Sizing it as ordinary in-flow
// content removes that second measurement entirely.
display: block;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.5;
transform: scale(1.04);
-webkit-user-drag: none;
user-select: none;
// Never settles below 1x: the "breathe in" flourish now runs from a larger
// scale down to exactly 1, so the image is always at least as big as the
// slide and can never reveal what sits behind it.
transform: scale(1.06);
transition: transform 0.56s cubic-bezier(0.16, 0.86, 0.3, 1);
}
.showcase__scrim {
position: absolute;
inset: 0;
background:
linear-gradient(255deg, rgba(122, 27, 51, 0.55) 0%, rgba(122, 27, 51, 0) 52%),
linear-gradient(to left, rgba(20, 22, 26, 0.2) 0%, rgba(20, 22, 26, 0.92) 72%);
.showcase__slide.is-active .showcase__art {
transform: scale(1);
}
.showcase__copy {
position: absolute;
inset: 0;
padding: 22px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
color: #fff;
}
.showcase__eyebrow {
font-size: 10.5px;
letter-spacing: 1.6px;
color: rgba(255, 255, 255, 0.62);
padding-bottom: 9px;
}
.showcase__title {
font-size: 22px;
font-weight: 800;
line-height: 1.35;
color: #fff;
margin: 0 0 7px;
}
.showcase__sub {
font-size: 12.5px;
line-height: 1.85;
color: rgba(255, 255, 255, 0.7);
margin: 0 0 16px;
max-width: 30ch;
}
.showcase__cta {
display: inline-flex;
align-items: center;
gap: 7px;
border: 0;
cursor: pointer;
padding: 9px 16px;
border-radius: 999px;
background: #fff;
color: @ink;
font-size: 12.5px;
font-weight: 700;
font-family: inherit;
transition: transform 0.18s ease, background 0.18s ease;
}
.showcase__cta:active {
transform: scale(0.97);
.showcase__frame.is-dragging .showcase__art {
transition: none;
}
.showcase__dots {
@@ -183,19 +278,10 @@ onBeforeUnmount(() => {
cursor: pointer;
border-radius: 999px;
background: @hairline;
transition: all 0.25s ease;
transition: width 0.42s cubic-bezier(0.16, 0.86, 0.3, 1), background 0.3s ease;
}
.showcase__dot.is-active {
width: 20px;
background: @wine;
}
.showcase-fade-enter-active,
.showcase-fade-leave-active {
transition: opacity 0.55s ease;
}
.showcase-fade-enter-from,
.showcase-fade-leave-to {
opacity: 0;
}
</style>
@@ -30,7 +30,13 @@
<div class="ci__row">
<div class="ci__qty">
<button type="button" class="ci__qtyBtn" aria-label="افزودن" @click="increment">
<button
type="button"
class="ci__qtyBtn"
aria-label="افزودن"
:disabled="!canIncrement"
@click="increment"
>
<Icon icon="vuesax-linear:add" size="16" />
</button>
<span class="ci__qtyValue">{{ value.qty }}</span>
@@ -71,7 +77,13 @@ const emit = defineEmits<{ (e: 'note', value: number): void }>()
const cart = useCartStore()
const index = cart.find_index(props.value)
// Stock ceiling, same rule as the product page: uncapped for a pre-order
// variant, otherwise limited to what is on hand. The store clamps as well.
const maxQty = computed(() => cart.maxQty(props.value))
const canIncrement = computed(() => maxQty.value === null || props.value.qty < maxQty.value)
const increment = () => {
if (!canIncrement.value) return
cart.updateFeild(props.value.qty + 1, index, props.value, 'qty')
}
const decrement = () => {
@@ -102,22 +102,55 @@
</div>
</div>
<!-- Variants -->
<section v-if="variants && variants.length > 1" class="pd__block">
<h2 class="pd__blockTitle">انتخاب وزن</h2>
<div class="pd__variants no-scrollbar">
<!--
Variants. Each chip carries the variant's OWN gallery picture when the
admin picked one, so two variants of the same weight (say plain vs.
stone-set) are told apart at a glance instead of only by title — and
several weights of one design correctly show the same photo.
Shown from one variant up (not two): with a picture and a stock badge
the chip is worth seeing even when there is only one choice.
The row wraps rather than scrolling sideways: past ~4 chips a
horizontal strip hides the rest off-screen, and products here can have
10+ weights. Beyond two rows the extra chips collapse behind a toggle.
-->
<section v-if="variants && variants.length" class="pd__block">
<h2 class="pd__blockTitle">انتخاب تنوع</h2>
<div class="pd__variants">
<button
v-for="item in variants"
v-for="item in visibleVariants"
:key="item.id"
type="button"
class="pd__variant"
:class="{ 'is-on': selectedVariant?.id === item.id }"
:class="{
'is-on': selectedVariant?.id === item.id,
'is-out': !isOrderable(item),
}"
:disabled="!isOrderable(item)"
@click="selectedVariant = item"
>
<img
v-if="variantImage(item)"
class="pd__variantImg"
:src="variantImage(item)"
:alt="item.title"
/>
<span class="pd__variantTitle">{{ item.title }}</span>
<span class="pd__variantWeight">{{ Number(item.rashWeightGrams) }} گرم</span>
<span class="pd__variantStock" :class="stockChipClass(item)">
{{ stockChipLabel(item) }}
</span>
</button>
</div>
<button
v-if="variants.length > VARIANT_PREVIEW_COUNT"
type="button"
class="pd__variantsMore"
@click="showAllVariants = !showAllVariants"
>
{{ showAllVariants ? 'نمایش کمتر' : `نمایش همه (${variants.length})` }}
</button>
</section>
<!-- Specs -->
@@ -166,7 +199,13 @@
<!-- Action bar -->
<div class="pd__bar">
<div v-if="inCart" class="pd__qty">
<button type="button" class="pd__qtyBtn" aria-label="افزایش" @click="increment">
<button
type="button"
class="pd__qtyBtn"
aria-label="افزایش"
:disabled="!canIncrement"
@click="increment"
>
<Icon icon="vuesax-linear:add" size="16" />
</button>
<span class="pd__qtyValue">{{ cartQty }}</span>
@@ -264,8 +303,9 @@ import GallerySlider from './GallerySlider.vue'
import Spinner from '../Spinner.vue'
import NotifyVant from '../NotifyVant.vue'
import DialogVant from '../DialogVant.vue'
import { useProduct } from '../../composables/useProduct'
import { useProduct, isVariantOrderable } from '../../composables/useProduct'
import { useProductDetail } from '../../composables/useProductDetail'
import type { ProductVariantSummary } from '../../api/client'
import { useFavoritesStore } from '../../stores/favoritesStore'
import { useCartStore, type CartItem } from '../../stores/cartStore'
import { isUserLoggedIn } from '../../utils/checkAccess'
@@ -324,6 +364,34 @@ const qty = computed(() => productAdapter.value.qty.value)
const isPreOrder = computed(() => productAdapter.value.isPreOrder.value)
const is_exist = computed(() => productAdapter.value.is_exist.value)
// ── Variant chips ───────────────────────────────────────────────
// Two rows' worth is shown up front; the rest sit behind "نمایش همه" so a
// product with 10+ weights does not push the description off the screen.
const VARIANT_PREVIEW_COUNT = 6
const showAllVariants = ref(false)
const visibleVariants = computed(() =>
showAllVariants.value ? variants.value : variants.value.slice(0, VARIANT_PREVIEW_COUNT),
)
const isOrderable = (v: ProductVariantSummary) => isVariantOrderable(v)
/**
* The chip picture: the variant's own image when the admin picked one, else the
* product's main photo so chips never render as empty boxes. Variants sharing
* one image (same design, several weights) intentionally show the same picture.
*/
const variantImage = (v: ProductVariantSummary) =>
v.image?.url ?? productDetail.productRef.value?.images?.[0]?.url ?? ''
const stockChipLabel = (v: ProductVariantSummary) => {
if ((v.qty ?? 0) > 0) return 'موجود'
return v.isPreOrder ? 'پیش‌سفارش' : 'ناموجود'
}
const stockChipClass = (v: ProductVariantSummary) => {
if ((v.qty ?? 0) > 0) return 'is-in'
return v.isPreOrder ? 'is-pre' : 'is-none'
}
const body = computed(() => productDetail.productRef.value?.description ?? '')
const bodyIsLong = computed(() => body.value.length > 120)
const categoryTitle = computed(() => productDetail.productRef.value?.category?.title ?? '')
@@ -336,6 +404,16 @@ watch(slides, (list) => {
if (imageIndex.value > list.length - 1) imageIndex.value = 0
})
// Picking a variant scrolls the gallery to that variant's photo, so the chosen
// chip and the big picture always agree. Only moves when the variant actually
// has an image and it is one of the product's own slides.
watch(selectedVariant, (v) => {
const url = v?.image?.url
if (!url) return
const i = slides.value.indexOf(url)
if (i > -1) imageIndex.value = i
})
// ── Full-screen preview ─────────────────────────────────────────
// Tapping the inline gallery (a plain tap, not a swipe — GallerySlider tells
// the two apart itself and only emits `tap` for the former) opens a
@@ -385,7 +463,14 @@ const inCart = computed(() => cart.isInCart(storeProduct.value))
const cartIndex = computed(() => cart.find_index(storeProduct.value))
const cartQty = computed(() => (cartIndex.value > -1 ? cart.items[cartIndex.value].qty : 0))
const increment = () => cart.updateFeild(cartQty.value + 1, cartIndex.value, storeProduct.value, 'qty')
// Stock ceiling: a pre-order variant may exceed what is on hand, anything else
// stops at its qty. The store clamps too — this just keeps the button honest.
const cartMaxQty = computed(() => cart.maxQty(storeProduct.value))
const canIncrement = computed(() => cartMaxQty.value === null || cartQty.value < cartMaxQty.value)
const increment = () => {
if (!canIncrement.value) return
cart.updateFeild(cartQty.value + 1, cartIndex.value, storeProduct.value, 'qty')
}
const decrement = () => {
if (cartQty.value <= 1) {
cart.remove(storeProduct.value)
@@ -623,20 +708,22 @@ onBeforeUnmount(() => {
color: @ink;
}
/* Wraps instead of scrolling sideways — see the template comment: a product
may have 10+ weights and off-screen chips are chips nobody taps. */
.pd__variants {
display: flex;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
overflow-x: auto;
}
.pd__variant {
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 3px;
padding: 10px 14px;
padding: 8px;
border-radius: 14px;
cursor: pointer;
text-align: start;
text-align: center;
align-items: center;
background: @canvas;
border: 1px solid @hairline;
transition: border-color 0.18s ease, background 0.18s ease;
@@ -645,6 +732,54 @@ onBeforeUnmount(() => {
background: @ink;
border-color: @ink;
}
.pd__variantImg {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 10px;
margin-bottom: 2px;
}
/* Out of stock and not pre-orderable: still listed, so the customer can see
the weight exists, but visibly dimmed and not tappable. */
.pd__variant.is-out {
opacity: 0.45;
cursor: not-allowed;
}
.pd__variantStock {
font-size: 9.5px;
font-weight: 700;
padding: 1px 6px;
border-radius: 999px;
margin-top: 1px;
}
.pd__variantStock.is-in {
color: #1a7f3c;
background: rgba(26, 127, 60, 0.1);
}
.pd__variantStock.is-pre {
color: #1f6feb;
background: rgba(31, 111, 235, 0.1);
}
.pd__variantStock.is-none {
color: @inkFaint;
background: rgba(0, 0, 0, 0.05);
}
.pd__variant.is-on .pd__variantStock {
color: #fff;
background: rgba(255, 255, 255, 0.16);
}
.pd__variantsMore {
margin-top: 10px;
width: 100%;
padding: 8px;
border-radius: 12px;
border: 1px solid @hairline;
background: transparent;
color: @ink;
font-size: 12px;
font-weight: 700;
cursor: pointer;
}
.pd__variantTitle {
font-size: 12.5px;
font-weight: 700;
+18 -2
View File
@@ -21,20 +21,36 @@
import { computed, ref, unref, type Ref } from 'vue'
import type { ProductSummary, ProductVariantSummary } from '../api/client'
/** A variant can be ordered when it has stock, or when it is flagged pre-order. */
export function isVariantOrderable(v: ProductVariantSummary): boolean {
return (v.qty ?? 0) > 0 || Boolean(v.isPreOrder)
}
function getCheapestVariant(variants: ProductVariantSummary[] | undefined): ProductVariantSummary | null {
if (!variants || variants.length === 0) return null
return variants.reduce((cheapest, v) =>
// Prefer something the customer can actually order: defaulting to an
// out-of-stock variant means the page opens on a disabled button even though
// other weights are available. Falls back to the full list when nothing is
// orderable, so the page still shows a selection.
const pool = variants.filter(isVariantOrderable)
const candidates = pool.length ? pool : variants
return candidates.reduce((cheapest, v) =>
parseFloat(v.defaultWagePercent) < parseFloat(cheapest.defaultWagePercent) ? v : cheapest,
)
}
export function useProduct(productItem: ProductSummary, initialVariant?: ProductVariantSummary) {
const product = ref<ProductSummary>(productItem)
const image = computed(() => product.value.images?.[0]?.url)
const id = computed(() => product.value.id)
const title = computed(() => product.value.title)
const variants = computed(() => product.value.variants)
const selectedVariant: Ref<ProductVariantSummary | null> = ref(initialVariant ?? getCheapestVariant(unref(variants)))
// The selected variant's own picture when the admin chose one, otherwise the
// product's main image. Several variants may legitimately resolve to the SAME
// image — one photo, several weights.
const image = computed(
() => selectedVariant.value?.image?.url ?? product.value.images?.[0]?.url,
)
const min_gram = computed(() => selectedVariant.value ? parseFloat(selectedVariant.value.rashWeightGrams) : 0)
const wage = computed(() => (selectedVariant.value ? parseFloat(selectedVariant.value.defaultWagePercent) : null))
const hasDiscountWage = ref<number | null>(null) // no promotions backend yet — see file header
+4 -1
View File
@@ -4,7 +4,10 @@ import VueLazyLoad from 'vue3-lazyload';
import App from './App.vue';
import { router } from './router';
import Container from './components/ui/Container.vue';
import Vector from './assets/img/Vector.svg';
// TODO: temporary placeholder — swap Vector.svg back in (or a proper loading
// mark) once one exists; montzar-logo.png is the brand logo, borrowed here
// just so lazy-loaded images have something other than a broken icon.
import Vector from './assets/img/montzar-logo.png';
// Global styles, ported from legacy henza_pwa/src/main.ts — same import order
// (ant-design-vue's own theme first, then our Less overrides on top). Legacy
+9 -2
View File
@@ -87,9 +87,16 @@ router.afterEach((to) => {
transition.setTransitionFlag(true);
}, 100);
// Unconditional on both branches: this hook is the single source of truth for
// tab-bar visibility. A screen may hide the bar for its own reasons while it
// is open (SearchView does, for its filter sheet), and this is what clears
// that override on the way out — the old `if (!nav.showNav)` guard made the
// same write, just phrased as if something else might own the flag.
const route = nav.navBarRoutes.find((x) => to.name === x.name);
if (route) {
nav.setActiveLink(route.index);
if (!nav.showNav) nav.setNavVisibility(true);
} else nav.setNavVisibility(false);
nav.setNavVisibility(true);
} else {
nav.setNavVisibility(false);
}
});
+38 -2
View File
@@ -54,13 +54,42 @@ export const useCartStore = defineStore('cart', {
}
},
addToCart(data: CartItem) {
// Refuse a variant that cannot be ordered — out of stock and not flagged
// pre-order. The same guard the admin cart applies (stores/cart.ts), kept
// here so it holds even if a caller forgets to disable its button.
const target = data.product?.variants?.find((v) => v.id === data.vid)
if (!target) return false
if (!((target.qty ?? 0) > 0 || target.isPreOrder)) return false
const index = this.find_index(data)
if (index === -1) this.items.push(data)
if (index === -1) this.items.push({ ...data, qty: this.capQty(data.qty, target) })
else {
this.items[index].product = data.product
this.items[index].qty = data.qty
this.items[index].qty = this.capQty(data.qty, target)
}
persist(this.items)
return true
},
/**
* Stock ceiling for a cart line. A pre-order variant is orderable beyond
* what is on hand (that is the point of pre-ordering), so it is uncapped;
* anything else stops at its on-hand quantity.
*/
capQty(want: number, variant: { qty?: number; isPreOrder?: boolean }) {
const n = Math.max(1, Math.floor(want) || 1)
if (variant.isPreOrder) return n
const max = variant.qty ?? 0
return max > 0 ? Math.min(n, max) : n
},
/** The ceiling for an item already in the cart; null when uncapped. */
maxQty(item: Pick<CartItem, 'pid' | 'vid'>) {
const i = this.find_index(item)
if (i === -1) return null
const v = this.variant(this.items[i])
if (!v || v.isPreOrder) return null
return (v.qty ?? 0) > 0 ? (v.qty as number) : null
},
remove(item: CartItem) {
const index = this.find_index(item)
@@ -72,6 +101,13 @@ export const useCartStore = defineStore('cart', {
updateFeild(value: unknown, index: number | null, item: Pick<CartItem, 'pid' | 'vid'>, field: keyof CartItem) {
if (!this.isInCart(item)) return false
const i = index ?? this.find_index(item)
// A quantity change is clamped to what is actually in stock (unless the
// variant is pre-orderable), so the ceiling holds no matter which screen
// drives the stepper.
if (field === 'qty') {
const v = this.variant(this.items[i])
value = v ? this.capQty(Number(value), v) : Math.max(1, Number(value) || 1)
}
;(this.items[i] as any)[field] = value
persist(this.items)
return true
+44 -4
View File
@@ -138,7 +138,7 @@ import type { HomeCategory } from '../stores/configStore'
import { useCartStore } from '../stores/cartStore'
import { useFiltersStore } from '../stores/filtersStore'
import { api } from '../api/client'
import type { GoldPriceQuote, ProductSummary } from '../api/client'
import type { AdminSlide, GoldPriceQuote, ProductSummary } from '../api/client'
const router = useRouter()
const memory = useConfigStore()
@@ -149,6 +149,10 @@ const loading = ref(true)
const refreshing = ref(false)
const products = ref<ProductSummary[]>([])
const goldPrice = ref<GoldPriceQuote | null>(null)
// Admin-managed banner slides (manage/Const.vue "اسلایدر موبایل"). null while
// unfetched/unavailable — distinct from "fetched, empty" — so `slides` below
// knows whether to wait or fall back to the category-derived hero.
const adminSlides = ref<AdminSlide[] | null>(null)
const productDrawer = ref(false)
const activeProductId = ref<string | null>(null)
@@ -157,9 +161,12 @@ const featured = computed<ProductSummary | null>(() => products.value[0] ?? null
const gridProducts = computed(() => products.value.slice(1, 5))
const newestProducts = computed(() => products.value.slice(5, 13))
// The hero is built from REAL categories, not a curated banner payload (none
// exists). Each slide deep-links into search filtered by that category, so the
// artwork is decorative but the destination is genuine.
// The hero prefers the admin-uploaded banner (manage/Const.vue "اسلایدر
// موبایل") when one has been configured; otherwise it falls back to a hero
// built from REAL categories, since no curated banner payload existed before
// that admin screen was wired up. Each fallback slide deep-links into search
// filtered by that category, so the artwork is decorative but the
// destination is genuine.
const SLIDE_COPY = [
{ eyebrow: 'مجموعه منتزر', cta: 'دیدن مجموعه' },
{ eyebrow: 'انتخاب سردبیر', cta: 'مشاهده' },
@@ -167,6 +174,20 @@ const SLIDE_COPY = [
]
const slides = computed<ShowcaseSlide[]>(() => {
if (adminSlides.value?.length) {
return adminSlides.value
.filter((s) => s.image)
.map((s, i) => ({
key: `${i}-${s.image}`,
eyebrow: 'مجموعه منتزر',
title: '',
subtitle: '',
cta: '',
image: s.image,
link: s.link || undefined,
}))
}
const cats = memory.cats.slice(0, 3)
if (!cats.length) return []
return cats.map((cat, i) => ({
@@ -196,6 +217,17 @@ function onCategory(cat: HomeCategory) {
}
function onSlide(slide: ShowcaseSlide) {
// Admin-uploaded slides (manage/Const.vue) carry their own destination
// instead of a categoryId — an absolute URL opens in a new tab, anything
// else is treated as an in-app path.
if (slide.link) {
if (/^https?:\/\//i.test(slide.link)) {
window.open(slide.link, '_blank', 'noopener')
} else {
router.push(slide.link)
}
return
}
if (slide.categoryId) {
filters.query.cats = [slide.categoryId]
}
@@ -221,6 +253,14 @@ async function loadData() {
} catch {
goldPrice.value = null
}
try {
adminSlides.value = await api.getHomeSlider()
} catch {
// No admin slides configured, or the endpoint failed — the category-
// derived hero below covers this silently, same as before this existed.
adminSlides.value = null
}
}
async function onRefresh() {
@@ -112,6 +112,7 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
import { PullRefresh } from 'vant'
import Icon from '../../components/icon/Icon.vue'
import PageBar from '../../components/ui/PageBar.vue'
@@ -246,6 +247,22 @@ function onBarClick(e: MouseEvent) {
}
}
// The filter sheet deliberately hides the bottom tab bar while it is open, so
// its own fixed action bar ("اعمال فیلتر" / "حذف فیلترها") stays clickable —
// the tab bar sits at the same bottom edge with a higher z-index. But leaving
// the page with the sheet still open (browser/swipe back, or tapping a
// collection tile) never ran hideFilters, so that hide leaked: showNav stayed
// false, and on any destination outside the five tab routes the user was left
// with no tab bar at all until a full page refresh reset the store.
//
// Restoring it here rather than in onBeforeUnmount is deliberate: this guard
// runs BEFORE router.afterEach, which then writes the correct visibility for
// the destination and gets the last word. onBeforeUnmount runs after it, and
// would wrongly re-show the bar on full-page routes like /product/:id.
onBeforeRouteLeave(() => {
if (showFilter.value) nav.setNavVisibility(true)
})
onMounted(loadProducts)
</script>