|?b7l>r^ zs$}$9V&khLtu<0gthL0(U>sN!qZP1aLwD{>;B-^mhX(>WbdPb+K*Hz yn4E5z0k8$mG^ z94!h?loUT1D)8)Uf)8Ii!4+K*N(dZoy3z!+>6rB$QQZKfbVECVFV+CKVWB8Jt6@!h z%=YCmZ(bU)rX!{&W5@@-V6rwL!KOIyT1qLUFR~m^s#G~O9&@am;nkvI-x0}o2Q!?m zh{ `4 m zdh=yvcCW6oy2H{DI kM4i)2 zo*C9Wb}Znnt1bD!O$)|KO4>3KDN<7n^++4ALeru(TUx@$b{f{_i!2EvIy2tyLZaMS z6>3dl?rzc>)cm?}5@RfZg7HXj-%~lhaVSGE5^1Z@vje7sPai07RZq;u?$`(9DRi}U z{@P7bnq_Qm834|Kj>cJCsGy|x;nNd9FtyP>BP|>%OHP#pzZelr#EM(j#l%ifj$y1S zF3LYUV5B10`*O&JPJ`C|S{)7ql%iBj=bYV;rbUbAjDsH?*XsqNT%_crxd%Dcd-I zv(ATD9B{I%_|tuPemWdbtO^1JYdS{R+-q3h*_dHz9Xxm_$DNl)3>2b-De|8$$pg&; zV3nkWbNj!4G|Q1Oul%zJEFl=KC=M4DKRKbXC}JykYDn|g@sQIMfpI?5d95ta3f6U= zO()D%PL%~;`gusj_ I#r<+MN=YA{X^&tNPau>WL0#Z)Q9&>mV&RT{&h zlwx?``7CR iLZ43)jYj*SZ*JrXiloUVKUWP}gMvyHwN zMieoUwv6DKzQ(2}dtc46Z%|^Kpll?AqpmJCv`)#ja<2#ghRcHIPAOvNn 5>JvdT!w z^21|I_0S~^m{wcCfs+9d0Ucp{&XhHfUZd@y<&O0gA|%c_l0_EZB%{dBzW2`C~ zI!MZ~w=~z>-F&JN7;ZHHV^zU{p>vN~DWGZuu@$^lk_=ZhL*sCGTyv_bc=nX$7pHud zq9qN>gr-Vl1rE_{RSaujh$im{GMoJHSiq*9m>C45r=*obE6G?axp#kthhGXOgK;e$ zEG<|*v#UsV# smYj#9hKN}d_oY} z+6+$bo{S@*m<1W-*tDeaUQ`K}a8*r}LlVEUU`s>*x38<9B@`pU^TX50y3I>sRN{WD zg<@53x*}(F1jfRPBOs+ 3j^(t4;Jk9o9B~*8hE;uXB5uz=iA45?v!R# zr{MMtMTSd)>z2lR zT&O@vK}I^R?Ta{cx`DUg98C@Z&(sRBV)CXXov~63`;LY@eNs<$nFO$< zH)dtKO|R}EeU}HXQOu=h zLuonyatZ(~k$m7N%(73z)O0kEU=avsIbD&&)&mn;|Ee1AqhkwCpHvtN18ugU`#)Ta z@>6`(;CJqw1mNLTQ4+>pxWOGrhjW5lsL=BK2mjz`$ngn9RymgDZDRqLBMK>o!4owG zq6WZl%d9|ncQZQ&BNG0{p`}AQ!^$>GPJ7Gg&N`Ol9DO-USH{tow{&GJy?M~WaaFfz z;APHIqBl;yF_jIi$pf@t+ul%~QS?lHs4L_AH1lM7$eK?0n;j)TsW!GK;hQu9OQ?LI zR*VFpv=p+ir7z~|hr$K{;Lch@me&2GfbHKWtN$4QG<_Fw=e!%5DZM#MHSzVO*dG{M zix!U46?_|0fR>KPO3JZ!Wvki^) )`&^*mHo98bfyIi 5Ot1C+Y+()da53O?{(h`Q@F=gLGyr6S23DLg1K)EETJHW>{UY+42t)d3LWJr7PoD z*>3sSYZq6L3E=_n2 V3spio `2Y3yd)w zEvDX!0pkQ(N!E9{i`sT3r{Rybm3TwHWZQs`FAb6}&Zbv=4x~N?{Bu)+u$#RVS&Rhj zu@A7uf|8D3UKz3BSBn%Yj)_=cogg1LiV2mG)i54GUc=Qr@g$I01rzbyz2h7Ez56K} zflL~c?mX6#Vhvd}(J5&FsG;>CTDVVKMtKX60{Zg~>jZ&vtnY{t#Yn9645e{Q_G>+R zY9~!Os~iJuhJzz>3&awzCI%s>7#NMtZGt-e0>00m%d6<~_^S^B-*1Km$aA=+8tGOD zMG^=VPo40ypabbBMv| >UZ<~E_qF8~oZ>sRVbjVE(tT7Qr8%sjbJi2Dd|tdZI0lS2V7kE&TLz)em+ zcTS+B!$Pu_;Oy7b(!Vy9{1+pVP{Hyx$mqFsw0tv25C#e*d`)t` <*awQQu-~$q&U;5 zQo tD)6bGQyiC c(U)r?XgKB$9Qz4hNhVH}rHWDo(KX zW$iclOHa&w2l!}e!0WiSLEx?UC(Si =_naNWCcn%a>_HDYdQ=A z1w&`Xp%NgROBQihpIJr57j$ibw~C*il642-su6tUSxIj; 9zR~!l*h+`+y86( zW9HZPZA%yQ=kPGk>k|;>WgB~ulH !0n`bNWo$f zPjgW3$lvj;T?Y q%I?>Td;-|L@3xnUD^{$i%jaKA z8hSn%0(Rq{I(iRHp6J`1^?iWIFm3vJppvPNm8P9~7 K_@ zo+-Z*_!lm{{ih!Ve!J1`wi)Y$9|5ig{&v1n)h3Mk_ctrnHEW@EF)7EdO#oS}@;Tsg zd`GJ(((IM;&m^hpuj41AE*AN6l34ssv(xNWZB_8K u!YI{p7V_Cp(Jn~#B(*z fC0W^ml>Zw5E`54rp3?Xe00000NkvXXu0mjfszuK3 literal 0 HcmV?d00001 diff --git a/src/static/tabbar/tabbar-produce.png b/src/static/tabbar/tabbar-produce.png new file mode 100644 index 0000000000000000000000000000000000000000..8e39f73b324076cbd10911dad220d2e5b2bb2f68 GIT binary patch literal 12100 zcmV-KFT2o*P) Px#1ZP1_K>z@;j|==^1pojp?ny*JRCr$1eF>Bl)xCao_1@FnGd=r03 +YBH(!|eOM z^}hVS?^e}J&jQSb@;**+t8U%8%WuE8ZuRJ-ivzOBXv|K}$hh|M%P#-7$@%$9bUK}k z19y}z@?2a?VR0RaM8vsHXB5|jEX(Sd0+tU0$BrG_x@*_2wRLrM+XI0>1#T&oTm<+c z86aD&)=OqgpYh |##E-%7Qf#geE HdARz727A{=)Y<_ igq9bbYJ?rEyk?eQiNt-a44 C&ZZva+%+B{67Xm}&&p2oilxMCWVhf6hZAKGFXf?Y_nYLc13Y zGD0g?R#sNJZr!>SFi(fo+ZPlAdoxA=p%WJ^TC^7CW{D |9Z8Qht@VzY6(;J^Z4=O#jn5q`VC-ClPGY3(A%@IgFJrx`0w0& z^UcqY7#s`_ZNM4 2=d;mIZT7W zkT4m7Kq#Y=BO=1#J%TCk6NqHRb8x?;tf;s5S`-n8?i0^>unw)AuCA`OKm6ejSHmow zP>YQj`ch*Q$jr=KwS4*Vmq`o`Qadz=fvajBtr1~K8Kf*5B+wh6S)inb!d+eNlJbhu zf+L?D-r3mDP#g&OtB~K0LVg??2{{Inte0cWCUd4MK4DgRdd4*{ee;k`Fj~wqszRM% z$zU`{diDu+4U-JP6fFviM)Y+! 63rOy)g+3!R(arc@rO4Fn|8)wDk0e zCX)%86%hRt!l0VC{{1AxI3kLJW?3F^(kEa3%PTW*n?f*ZjEVv1VBB4I-L)? _ZuHECg#bRsNvSsrx_U_&DM`Q=Y%?k%(W>(fWZe4!skCOprXbfQg z39YX^0;6e&4!R0~!AzQ|_g7E<_hg^XUoIXR1xCyONNwf=4?J)TshxzU6pM~VK^cS^ z&8Upv!NFEklo!79&fE85GE|}#|6Bo0$Xl^u#owk)n|3t`%|0>ZSTu-!tA>vK=QXv5 zObCaA((j)A{oK~pw%tmJkzqs(uvjb;?!W*3W9YO&Bfci>ghp&dBNV5|gV)v7ReRrj z^NpKu-7E@!!N3p_p~dgRXI#ZT(?n_GAlQF`1ZTcpuZ#_XBgXu~^M71kTUWPU6dD1B z%>WXA_3G7(1|SehWTHt2Qxck~HVE`p+yh$Hu6=cWU0vN#apNKbCX7?R`OR+@#KpzM zYg(X;fu^(9oN9=`H~4)%gla+QrN6xL?SR;@aPQ$1Cdl25Q> z>|n3d_nI4r!zmRM?D*N=|Ni>T2 G`5tKlyM0O2}$TfJNh*srVj>#jk|a6 ze!8itNrE;k#I-6^8Y6nau^J3Y=xda9(xtO5S$X`#@k5 Xhp4B&F2mfJ=<=#{aCLzEI{AN1A*XotE#Gw z55@!yFhl8&KKke}FwPn6+f+>!U>@`yzS##Q2uMMMy1)AMZ?Ej=?Aogq84`MHJU5JA zy8F(3XwGgnnm}kuKI3{wI--am9F-1nJYxo*AGQ+bWo6}szyJO3U0)>e3Afwbg89Lv zkzjCqazes g_=R`(E?ZQ%|{0oH$WPVWQL3%#sG7@i0R=XoAjQl4Q{3 zKmOzUg%G@SwaAb#BnB*)f6cns*w{QeDD4FaAtXQC8>-R%o6TnFU~$p!-g@iJIVf^g zDf_$t;`v+KS|O!DIo{ ~k5U>&Ru5h>4Bg~1}VoAYp9?8neoQfjn^@BhB;SY5_L_CyoZLA!(pap2c1w~k6 zNj88HII^;{Ct-f^xF~oYoQnbS?JI8E$`gb ih&Y-y<1}G9sOiA31dB z;Hzr(MFTRxAMiK9p@zYTa8Mb8>~guTa5|megK3Rbi=GpYKmNF20tJyYAn~ aohYlSoR4*0cs~RAd)#)E`XqxcQ!{6Wr zfOBHdhC%SeC5vx(h7D+{7JbkkP?dSFzP9euZQHi}KlRaz5_X6ERDFHDm;EMzM6dvV zg|Va{N_rqGD@!b&4+U%2uAM_BaQvFI^B_nY(u81|larGMEt@Mc&VoT1z&BYWJ|&;% zVT5WeIRGA*)O5V@#vA8s;9@{~N5^T5rJV$#pwg6ZDFKjeHro}L1%DIF>D}LQ9)Jng zcs!mC) uw zt5y2zUtXGwn_qaSc|NqYw$+0;9gNt*5FAVpA)+u7n9qPnb`Wvd#EBEHLm5@X&WrFb zfBDNPbjp!1=)*_|k8;NbmnaCM!3$>Lcd`Oi;~h zuf6s&(uj2`&;(Y2EQ8??*1PWh(!b+!Q0Dew06H)&Jw09QUQig&7g`?FuVvr9y+aDK zE(XBdcyR=@{%eHiIC %+ z0qFD8f&~kn)jG)sqnW@)*m0`enl-Onqh|k~00 g|gf7_{DQx4WiJnetF-O6srU ZIR3{LW4+I4)X&6t5)rSPpbdi9919O>Gfe~SKUX6x zR*O_xS}GazhJ@VQ+{I+3+Qg9X`fF?N)0j#qkN3VS;R_s^@vq*$dZQ?yLNH+Jv}q6W zK~|tWAolBsJv%{MhosKV_69hyFXRP!e~>tsVY;%jvlry%=DavACv)StoUApMUw-Mg z4MzR7b@lZb%`L5lKnMhY5A^yyQf*zGU;yU otPc3 zU^7Z &32c8QRxlhGe73l#SHD0vh W4J8Tr%sjMz_}!wmTir?+EQb86k+odMLqQbaGm1T9(?4A>-u96ECnX z(oC}^%AwGZ_xKj=-mgBePGkUbdV1Qmnr&oZqCW%Bd77RJy=kfkkP;)z%k0Vdlb_1U z$ox1y&h_s2+}!VBqB>V^G-Mn(e$3(v1|(m=FU7>faM4S0xm+-lozk(RM g?_|wRd(%&FyWH0oEZYC0TO8#L!aI*VjvD&Ya=m zU>FgOKQl9{1^q5+X=#1OY_mRA+faY=newug4UG-I!&tUKTONaB?f}unIu@fBZR~1l zGMh|OM8+`j(YCEG3Ui|}lu}O!M(enBQ!g0}CY#6vbgRGqU 9Etf^4>8D6(%F`WEm2?+`5=#L#vP4;rN5oW?{F$+Ssw6q9` zXBb&qQzPC-$5?HW!{PAbemgu`S#?E4iP3B>@CO3_YG`PzhBPYT7zIqaELmBZZ^YPb z*LQb$gsnH2jItOv84!*HQ 8Vf${_&CoATek{!JYTPkM6Ul3+kXCeS(i zF>C(uV?Rjpc-&3=60yhltK3%}B=PY8`VZQV8S!;cZv)Il3LNPwOpyNB)z$G zX1Cq#jB`vfS&Ysucc *QZ}J>F_CQ Lv(?o#CtzcTv}^fvNy&b_tltVExp|E)3d%q}xOm5Y*rSDW zIDknk;kpwEPU6${Gi5kWW5ccTIk|ZYSXMSb%*Y*$+Zy2o$8glu)fI>vBLoIy#6bUO zcQ`g VM+%1&(8a8V&|Pf0zd; z3|lQ@k|ycHMu>!3d{{Vi= 4CTX0wuRKauYn(4`t zC(rpt=X^jN;c??~;t-opgZjn0J#I1Wr;Q9@q7?84B)cs}Y!inQm5gRnm`)Ll3&X7N zeZyzVmoNXvv}x1U(R6?&0a-7*p_zkjF&rw;uL$D(=H!&5cVM6WF#B>u3WXu9s5L0* zjj~%$6&wN1oH@OVV^E-&9v%vm^)*Cv!VwF{6Aeuh2%aMZEmki_1lr-Ww6yK8&;GWy z7STAIAO
v}Dvc(;yxE=wRC+{?274>AE5^|w&y z5M$X*sILn%OcM2IZtnQ6#l^+mxMkbc#RUZg|7>VzsHX{nbeOGXOW10$_8B}0g~((V z?t2px6T4$$ |(iEipXcIlmw>_X(*cs4sdxgX-}N zeV`Fv)xeSUA_^Qyd3nW0FfTP+__En-)jM~7va!6ptPG6l5f8MhLtG!jRm%PhAdVkD zaoFwl`by7~ImYLX@3X2nS`-%UeiM%IBQPKcE$oVOxhj!8(y qn4K9nZd`@K;rttDF=FA<=%|6`(FY?z_z43&exHJz z`om0#gXci+%~61oZZw)-!@Q#zbYz IMA`dZSL?+R-APICXT 5|_qx#`B2ZE^N&TWpNIzOimHsu)y*M~c0B_x{UdH15U>eQRN1;TAP}B+$X= zDrN>GWc*KBh9b}i_yaP>q*qqE2ZW(~h {BF>;A2*qH<}_A2M}yVlLtFr8off(J=vqBp3{N zU@BX1Ib!LDV3-*Np}Ic8&2zrECw=K>==1tSLD7ZD2sItj?%|=Jv$L}uq2&IYoE#+t z?FY0)_;5d%l9EynGgODUP@T`~E9q!$YtTm`MQJH1$Gsj8ourW;)Txh-8N!jUA50iA z@d+rhlgkYXJr(-)(3$I=P+Yb^hWAlnJ|MV+f*^#*Ga8MV;$#fKdclCLb#--I02^R} zV1I30U2fgMgNK`)&bY_w>l!aTQ&xI;Rdv;Z>Z+<)pB?_}#)`7??4@N1!n$&W>f%npS0y6)|%iCU|uCZ^bGd~YJdjqA((+n83DmJcxAoJHQe^L_IBFg0a`-4nV67pG8hQT%`GjLfp=pU zssZQ@bQ80rQ6O)8-dxI5G(CwR%o5C#UAR;>8$%$YNn33cQSws0ig=l7e!p>Ra)N1svfIxQpZvtT$7 ztgflbLTG!wkL`v9I!B{vM2nz3m^^vvJO(ftZJA 1X50q6Xr zbEt5|#mSvr?Jwqx%lg|VpX~T%d_wF$CQqL9+Mz=Se}K+1uIH`?3kcwebvo0H2E)&< zm_7S9x7@Pq>3Q?6d3^5NtN(Yw!UexwxM<<8TUwg$LzriyG^L~@r=j{$No+KNfj}tI z&o>SiX=xdG+ALUO0_jTP!-~Q!>!ikpdj4XgBvbOV0xYb>ty~`FVX~OPI5~x7MgybX zSUva3xs?uk?60Ownf~awoV;H;9dUn{H*ancEPM>wW>0k(J $pe@{Q{1s#TR$ CK{>%CJ-_E$Qi&_l6n%35|8Vi zc@@G>9S%WTFsHoq)Q2oDS5{VT<=6%B!G!(?`IDZW{s0S)2AEm8F$3GOZ{NN>+qZB3 z5LjRENx_!3me!qU#z-H)uoCTA+B-Y=mg-1)X68{>Vq&QyHuhLf_PD({+1bSji3xk8 zh<=C3Z1v8VF(cyl2lCm^u>z)opv6GTFjP#RHe(f~++;Qh+G$`PX@dAdhD$uhjvf&k zdgUWWj;y7<;!Ulf2A=cY%u8mjR (iU7s;X~INJxC+)aeo{BC08PZtNU!B%;$( zL`R707A<~|G()V=Bg7PL4x5Z&{O|L4{3Ru)MIa*A*Vk{?xT9%-2CV}A(iAR7<(XjI z?KYcjz|1x1517QZZh(71;DkeoiHUkdIL#qUOvxAwCcp#m;WEVY#KfdMpcPJoIjA>A zR4@i0@kRk-a#C`hMo$u*2gk>sbKo$!1ZFhqPa|I}Hp&=41unwm4$+?p1Ur?Qmii6# zazuc`48mL}jYPrc_eoB5MZsh;n?neHN=r-4Mx)`J4FBxNkxeaatySo+H90wX%qEK% zyv%i+kzjKEl!r<9Xkpf9$!k4-7Y_{iv~c(HA`=jPV%M%+FGUxQ2J`sv{P_!htY(b} zp-@l<0Uz-7iPdc7&I`eq7@I9N6p0v akEU;2?kN7h3oDhqES?m;GrPYoz2*!~aY355aNN7=&> z4N675uh8K9k}*liQ*RF&hrO2#EfZ?%s$Mah & z=0p3TuI?^3-y1`s!%k DIc(eg)hVL3L=X~aFB%jNP|t(IV2ZEaq_A3)4%HkFl? zjl-Y^s_zJZY7hnu6qNH} 0({rF{K=E9)|)_hT@c*E N% ldEKNh`lh*dKaX?=oAh z-DoF*P=`zW?(S~4`|#nz2TlSfPMkP?;>5}0JUxB-^r@pqj~;=OK6Ci+XT=8&6#X1h z)tZnHpOBW8K3=VIG~k{Tz13nF)-w0KU%mhJii!%*ict?jO&ol&k0?&ur{p8pp|Dn? z>tY71p@#t|RDb5onIftVA0SA0a*l`c#UFn^DE+D@pL*i2$B!Li?Z&77`{} 9A2+loDqLX3L#mYAeFl^rWQ3QTqXo z*XIksQhJB{sVeOLR51Ull9Cdx9E)!fs;a6)N^tWTeW(F5?Dg-x^CYtRjH`zM#I|kQ z?(44w+|S5VFade|o@(2+tr7+-)mEMMZ`io$6|2P{*<#N9BT@X>;IOJy(FleD9vG)Y zv}=IG%qc7^%z)kZskhGwP7Ff9P$QhQ9gkn4W{()C$C8_yI~Ber*<>^h=~u7*{X5?) z;O-TE9Mas}EJ1VmJ9ScAJT0{>aqA~{NW-&tZQitTfDi4%0I1DpwY9aSn#s|?>t2S4 z4ZG5=-MgfO_;{(gwxopW1+`_FK3@Pv1K~Y`WA&;RaH6r2E@Gj?2Ymj{w6ruZIj#y) zbKc+DVV^QG(t}M+O)?zusNNBCl@^o5XA5@hn7Mm*;SG}}PI?YPcg|Vaj2SbZ1>@s6 zkD-(wIdVjrHEWjGKF_{!2ncP&QCzhD8Sb`FAML?_4zFLoo*$@*3J8Aps)58u$cQtY zw0l>fR9#am>5WF(DEJ4nWVhSSIw1n<_+v=}%nHnA2g1%SG5~Ed5;H(;Z*w@~3K3?0 zJaNK=4Y}jS{WCo^ZCh4m*1JiGiEk$-CT+~l%6bD4(fWqQ#>;7M(cL% 5a?26Bp|cpF{ 9|fM#{Aef8Df zsgL%-00w|dhhfi(Db*U#IWe8)j$eLm8HQb>ZF~K-Hzcnwh ASjN9AO2Q>%LNP2 z)GWTx;YWeA{d|PNOJN011 Rn95uPa`TycQ>xJFEikRHk^9XN1M+PQm= z(2xk2WrV{oIdzo3CDEtT-R^Eb9vNVQygqLrJ|W(LHguTfdYhUW!{f5E-rBTj;|<%l zf3*Cgk3PO})27XL6%_2e1?S6<-oA0;2e MpZb-BA`m?C{tRWt{@Fi)Lv$@|l0&Ya%b-YRu=c1XE-xsu1{mfAbp zC09b6)ZX1CL6yJ|{ VQ)>`oZi&b0=` f7v#6+OoBH^mIA=%U;m3XZ+utrF z1E>jPK#xY?;I$q;nC8mobxXJ3e!Fzl6<3N5@R=BUtf(Jlb(ddu$xG8`&a8Unudn_T z&k0U4|N6z(eW$6Z;U|a`PMIyH8CHwc;OTZZVlW3hUavk94s~*Ah7V8=xms#eLS;iR z6x8X(=8DLI#^%O&l;yt8J;}+bJ5L-x`7@Y>A%(L92xm!6P2G`|m3b*lpzQ8;SGKmb z&-8lX<$^)qxbb-#opJF?Crz5fzZN2$Idxi^b;%47d~o+O7%x5|OwY`gyk5U#F#N>g+FvOvJIM5ha_^!vNT5eRgz z3 j<*H^L4H2O zrF;Gm6PM{7x#P#bz4DHgOZgEvqn!PF_DU9usb^+yG25hy@+v7SGe^t?40?U|mB0M? ztLGy=aZUyhnEwA9YIzbJRC5$)*L;VJ_)^$^PSQU7aFeuQ{X0@~V>SQ$lSdQ+++E!b z0T@}Bo1QkIO|ruoo8_=``XI~gtsQb85P{>0kplj3*y{~Q9bI0@?F&g=9>3)Fha`_b zBzJrKa+lX9bwkoP-Dg*9Fa?|d@q_KySm&_AQ95CWl?fUYHbR=AT^=Js(g_pt{(RHY zrFT%vlj0Mk0NN$tXH1{2S^$I8(A*@ow6{r(EzRP0A&U0zdvgE2z5i0HJ}3H8_3SWx z>s#MyM<*CA_7Wed*#6EB5RgS{X@(b;!hUcz+~9ILDleZgA@PY{|LL1mrKfMZ=K2*k zSJyYbsFy>SbNRe}Z_pA7`M>P-dd4G!55r`D0YUl}8ImV+-T?jQre2yJ+9B9xuu6&0 z!e%%-9VQZPk21e;#yVtlCs 7NZYTa43UwQWdFNt}(&K}_UrH!Zzs zJRI^Q&T^^gHMRB9(W6JD!~~ZJJ7F@V9iQx!I^YlT^QQw*YD8uie_?eF`3?lj<{D=;wCF`Zj#>YxY>FLsM-#fVe zcv(xa!K6=WYiSJoJfU{Xk4<=X5;|fDhQfY44ITvCu*qCV?0`8- Q%y~kG DMiNXNYvOpqD2514I04p4{J dK|Obej}(=1MDn z^jcO;ePgv!`26VaGX?`Sk>#`$IR8U~0ME;}EMM_dPHyfG8XKF0$*HS_ZO_V)+}$1_ z>HGy2KYTlXbi;0skzyRNQfXP4G(I=4;f4SGpR3`(wLh0Tq(1c6 nl@z;h|E9M!`Fxi aahqz7T-jPF%g}YacJWW!ZlvCnuXpaQ>(hf8?7VlJHYu zzNHJ&HzAKa<~Wm+k}$b+OGydI9os+N`t>76kMP4hYWA=MU|1$78fj^1x8HNmJ?~KF z3C%AkJAla-GK3BA58bdC_zo}wo&z&Qv-Ihn{e{~<{^(vf-Y?`=xGWaS#5?c2drkhN ziB}`yQ72H!OLWHbB)-vX5?{5`+}76CO8#Jg+v_F%2{KGl#Uk5#@4R Kht9 z_+aA`RaKRIp);h&VH7at THqS65eeOguC~jEVs&tgBXktp)KnLP{_}R<`p{Y6K%- z5hEC67(RkaL3);9vk`=nV2QTk&cWBzRF@PM?*3~ bzi&+burdgnGI3)5s)dWL zdoU#>HIKwp^U+7X>sGXt(C)D>JSPMAHl07&zhlP^31(L;K|m844i**9hEL>|l%v8} zFo4i4xOTygE3Uk9UI3FNsHT>U(U`!L00 Y$&FOUH=gt=Xm@qFhBQsBL zFbM6WKxhXEt`VKPc97F^&6IuM?}+jb7QOlAo8p>&fWZb#@5>uDY
itGCb}XoJ*A{DpE5pJa#Bhq>)i#-PQ3F>k~*38a qFWgwrc3 z&wH$w`Me)po+ (Tq0wgwM@Kc#`!Q$;5MT1pAVm>K zBOoIVWf4wU5*HB{AczI?p`G(kHHH-J8IiaKz)q18S{u=X*FeH^Nrm6<9@w{EINkR4 zc5(Ov{%{DM8qZatQ*B83L*Qrd{7IzSahyaIHA+px!-ZggfX!x`_rL=W6vWt_VsHdk zcE!L2ZInE^=HBHYW!015+Xr?odZRK1s-E={pPD3$no3OV*GULbTr|deN_%7sO$ovJ zcr7#xnO@9n4;3Gj>Op)WHZHa!6p1`t`01znz!*-jSR*$A^VfrEdKgOc9j(S?MM{Q& z-qBqkOq!Jc%+1Sg`7W1hIZ(y ;=sfxn(nYWf#P4Ae z&RL^g_3}zth5$L40Z$!e+ia=Nm0Z3Zk11ZbYts=k2#v@7cR|YbYF|zhQ$KXL;VM zR-=S6k_!*rv}x1-uw==N4|9i|Mnp1zf9xiDJc3YaO7P2ao@+$Y@ z2n zFp|e$GRp{NQ3KE%ugQ2HCW(}pe8*AblHQ9*xoAd)g__K~=20Nt?Ox#dYg-PN(3iKlUpV>mHNnoVn9-kG0 zOUBXEas8gmq_89Y!AX02XV_{n6@9pQ<9`+v?cWZ (Y1W0iqGN3DCH^cieX?NwjqZjjcsjB zFMaUAhBejIRdk}7iTPadg)tx+@DIti-gd_pyUjiwGf$b}Cbz%PPeed@?y931AvkO0 z1d2QMNMy!Vbn>+4WS+MBj>PBs4R<0jghX8LPfAKUbNEov@AmBZbW3e*O*t4fthZ(t z0v81X`om_6Nm+Q^4Nu0$C(bjO%*jTR$rcl1g|LggJDBM4kK^!@f4+Yp3&@0s2p4@` z96p~L%&7Bv-1|$ D=@vixXSY3a#OC^)J~(}loA$$+x}H056-kwJ4k_+T_(Qe=d{ u>%2a%FF@)?!u-aUKLn!Ksf!+x^#1|=;mcfrop#3n0000 + + + + + + + + \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-dateRangeSelect/package.json b/src/uni_modules/cxc-szcx-dateRangeSelect/package.json new file mode 100644 index 0000000..727d7ea --- /dev/null +++ b/src/uni_modules/cxc-szcx-dateRangeSelect/package.json @@ -0,0 +1,83 @@ +{ + "id": "cxc-szcx-dateRangeSelect", + "displayName": "cxc-szcx-dateRangeSelect", + "version": "1.0.0", + "description": "cxc-szcx-dateRangeSelect", + "keywords": [ + "cxc-szcx-dateRangeSelect" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-dateRangeSelect/readme.md b/src/uni_modules/cxc-szcx-dateRangeSelect/readme.md new file mode 100644 index 0000000..363f7fb --- /dev/null +++ b/src/uni_modules/cxc-szcx-dateRangeSelect/readme.md @@ -0,0 +1,168 @@ + +### 紧凑型日期时间选择器组件说明 + + +#### 一、组件功能 +该组件是基于 UniApp 开发的紧凑型日期选择器,支持以下功能: +1. **三种选择模式**: + - 单选(single) + - 范围选择(range) + - 多选(multiple) +2. **弹出式日历选择**: + - 支持月份滑动切换 + - 显示农历日期 + - 支持同天范围选择 +3. **数据双向绑定**: + - 通过 `modelValue` 实现父子组件数据同步 +4. **自定义样式**: + - 紧凑型输入框设计 + - 支持自定义主题颜色 + - 响应式布局适配 +5. **支持自定义日期禁用范围** + - 限制用户选择的日期范围。只能选择在 startDate 和 endDate 之间的日期,超出该范围的日期将被禁用,无法选择。 + - startDate:设置可选日期的起始日期,用户不能选择早于该日期的日期。 + - endDate:设置可选日期的结束日期,用户不能选择晚于该日期的日期。 + + +#### 二、组件Props + +| 参数名 | 类型 | 默认值 | 说明 | +|--------------|------------|----------|-------------------------------- | +| `modelValue` | Array/Date | `[null]` | 双向绑定的值(根据模式变化) | +| `mode` | String | `single` | 选择模式(single/range/multiple | +| `startDate` | String | ` ` | 设置可选日期的起始日期 | +| `endDate` | String | ` ` | 设置可选日期的结束日期 | +| `isSearch` | Boolean | `true` | 设置快速选择日期样式 | + + +#### 三、组件数据 + +| 名称 | 类型 | 说明 | +|------------|--------|--------------------------| +| `dateRange` | Array | 当前选中的日期范围(内部状态) | + + +#### 四、组件方法 + +| 方法名 | 参数 | 说明 | +|----------------|------------|--------------------------| +| `openPicker` | 无 | 打开日历选择器 | +| `calendarConfirm` | `e` | 日历确认回调(处理选中数据) | + + +#### 五、事件说明 + +| 事件名 | 说明 | 返回值 | +|--------------|--------------------------|----------------------| +| `update:modelValue` | 数据更新时触发 | 当前选中的日期数组 | + + +#### 六、样式说明 +```vue + +``` + +**关键样式点**: +1. 输入框宽度固定为 120px +2. 紧凑型设计(height: 20px) +3. 活动状态样式增强 +4. 水平排列布局 + + +#### 七、使用示例 +```vue + ++ + ++ {{ dateRange[0] || '开始日期' }} + +至 ++ {{ dateRange[1] || '结束日期' }} + ++ + + + + + +``` + + +#### 八、注意事项 +1. **日期格式要求**: + - 单选模式:`YYYY-MM-DD` 字符串格式 + - 范围模式:`[startDate, endDate]` 数组格式 + - 多选模式:`[date1, date2, ...]` 数组格式 +2. **依赖组件**: + - 需安装 `wu-calendar` 组件(第三方库) +3. **异常处理**: + ```javascript + calendarConfirm(e) { + this.dateRange = []; + try { + this.dateRange.push(formatDate(new Date(e.range.before))); + this.dateRange.push(formatDate(new Date(e.range.after))); + } catch (error) { + return; // 异常处理 + } + this.$emit('update:modelValue', this.dateRange); + } + ``` +4. **性能优化**: + - 建议使用 `:range-end-repick="true"` 开启范围重新选择 + - 通过 `:item-height="45"` 控制日历行高 + + +#### 九、扩展功能建议 +1. 添加时间选择功能 +2. 增加国际化支持 +3. 添加动画过渡效果 +4. 支持预设常用日期范围 + +如果需要进一步定制化,可以修改以下部分: +1. 日历组件配置(`wu-calendar` 参数) +2. 日期格式化函数(`formatDate`) +3. 输入框样式和交互逻辑 +4. 异常处理机制 \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-dictSelect/changelog.md b/src/uni_modules/cxc-szcx-dictSelect/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/src/uni_modules/cxc-szcx-dictSelect/components/cxc-szcx-dictSelect/cxc-szcx-dictSelect.vue b/src/uni_modules/cxc-szcx-dictSelect/components/cxc-szcx-dictSelect/cxc-szcx-dictSelect.vue new file mode 100644 index 0000000..bf3bc87 --- /dev/null +++ b/src/uni_modules/cxc-szcx-dictSelect/components/cxc-szcx-dictSelect/cxc-szcx-dictSelect.vue @@ -0,0 +1,69 @@ + ++ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-dictSelect/package.json b/src/uni_modules/cxc-szcx-dictSelect/package.json new file mode 100644 index 0000000..9c2775c --- /dev/null +++ b/src/uni_modules/cxc-szcx-dictSelect/package.json @@ -0,0 +1,83 @@ +{ + "id": "cxc-szcx-dictSelect", + "displayName": "cxc-szcx-dictSelect", + "version": "1.0.0", + "description": "cxc-szcx-dictSelect", + "keywords": [ + "cxc-szcx-dictSelect" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-dictSelect/readme.md b/src/uni_modules/cxc-szcx-dictSelect/readme.md new file mode 100644 index 0000000..66edf7c --- /dev/null +++ b/src/uni_modules/cxc-szcx-dictSelect/readme.md @@ -0,0 +1,90 @@ +# cxc-szcx-dictSelect +### 组件说明:`uni-data-checkbox` 多选字典项选择组件 + +#### 一、组件概述 +该组件基于 Vue 3 和 `uni-data-checkbox` 实现了一个多选的字典项选择器。它通过传入字典编码(`dictCode`)从后端接口获取字典项数据,并将其展示为多选框列表。组件支持双向数据绑定,可将选中的值同步给父组件,同时在选中值发生变化时触发 `change` 事件。 + +#### 二、组件使用的技术栈 +- **框架**:Vue 3(使用组合式 API) +- **UI 组件**:`uni-data-checkbox`(用于展示多选框列表) +- **请求库**:假设使用了自定义的 `getDictItemsApi` 函数进行后端数据请求 + +#### 三、组件输入(Props) + +| 属性名 | 类型 | 是否必填 | 默认值 | 说明 | +| ---- | ---- | ---- | ---- | ---- | +| `dictCode` | String | 是 | 无 | 用于从后端获取字典项数据的字典编码 | +| `modelValue` | String | 否 | '' | 双向绑定的选中值,多个值以逗号分隔 | + +#### 四、组件输出(Emits) + +| 事件名 | 说明 | 参数 | +| ---- | ---- | ---- | +| `update:modelValue` | 当选中值发生变化时,用于更新父组件的 `modelValue` | 选中值的字符串,多个值以逗号分隔 | +| `change` | 当选中值发生变化时触发 | 选中值的字符串,多个值以逗号分隔 | + +#### 五、组件内部数据 + +| 变量名 | 类型 | 说明 | +| ---- | ---- | ---- | +| `dictItems` | Ref+ | 存储从后端获取的字典项数据 | +| `selectedValuesArray` | Ref | 存储当前选中的值,以数组形式存储 | + +#### 六、组件方法 + +##### 1. `loadDictItems` +- **功能**:异步从后端接口获取字典项数据,并将其赋值给 `dictItems`。 +- **实现逻辑**: + - 调用 `getDictItemsApi` 函数,传入 `props.dictCode` 进行数据请求。 + - 若请求成功,将响应数据的 `result` 字段赋值给 `dictItems.value`。 + - 若请求失败,在控制台输出错误信息。 + +##### 2. 监听 `selectedValuesArray` 的变化 +- **功能**:当 `selectedValuesArray` 发生变化时,将选中的值转换为字符串,并触发 `update:modelValue` 和 `change` 事件通知父组件。 +- **实现逻辑**: + - 使用 `watch` 函数监听 `selectedValuesArray` 的变化。 + - 当变化发生时,将新的选中值数组使用 `join(',')` 方法转换为字符串。 + - 触发 `update:modelValue` 和 `change` 事件,将转换后的字符串作为参数传递。 + +##### 3. 监听 `props.modelValue` 的变化 +- **功能**:当父组件传递的 `modelValue` 发生变化时,更新 `selectedValuesArray`。 +- **实现逻辑**: + - 使用 `watch` 函数监听 `props.modelValue` 的变化。 + - 当变化发生时,将新的 `modelValue` 使用 `split(',')` 方法转换为数组,并赋值给 `selectedValuesArray.value`。 + - `immediate: true` 表示在组件初始化时就会执行一次监听回调,确保初始值能正确同步。 + +#### 七、组件生命周期钩子 + +##### `onMounted` +- **功能**:在组件挂载后调用 `loadDictItems` 函数,从后端获取字典项数据。 + +#### 八、使用示例 +```vue + + ++ + + +``` + +#### 九、注意事项 +- 确保 `getDictItemsApi` 函数能正确获取后端数据,且响应数据的格式符合 `{ result: [...] }`。 +- 若 `modelValue` 初始值为空字符串,`selectedValuesArray` 会初始化为空数组。 +- 由于使用了 `watch` 的 `deep: true` 选项,在 `selectedValuesArray` 内部元素发生变化时也会触发监听回调,可能会影响性能,需注意。 \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-lineChart/changelog.md b/src/uni_modules/cxc-szcx-lineChart/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/src/uni_modules/cxc-szcx-lineChart/components/cxc-szcx-lineChart/cxc-szcx-lineChart.vue b/src/uni_modules/cxc-szcx-lineChart/components/cxc-szcx-lineChart/cxc-szcx-lineChart.vue new file mode 100644 index 0000000..e22dd35 --- /dev/null +++ b/src/uni_modules/cxc-szcx-lineChart/components/cxc-szcx-lineChart/cxc-szcx-lineChart.vue @@ -0,0 +1,295 @@ + ++ 当前选中的值: {{ selectedValues }}
++ + + + + + + diff --git a/src/uni_modules/cxc-szcx-lineChart/package.json b/src/uni_modules/cxc-szcx-lineChart/package.json new file mode 100644 index 0000000..dd31225 --- /dev/null +++ b/src/uni_modules/cxc-szcx-lineChart/package.json @@ -0,0 +1,83 @@ +{ + "id": "cxc-szcx-lineChart", + "displayName": "cxc-szcx-lineChart", + "version": "1.0.0", + "description": "cxc-szcx-lineChart", + "keywords": [ + "cxc-szcx-lineChart" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-lineChart/readme.md b/src/uni_modules/cxc-szcx-lineChart/readme.md new file mode 100644 index 0000000..9ea8aef --- /dev/null +++ b/src/uni_modules/cxc-szcx-lineChart/readme.md @@ -0,0 +1,179 @@ +# cxc-szcx-lineChart +# # `line-chart.vue` 组件说明书 + +## 一、组件概述 +`line-chart.vue` 是一个基于 ECharts 实现的折线图组件,用于在 UniApp 项目中展示数据的折线图。该组件接收一系列数据和配置参数,支持动态更新数据,并展示参考线。 + +## 二、组件依赖 +- **Vue 3**:使用 Vue 3 的组合式 API 进行开发。 +- **ECharts**:用于绘制折线图。 +- **`lime-echart`**:UniApp 插件,提供 ECharts 的渲染支持。 + +## 三、组件使用方法 + +### 1. 引入组件 +在需要使用该组件的页面中引入 `line-chart.vue` 组件。 +```vue + ++ ++ + + + + +``` + +### 2. 组件属性 + +| 属性名 | 类型 | 默认值 | 描述 | +| ---- | ---- | ---- | ---- | +| `dataList` | `Object` | `[]` | 包含图表数据的数组,每个元素是一个对象,包含 `xField`、`yField` 和 `legendField` 对应的数据。 | +| `xField` | `String` | `''` | 数据中用于表示 x 轴的字段名。 | +| `yField` | `String` | `''` | 数据中用于表示 y 轴的字段名。 | +| `legendField` | `String` | `''` | 数据中用于表示图例的字段名。 | +| `referenceValue` | `Number` | `10` | 图表中参考线的数值。 | + +## 四、组件内部实现 + +### 1. 模板部分 +```vue + ++ + + +``` +- 使用 `l-echart` 组件渲染图表,通过 `ref` 绑定到 `chart`,并在初始化完成时调用 `initChart` 方法。 + +### 2. 脚本部分 + +#### 2.1 引入必要的模块 +```javascript +import { ref, watch } from 'vue'; +``` +引入 Vue 3 的 `ref` 和 `watch` 函数。 + +#### 2.2 定义组件属性 +```javascript +const props = defineProps({ + dataList: { + type: Object, + default: () => [] + }, + // 其他属性... +}); +``` +定义组件接收的属性。 + +#### 2.3 初始化图表 +```javascript +const chart = ref(null); +let echarts = null; + +const initChart = async (canvas) => { + await initEcharts(canvas); + updateChart(); +}; + +const initEcharts = async (canvas) => { + echarts = await import('echarts'); + const { init } = await import('@/uni_modules/lime-echart/static/echarts.min'); + echarts = init(canvas, echarts); +}; +``` +- `chart` 用于引用 `l-echart` 组件。 +- `initChart` 方法在图表初始化时调用,先初始化 ECharts 实例,再更新图表。 +- `initEcharts` 方法异步加载 ECharts 并初始化实例。 + +#### 2.4 处理数据 +```javascript +const processData = () => { + const legendData = [...new Set(props.dataList.map((item) => item[props.legendField]))]; + + return legendData.map((legendItem) => { + const seriesData = props.dataList + .filter((item) => item[props.legendField] === legendItem) + .sort((a, b) => new Date(a[props.xField]) - new Date(b[props.xField])) + .map((item) => ({ + name: item[props.xField], + value: [item[props.xField], item[props.yField]] + })); + + return { + name: legendItem, + type: 'line', + showSymbol: true, + data: seriesData + }; + }); +}; +``` +处理传入的数据,根据 `legendField` 分组,对每组数据按 `xField` 排序,并转换为 ECharts 所需的格式。 + +#### 2.5 获取图表配置 +```javascript +const getOption = () => ({ + tooltip: { + trigger: 'axis', + formatter: (params) => { + return `${params[0].axisValue}+
` + params.map((item) => `${item.marker} ${item.seriesName}: ${item.value[1]}`).join('
'); + } + }, + // 其他配置... +}); +``` +返回 ECharts 的配置对象,包括 tooltip、x 轴、y 轴、系列数据、图例和网格等配置。 + +#### 2.6 更新图表 +```javascript +const updateChart = () => { + if (!chart.value) return; + + const option = getOption(); + chart.value.setOption(option); +}; +``` +如果 `chart` 实例存在,获取最新的图表配置并更新图表。 + +#### 2.7 监听数据变化 +```javascript +watch( + () => props.dataList, + () => { + updateChart(); + }, + { deep: true } +); +``` +当 `props.dataList` 发生变化时,调用 `updateChart` 方法更新图表。 + +### 3. 样式部分 +```css +.chart-container { + width: 100%; + height: 30vh; +} +``` +设置图表容器的宽度为 100%,高度为 30vh。 + +## 五、注意事项 +- 确保项目中已经正确安装并配置了 `lime-echart` 插件。 +- 传入的 `dataList` 数据格式要符合要求,包含 `xField`、`yField` 和 `legendField` 对应的数据。 +- 由于使用了异步加载 ECharts,可能会有一定的延迟,需要确保在合适的时机初始化图表。 \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-stationJl-select/changelog.md b/src/uni_modules/cxc-szcx-stationJl-select/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/src/uni_modules/cxc-szcx-stationJl-select/components/cxc-szcx-stationJl-select/cxc-szcx-stationJl-select.vue b/src/uni_modules/cxc-szcx-stationJl-select/components/cxc-szcx-stationJl-select/cxc-szcx-stationJl-select.vue new file mode 100644 index 0000000..d44d09a --- /dev/null +++ b/src/uni_modules/cxc-szcx-stationJl-select/components/cxc-szcx-stationJl-select/cxc-szcx-stationJl-select.vue @@ -0,0 +1,90 @@ + ++ ++ + + + + + \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-stationJl-select/package.json b/src/uni_modules/cxc-szcx-stationJl-select/package.json new file mode 100644 index 0000000..1af6df2 --- /dev/null +++ b/src/uni_modules/cxc-szcx-stationJl-select/package.json @@ -0,0 +1,83 @@ +{ + "id": "cxc-szcx-stationJl-select", + "displayName": "cxc-szcx-stationJl-select", + "version": "1.0.0", + "description": "cxc-szcx-stationJl-select", + "keywords": [ + "cxc-szcx-stationJl-select" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/cxc-szcx-stationJl-select/readme.md b/src/uni_modules/cxc-szcx-stationJl-select/readme.md new file mode 100644 index 0000000..0b830c7 --- /dev/null +++ b/src/uni_modules/cxc-szcx-stationJl-select/readme.md @@ -0,0 +1 @@ +# cxc-szcx-stationJl-select \ No newline at end of file diff --git a/src/uni_modules/uni-data-checkbox/changelog.md b/src/uni_modules/uni-data-checkbox/changelog.md new file mode 100644 index 0000000..7c99f6c --- /dev/null +++ b/src/uni_modules/uni-data-checkbox/changelog.md @@ -0,0 +1,51 @@ +## 1.0.6(2024-10-22) +- 新增 当 multiple 为 false 且传递的 value 为 数组时,使用数组第一项用作反显 +## 1.0.5(2024-03-20) +- 修复 单选模式下选中样式不生效的bug +## 1.0.4(2024-01-27) +- 修复 修复错别字chagne为change +## 1.0.3(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.2(2022-06-30) +- 优化 在 uni-forms 中的依赖注入方式 +## 1.0.1(2022-02-07) +- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +## 0.2.5(2021-08-23) +- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 +## 0.2.4(2021-08-17) +- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 +## 0.2.3(2021-08-11) +- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +## 0.2.2(2021-07-30) +- 优化 在uni-forms组件,与label不对齐的问题 +## 0.2.1(2021-07-27) +- 修复 单选默认值为0不能选中的Bug +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.11(2021-07-06) +- 优化 删除无用日志 +## 0.1.10(2021-07-05) +- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题 +## 0.1.9(2021-07-05) +- 修复 nvue 黑框样式问题 +## 0.1.8(2021-06-28) +- 修复 selectedTextColor 属性不生效的Bug +## 0.1.7(2021-06-02) +- 新增 map 属性,可以方便映射text/value属性 +## 0.1.6(2021-05-26) +- 修复 不关联服务空间的情况下组件报错的Bug +## 0.1.5(2021-05-12) +- 新增 组件示例地址 +## 0.1.4(2021-04-09) +- 修复 nvue 下无法选中的问题 +## 0.1.3(2021-03-22) +- 新增 disabled属性 +## 0.1.2(2021-02-24) +- 优化 默认颜色显示 +## 0.1.1(2021-02-24) +- 新增 支持nvue +## 0.1.0(2021-02-18) +- “暂无数据”显示居中 diff --git a/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js b/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js new file mode 100644 index 0000000..9a44a9e --- /dev/null +++ b/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js @@ -0,0 +1,316 @@ + +const events = { + load: 'load', + error: 'error' +} +const pageMode = { + add: 'add', + replace: 'replace' +} + +const attrs = [ + 'pageCurrent', + 'pageSize', + 'collection', + 'action', + 'field', + 'getcount', + 'orderby', + 'where' +] + +export default { + data() { + return { + loading: false, + listData: this.getone ? {} : [], + paginationInternal: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + }, + errorMessage: '' + } + }, + created() { + let db = null; + let dbCmd = null; + + if(this.collection){ + this.db = uniCloud.database(); + this.dbCmd = this.db.command; + } + + this._isEnded = false + + this.$watch(() => { + let al = [] + attrs.forEach(key => { + al.push(this[key]) + }) + return al + }, (newValue, oldValue) => { + this.paginationInternal.pageSize = this.pageSize + + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (needReset) { + this.clear() + this.reset() + } + if (newValue[0] != oldValue[0]) { + this.paginationInternal.current = this.pageCurrent + } + + this._execLoadData() + }) + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList = [] + if (!window.unidev) { + window.unidev = { + clientDB: { + data: [] + } + } + } + unidev.clientDB.data.push(this._debugDataList) + } + // #endif + + // #ifdef MP-TOUTIAO + let changeName + let events = this.$scope.dataset.eventOpts + for (let i = 0; i < events.length; i++) { + let event = events[i] + if (event[0].includes('^load')) { + changeName = event[1][0][0] + } + } + if (changeName) { + let parent = this.$parent + let maxDepth = 16 + this._changeDataFunction = null + while (parent && maxDepth > 0) { + let fun = parent[changeName] + if (fun && typeof fun === 'function') { + this._changeDataFunction = fun + maxDepth = 0 + break + } + parent = parent.$parent + maxDepth--; + } + } + // #endif + + // if (!this.manual) { + // this.loadData() + // } + }, + // #ifdef H5 + beforeDestroy() { + if (process.env.NODE_ENV === 'development' && window.unidev) { + let cd = this._debugDataList + let dl = unidev.clientDB.data + for (let i = dl.length - 1; i >= 0; i--) { + if (dl[i] === cd) { + dl.splice(i, 1) + break + } + } + } + }, + // #endif + methods: { + loadData(args1, args2) { + let callback = null + if (typeof args1 === 'object') { + if (args1.clear) { + this.clear() + this.reset() + } + if (args1.current !== undefined) { + this.paginationInternal.current = args1.current + } + if (typeof args2 === 'function') { + callback = args2 + } + } else if (typeof args1 === 'function') { + callback = args1 + } + + this._execLoadData(callback) + }, + loadMore() { + if (this._isEnded) { + return + } + this._execLoadData() + }, + refresh() { + this.clear() + this._execLoadData() + }, + clear() { + this._isEnded = false + this.listData = [] + }, + reset() { + this.paginationInternal.current = 1 + }, + remove(id, { + action, + callback, + confirmTitle, + confirmContent + } = {}) { + if (!id || !id.length) { + return + } + uni.showModal({ + title: confirmTitle || '提示', + content: confirmContent || '是否删除该数据', + showCancel: true, + success: (res) => { + if (!res.confirm) { + return + } + this._execRemove(id, action, callback) + } + }) + }, + _execLoadData(callback) { + if (this.loading) { + return + } + this.loading = true + this.errorMessage = '' + + this._getExec().then((res) => { + this.loading = false + const { + data, + count + } = res.result + this._isEnded = data.length < this.pageSize + + callback && callback(data, this._isEnded) + this._dispatchEvent(events.load, data) + + if (this.getone) { + this.listData = data.length ? data[0] : undefined + } else if (this.pageData === pageMode.add) { + this.listData.push(...data) + if (this.listData.length) { + this.paginationInternal.current++ + } + } else if (this.pageData === pageMode.replace) { + this.listData = data + this.paginationInternal.count = count + } + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList.length = 0 + this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData))) + } + // #endif + }).catch((err) => { + this.loading = false + this.errorMessage = err + callback && callback() + this.$emit(events.error, err) + }) + }, + _getExec() { + let exec = this.db + if (this.action) { + exec = exec.action(this.action) + } + + exec = exec.collection(this.collection) + + if (!(!this.where || !Object.keys(this.where).length)) { + exec = exec.where(this.where) + } + if (this.field) { + exec = exec.field(this.field) + } + if (this.orderby) { + exec = exec.orderBy(this.orderby) + } + + const { + current, + size + } = this.paginationInternal + exec = exec.skip(size * (current - 1)).limit(size).get({ + getCount: this.getcount + }) + + return exec + }, + _execRemove(id, action, callback) { + if (!this.collection || !id) { + return + } + + const ids = Array.isArray(id) ? id : [id] + if (!ids.length) { + return + } + + uni.showLoading({ + mask: true + }) + + let exec = this.db + if (action) { + exec = exec.action(action) + } + + exec.collection(this.collection).where({ + _id: dbCmd.in(ids) + }).remove().then((res) => { + callback && callback(res.result) + if (this.pageData === pageMode.replace) { + this.refresh() + } else { + this.removeData(ids) + } + }).catch((err) => { + uni.showModal({ + content: err.message, + showCancel: false + }) + }).finally(() => { + uni.hideLoading() + }) + }, + removeData(ids) { + let il = ids.slice(0) + let dl = this.listData + for (let i = dl.length - 1; i >= 0; i--) { + let index = il.indexOf(dl[i]._id) + if (index >= 0) { + dl.splice(i, 1) + il.splice(index, 1) + } + } + }, + _dispatchEvent(type, data) { + if (this._changeDataFunction) { + this._changeDataFunction(data, this._isEnded) + } else { + this.$emit(type, data, this._isEnded) + } + } + } +} diff --git a/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue new file mode 100644 index 0000000..4da7bbe --- /dev/null +++ b/src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue @@ -0,0 +1,853 @@ + ++ + + + + + + + diff --git a/src/uni_modules/uni-data-checkbox/package.json b/src/uni_modules/uni-data-checkbox/package.json new file mode 100644 index 0000000..f823e8b --- /dev/null +++ b/src/uni_modules/uni-data-checkbox/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-data-checkbox", + "displayName": "uni-data-checkbox 数据选择器", + "version": "1.0.6", + "description": "通过数据驱动的单选框和复选框", + "keywords": [ + "uni-ui", + "checkbox", + "单选", + "多选", + "单选多选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-load-more","uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/src/uni_modules/uni-data-checkbox/readme.md b/src/uni_modules/uni-data-checkbox/readme.md new file mode 100644 index 0000000..6eb253d --- /dev/null +++ b/src/uni_modules/uni-data-checkbox/readme.md @@ -0,0 +1,18 @@ + + +## DataCheckbox 数据驱动的单选复选框 +> **组件名:uni-data-checkbox** +> 代码块: `uDataCheckbox` + + +本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括: + +1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能 +2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验 +3. 本组件合并了单选多选 +4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性 + +在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/src/uni_modules/uni-data-picker/changelog.md b/src/uni_modules/uni-data-picker/changelog.md new file mode 100644 index 0000000..10dd088 --- /dev/null +++ b/src/uni_modules/uni-data-picker/changelog.md @@ -0,0 +1,79 @@ +## 2.0.2(2025-04-14) +- 修复 在readonly属性为true时选项匹配错误的问题 +## 2.0.0(2023-12-14) +- 新增 支持 uni-app-x +## 1.1.2(2023-04-11) +- 修复 更改 modelValue 报错的 bug +- 修复 v-for 未使用 key 值控制台 warning +## 1.1.1(2023-02-21) +- 修复代码合并时引发 value 属性为空时不渲染数据的问题 +## 1.1.0(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.9(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.8(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.7(2022-07-06) +- 优化 pc端图标位置不正确的问题 +## 1.0.6(2022-07-05) +- 优化 显示样式 +## 1.0.5(2022-07-04) +- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +## 1.0.4(2022-04-19) +- 修复 字节小程序 本地数据无法选择下一级的Bug +## 1.0.3(2022-02-25) +- 修复 nvue 不支持的 v-show 的 bug +## 1.0.2(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式 +## 1.0.1(2021-11-23) +- 修复 由上个版本引发的map、v-model等属性不生效的bug +## 1.0.0(2021-11-19) +- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +## 0.4.9(2021-10-28) +- 修复 VUE2 v-model 概率无效的 bug +## 0.4.8(2021-10-27) +- 修复 v-model 概率无效的 bug +## 0.4.7(2021-10-25) +- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+ +- 修复 树型 uniCloud 数据类型为 int 时报错的 bug +## 0.4.6(2021-10-19) +- 修复 非 VUE3 v-model 为 0 时无法选中的 bug +## 0.4.5(2021-09-26) +- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效 +- 修复 readonly 为 true 时报错的 bug +## 0.4.4(2021-09-26) +- 修复 上一版本造成的 map 属性失效的 bug +- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略 +## 0.4.3(2021-09-24) +- 修复 某些情况下级联未触发的 bug +## 0.4.2(2021-09-23) +- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用 +- 新增 选项内容过长自动添加省略号 +## 0.4.1(2021-09-15) +- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段 +## 0.4.0(2021-07-13) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.3.5(2021-06-04) +- 修复 无法加载云端数据的问题 +## 0.3.4(2021-05-28) +- 修复 v-model 无效问题 +- 修复 loaddata 为空数据组时加载时间过长问题 +- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点 +## 0.3.3(2021-05-12) +- 新增 组件示例地址 +## 0.3.2(2021-04-22) +- 修复 非树形数据有 where 属性查询报错的问题 +## 0.3.1(2021-04-15) +- 修复 本地数据概率无法回显时问题 +## 0.3.0(2021-04-07) +- 新增 支持云端非树形表结构数据 +- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题 +## 0.2.0(2021-03-15) +- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题 +## 0.1.9(2021-03-09) +- 修复 微信小程序某些情况下无法选择的问题 +## 0.1.8(2021-02-05) +- 优化 部分样式在 nvue 上的兼容表现 +## 0.1.7(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js new file mode 100644 index 0000000..6ef26a2 --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue b/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue new file mode 100644 index 0000000..4b6510f --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue @@ -0,0 +1,381 @@ + ++ + + ++ {{mixinDatacomErrorMessage}} ++ + ++ + + ++ + + + + + diff --git a/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue b/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue new file mode 100644 index 0000000..f911885 --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue @@ -0,0 +1,545 @@ + ++ ++ ++ +{{error!.errMsg}} ++ ++ + +{{item[mappingTextName]}} +{{split}} + +{{placeholder}} ++ ++ + ++ + + ++ + ++ +{{popupTitle}} ++ ++ + + ++ +{{error!.errMsg}} ++ ++ + ++ {{item[mappingTextName]}} + + ++ ++ +{{item[mappingTextName]}} ++ + ++ + + + + + + diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts new file mode 100644 index 0000000..baa0dff --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts @@ -0,0 +1 @@ +export const imgbase : string = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZVHb98LM+F5bHL8khA1iSeiyQBCRM+YGqKUnnJTDLGI0BGZlKDIU2MMglUiDApEZvSsZnQtBRJtKwQNKQMFYeRDR10WOLd8ljYXdh+v8v5fR3Od+797t1dnOnO/Ofce77z+J//+b/P+ZqtXbs2sJ9MJhNUV1cHJ06cCJo3bx7EPc2aNcvpy7pWrVoF+/fvDyoqKoI2bdoE9fX1F7TjN8a+EXBn/fkfvw942Tf+wYMHg9mzZwfjxo0LDhw4EPa1x2MbFw/fOGfPng1qa2tzcCkILsLDydq2bRsunpOTMM7TD/W/tZDZhPdeKD+yGxHhdu3aBV27dg3OnDlzMVANMheLAO3btw8KCwuDmpoaX5OxbgUIMEq7K8IcPnw4KCsrC/r37x8cP378/4cAXAB3vqSkJMuiDhTkw+XcuXNhOWbMmKBly5YhUT8xArhyFvP0BfwRsAuwxJZJsm/nzp2DTp06he/OU+cZ64K6o0ePBkOHDg2GDx8e6gEbJ5Q/NHNuAJQ1hgBeHUDlR7nVTkY8rQAvAi4z34vR/mPs1FoRsaCgIJThI0eOBC1atEiFGGV+5MiRoS45efJkqFjJFXV1dQuA012m2WcwTw98fy6CqBdsaiIO4CScrGPHjvk4odhavPquRtFWXEC25VgkREKOCh/qDSq+vn37htzD/mZTOmOc5U7zKzBPEedygWshcDyWvs30igAbU+6oyMgJBCFhwQE0fccxN60Ay9iebbjoDh06hMowjQxT4fXq1SskArmHZpkArvixp/kWzHdMeArExSJEaiXIjjRjRJ4DaAGWpibLzXN3Fm1vA5teBgh3j1Rv3bp1YgKwPdmf2p9zcyNYYgPKMfY0T5f5nNYdw158nJ8QawW4CLKwiOBSEgO/hok2eBydR+3dYH+PLxA5J8Vv0KBBwenTp0P2JWAx6+yFEBfs8lMY+y0SWMBNI9E4ThKi58VKTg3FQZS1RQF1cz27eC0QHMu+3E0SkUowjhVt5VdaWhp07949ZHv2Qd1EjDXM2cla1M0nl3GxAs3J9yREzyTdFVKVFOaE9qRA8GM0WebRuo9JGZKA7Mv2SeS/Z8+eoQ9BArMfFrLGo6jvxbhHbJZnKX2Rzz1O7QhJJ9Cs2ZMaWIyq/zhdeqPNfIoHd58clIQD+JSXl4dKlyIAuBdVXZwFVWKspSSoxE++h8x4k3uCnEhE4I5KwRiFWGOU0QWKiCYLbdoRMRKAu2kQ9vkfLU6dOhX06NEjlH+yMRZSinnuyWnYosVcji8CEA/6Cg2JF+IIUBqnGKUTCNwtwBN4f89RiK1R96DEgO2o0NDmtEdvVFdVVYV+P3UAPUEs6GFwV3PHmXkD4vh74iDFJysVI/MlaQhwKeBNTLYX5VuA8T4/gZxA4MRGFxDB6R7OmYPfyykGRJbyie+XnGYnQIC/coH9+vULiYrxrkL9ZA9+0ykaHIfEpM7ge8TiJ2CsHYwyMfafAF1yCGBHYIbCVDjDjKt7BeB51D+LgQa6OkG7IDYEEtvQ7lnXLKLtLdLuJBpE4gPUXcW2+PkZwOex+4cGDhwYDBkyRL7/HFcEwUGPo/8uWRUpYnfxGHco8HkewLHLyYmAawAPuIFZxhOpDfJQ8gbUv41yORAptMWBNr6oqMhWird5+u+iHmBb2nhjDV7HWBNQTgK8y11l5NetWzc5ULscAtSj7nbNI0skhWeUZCc0W4nyH/jO4Vz0u1IeYhbk4AiwM6tjxIWByHsoZ9qcIBPJd/y+DwPfBESOmCa/QF3WiZHucLlEDpNxcNhmheEOPgdQNx6/VZFQzFZ5TN08AHXQt2Ii3EdyFuUsPtTcGPhW5iMiCNELvz+Gdn9huG4HUJaW/w3g0wxV0XaG7arG2WeKiUWYM4Y7GO5ezshTARbbWGw/DvXkpp/ivVvE0JVoMxN4rpGzJMhE5Pl+xlATsDIqikP9F9D2z3h9nOksEUFhK+qO4rcPkoalMQ/HqJLIyb3F3JdjrCcw1yZ8joyJLR5gCo54etlag7qIoeNh1N1BRYj3DTFJ0elotxPlVzkGuYAmL0VSJVGAJA41c4Z6A3BzTLfn0HYwYKEI6CUAMzZEWvLsIcQOo1AmmyyM72nHJCfYsogflGV6jEk9vyQZXSuq6w4c16NsGcGZbwOPr+H1RkOk2LEzjNepxQkihHSCQ4ynAYNRx2zMKV92CQMWqj8J0BRE8EShxRFN6YrfCRhC0x3r/Zm4IbQCcmJoV0kMamllccR6FjHqUC5F2R/wS2dcymOlfAKOS4KmzQb5cpNC2MC7JhVn5wjXoJ44rYhLh8n0eXOCorJxa7POjbSlCGVczr34/RsAmrcvo9s+wGp3tzVhntxiXiJ4nvEYb4FJkf0O8HocAePmLvCxnL0AORraVekJk6TYjDabRVXfRE2lCN1h6ZQRN1+InUbsCpKwoBZHh0dODN9JBCUffItXxEavTQkUtnfTVAplCWL3JISz29h4NjotnuSsQKJCk8dF+kJR6RARjrqFVmfPnj3ZbK8cIJ0msd6jgHPGtfVTQ8VLmlvh4mct9sobRmPic0DyDQQnx/NlfYUgyz59+oScsH379pAwXABD32nTpoUHIToESeI5mnbE/UqDdyLcafEBf2MCqgC7NwxIbMREJQ0g4D4sfJwnD+AmRrII05cfMWJE+L1169bQr+fip06dGp4oJ83lmYd5wj/EmMa4TaHivo4EeCguYZBnkB5g2aWA69OIEnUHOaGysjIYMGBAMGnSpODYsWPZwCpFmm4lNq+4gSLQA7jcX8DwtjEyRC8wjabnXEx9kfWnTJkSJkAo90xpJVV+FmcVNeYAF5zWngS4C4O91MBxmAv8blLEpbjI5sz9MTdAhcgkCT1RO8mZkAjfiYpTEvStAS53Uw1vAiUGgZ3GpuQEYvoiBqlIan7kSDHnTwJQFNiPu0+5VxCVYhcZIjNrdXUDdp+Eq5AZ3Gkg8QAyVZRZIk4Tl4QAbF9cXJxNYZMAtAokgs4BrNxEpCtteXg7DDTMDKYNSuQdKsnJBek7HxewvxaosWxLYXtw+cJp18217wql4aKCfBNoEu0O5VU+PhctJ0YeXD4C6JQpyrlpSLTojpGGGN5YwNziChdIZLk4lvLcFJ9jMX3QdiImY9bmGQU+TRUL5CHITTRlgF8D9ouD1MfmLoEPl5xokIumZ2cfgMpHt47IW9N64Hsh7wQYYjyIugWuF5fCqYncXRd5vPMWyizzvhi/32+nvG0dZc9vR6fZOu0md5e+uC408FvKSIOZwXlGvxPv95izA2Vtvg1xKFWARI+vMX66HUhpQQb643uW1bSjuTWyw2SBvDrBvjFic1eGGlz5esq3ko9uSIlBRqPuFcCv8F4WIcN12nVaBd0SaYwI6PDDImR11JkqgHcPmQssjxIn6bUshygDFJUTxPMpHk+jfjPgupgdnYV2R/g7xSjtpah8RJBewhwf0gGK6XI92u4wXFEU40afJ4DN4h5LcAd+40HI3JgJecuT0c062W0i2hQJUTcxan3/CMW1PF2K6bbA+Daz4xRs1D3Br1Cm0OihKCqizW78/nXAF/G5TXrEcVzaNMH6CyMswqsAHqDyDLEyou8lwOXnKF8DjI6KjV3KzMBiXkDH8ij/H214J5A596ekrZ3F0zXlWeL7+P5eUrNo3/QwC15uxthuzidy7DzKRwEDaAViiDgKbTbz7CJnzo0bN7pIfIiid8SuPwn25o3QCmpnyjlZkyxPP8EomCJzrGb7GJMx7tNsq4MT2xMUYaiErZOluTzKsnz3gwCeCZyVRZJfYplNEokEjwrPtxlxjeYAk+F1F74VAzPxQRNYYdtpOUvWs8J1sGhBJMNsb7igN8plJs1eSmLIhLKE4rvaCX27gOhLpLOsIzJ7qn/i+wZzcvSOZ23/du8TZjwV8zHIXoP4R3ifBxiFz1dcVpa3aPntPE+c6TmIWE9EtcMmAcPdWAhYhAXxcLOQi9L1WhD1Sc8p1d2oL7XGiRKp8F4A2i8K/nfI+y/gsTDJ/YC/8+AD5Uh04KHiGl+cIFPnBDDrPMjwRGkLXyxO4VGbfQWnDH2v0bVWE3C9QOXlepbgjEfIJQI6XDG3z5ahD9cw2pS78ipB85wyScNTvsVzlzzhL8/jRrnmVjfFJK/m3m4nj9vbgQTguT8XZTjsm672R5uJKEaQmBI/c58gyus8ZDagLpEVSJBIyHp4jn++xqPV71OgQgJYEWOtZ/haxRtKmWOBu8xdBLftWltsY84zE6WIEy/eIOWL+BaayMx+KHtL7EAkqdNDLiEXmEMUHniedtJqg9HmZtfvt26vNi0BdG3Ft3g8ZOf7PAu59TxtzivLNIekyi+wD1i8CuUiD9FXAa8C+/xS3JPmZnomyc7H+fb4/Se0bk41Fel621r4cgVxbq91V4jVqwB7HTe2M7jgB+QWHavZkDRPmZcASoZEmBx6i75bGjPcMdL4/VKGFAGWZkGzPG0XAbdL9A81G5LOmUnC9hHKJeO7dcUMjblSl12867ElFTtaGl20xvvLGPdVz/8TVuU7y0x1PG7vtNg24oz9Uo/Z412++VFWI7Fcog9tu9Lm6gvRmIPv9x1xmQAu6RDkXtbOtlGEmpgD5Nvnyc0dcv0EE6cfdi1HmhMf9wDF3k3gtRvEedhxjpgfqPb9PU9iEJHnyOUA7bQUXh6kq/D7l2iTjWv7XOD530BDr8jIrus+srXjt4MzumJMHuTsBa63YKE1+RR5lBjEikCCnWKWiHdzOgKO+nRIBAF88za/IFmJ3eMZov4CYxGBabcpGL8EYx+SeMXJeRwHNsV/h+vdxeuhEpN3ZyNY78Gm2fknJxVGhyjixPiQvVkNzT1elD9Py/aTAL64Hb9vcYmC9zfdXdT/C1LeGbg4rnBaAihDFJH12W5ulfNCNe/xTsP3bp8ikzJs5BF+5PNfAQYAPaseTdsEcaYAAAAASUVORK5CYII=' \ No newline at end of file diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js new file mode 100644 index 0000000..cfae22a --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js @@ -0,0 +1,622 @@ +export default { + props: { + localdata: { + type: [Array, Object], + default () { + return [] + } + }, + spaceInfo: { + type: Object, + default () { + return {} + } + }, + collection: { + type: String, + default: '' + }, + action: { + type: String, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: [String, Object], + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 500 + }, + getcount: { + type: [Boolean, String], + default: false + }, + getone: { + type: [Boolean, String], + default: false + }, + gettree: { + type: [Boolean, String], + default: false + }, + manual: { + type: Boolean, + default: false + }, + value: { + type: [Array, String, Number], + default () { + return [] + } + }, + modelValue: { + type: [Array, String, Number], + default () { + return [] + } + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + map: { + type: Object, + default () { + return { + text: "text", + value: "value" + } + } + } + }, + data() { + return { + loading: false, + errorMessage: '', + loadMore: { + contentdown: '', + contentrefresh: '', + contentnomore: '' + }, + dataList: [], + selected: [], + selectedIndex: 0, + page: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + } + } + }, + computed: { + isLocalData() { + return !this.collection.length; + }, + isCloudData() { + return this.collection.length > 0; + }, + isCloudDataList() { + return (this.isCloudData && (!this.parentField && !this.selfField)); + }, + isCloudDataTree() { + return (this.isCloudData && this.parentField && this.selfField); + }, + dataValue() { + let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || + this.modelValue !== undefined); + return isModelValue ? this.modelValue : this.value; + }, + hasValue() { + if (typeof this.dataValue === 'number') { + return true + } + return (this.dataValue != null) && (this.dataValue.length > 0) + } + }, + created() { + this.$watch(() => { + var al = []; + ['pageCurrent', + 'pageSize', + 'spaceInfo', + 'value', + 'modelValue', + 'localdata', + 'collection', + 'action', + 'field', + 'orderby', + 'where', + 'getont', + 'getcount', + 'gettree' + ].forEach(key => { + al.push(this[key]) + }); + return al + }, (newValue, oldValue) => { + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (newValue[0] != oldValue[0]) { + this.page.current = this.pageCurrent + } + this.page.size = this.pageSize + + this.onPropsChange() + }) + this._treeData = [] + }, + methods: { + onPropsChange() { + this._treeData = []; + }, + + // 填充 pickview 数据 + async loadData() { + if (this.isLocalData) { + this.loadLocalData(); + } else if (this.isCloudDataList) { + this.loadCloudDataList(); + } else if (this.isCloudDataTree) { + this.loadCloudDataTree(); + } + }, + + // 加载本地数据 + async loadLocalData() { + this._treeData = []; + this._extractTree(this.localdata, this._treeData); + + let inputValue = this.dataValue; + if (inputValue === undefined) { + return; + } + + if (Array.isArray(inputValue)) { + inputValue = inputValue[inputValue.length - 1]; + if (typeof inputValue === 'object' && inputValue[this.map.value]) { + inputValue = inputValue[this.map.value]; + } + } + + this.selected = this._findNodePath(inputValue, this.localdata); + }, + + // 加载 Cloud 数据 (单列) + async loadCloudDataList() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let response = await this.getCommand(); + let responseData = response.result.data; + + this._treeData = responseData; + + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (树形) + async loadCloudDataTree() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere() + }; + if (this.gettree) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`; + } + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + this._treeData = responseData; + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (节点) + async loadCloudDataNode(callback) { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + }; + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + callback(responseData); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 回显 Cloud 数据 + getCloudDataValue() { + if (this.isCloudDataList) { + return this.getCloudDataListValue(); + } + + if (this.isCloudDataTree) { + return this.getCloudDataTreeValue(); + } + }, + + // 回显 Cloud 数据 (单列) + getCloudDataListValue() { + // 根据 field's as value标识匹配 where 条件 + let where = []; + let whereField = this._getForeignKeyByField(); + if (whereField) { + where.push(`${whereField} == '${this.dataValue}'`) + } + + where = where.join(' || '); + + if (this.where) { + where = `(${this.where}) && (${where})` + } + + return this.getCommand({ + field: this._cloudDataPostField(), + where + }).then((res) => { + this.selected = res.result.data; + return res.result.data; + }); + }, + + // 回显 Cloud 数据 (树形) + getCloudDataTreeValue() { + return this.getCommand({ + field: this._cloudDataPostField(), + getTreePath: { + startWith: `${this.selfField}=='${this.dataValue}'` + } + }).then((res) => { + let treePath = []; + this._extractTreePath(res.result.data, treePath); + this.selected = treePath; + return treePath; + }); + }, + + getCommand(options = {}) { + /* eslint-disable no-undef */ + let db = uniCloud.database(this.spaceInfo) + + const action = options.action || this.action + if (action) { + db = db.action(action) + } + + const collection = options.collection || this.collection + db = db.collection(collection) + + const where = options.where || this.where + if (!(!where || !Object.keys(where).length)) { + db = db.where(where) + } + + const field = options.field || this.field + if (field) { + db = db.field(field) + } + + const orderby = options.orderby || this.orderby + if (orderby) { + db = db.orderBy(orderby) + } + + const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current + const size = options.pageSize !== undefined ? options.pageSize : this.page.size + const getCount = options.getcount !== undefined ? options.getcount : this.getcount + const getTree = options.gettree !== undefined ? options.gettree : this.gettree + + const getOptions = { + getCount, + getTree + } + if (options.getTreePath) { + getOptions.getTreePath = options.getTreePath + } + + db = db.skip(size * (current - 1)).limit(size).get(getOptions) + + return db + }, + + _cloudDataPostField() { + let fields = [this.field]; + if (this.parentField) { + fields.push(`${this.parentField} as parent_value`); + } + return fields.join(','); + }, + + _cloudDataTreeWhere() { + let result = [] + let selected = this.selected + let parentField = this.parentField + if (parentField) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selected.length) { + for (var i = 0; i < selected.length - 1; i++) { + result.push(`${parentField} == '${selected[i].value}'`) + } + } + + let where = [] + if (this.where) { + where.push(`(${this.where})`) + } + + if (result.length) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() { + let where = [] + let selected = this.selected; + if (selected.length) { + where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`); + } + + where = where.join(' || '); + + if (this.where) { + return `(${this.where}) && (${where})` + } + + return where + }, + + _getWhereByForeignKey() { + let result = [] + let whereField = this._getForeignKeyByField(); + if (whereField) { + result.push(`${whereField} == '${this.dataValue}'`) + } + + if (this.where) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() { + let fields = this.field.split(','); + let whereField = null; + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as'); + if (items.length < 2) { + continue; + } + if (items[1].trim() === 'value') { + whereField = items[0].trim(); + break; + } + } + return whereField; + }, + + _updateBindData(node) { + const { + dataList, + hasNodes + } = this._filterData(this._treeData, this.selected) + + let isleaf = this._stepSearh === false && !hasNodes + + if (node) { + node.isleaf = isleaf + } + + this.dataList = dataList + this.selectedIndex = dataList.length - 1 + + if (!isleaf && this.selected.length < dataList.length) { + this.selected.push({ + value: null, + text: "请选择" + }) + } + + return { + isleaf, + hasNodes + } + }, + + _updateSelected() { + let dl = this.dataList + let sl = this.selected + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < sl.length; i++) { + let value = sl[i].value + let dl2 = dl[i] + for (let j = 0; j < dl2.length; j++) { + let item2 = dl2[j] + if (item2[valueField] === value) { + sl[i].text = item2[textField] + break + } + } + } + }, + + _filterData(data, paths) { + let dataList = [] + let hasNodes = true + + dataList.push(data.filter((item) => { + return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '') + })) + for (let i = 0; i < paths.length; i++) { + let value = paths[i].value + let nodes = data.filter((item) => { + return item.parent_value === value + }) + + if (nodes.length) { + dataList.push(nodes) + } else { + hasNodes = false + } + } + + return { + dataList, + hasNodes + } + }, + + _extractTree(nodes, result, parent_value) { + let list = result || [] + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + if (parent_value !== null && parent_value !== undefined && parent_value !== '') { + child.parent_value = parent_value + } + result.push(child) + + let children = node.children + if (children) { + this._extractTree(children, result, node[valueField]) + } + } + }, + + _extractTreePath(nodes, result) { + let list = result || [] + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + result.push(child) + + let children = node.children + if (children) { + this._extractTreePath(children, result) + } + } + }, + + _findNodePath(key, nodes, path = []) { + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + let children = node.children + let text = node[textField] + let value = node[valueField] + + path.push({ + value, + text + }) + + if (value === key) { + return path + } + + if (children) { + const p = this._findNodePath(key, children, path) + if (p.length) { + return p + } + } + + path.pop() + } + return [] + } + } +} diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts new file mode 100644 index 0000000..857408d --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts @@ -0,0 +1,692 @@ +export type PaginationType = { + current : number, + size : number, + count : number +} + +export type LoadMoreType = { + contentdown : string, + contentrefresh : string, + contentnomore : string +} + +export type SelectedItemType = { + name : string, + value : string, +} + +export type GetCommandOptions = { + collection ?: UTSJSONObject, + field ?: string, + orderby ?: string, + where ?: any, + pageData ?: string, + pageCurrent ?: number, + pageSize ?: number, + getCount ?: boolean, + getTree ?: any, + getTreePath ?: UTSJSONObject, + startwith ?: string, + limitlevel ?: number, + groupby ?: string, + groupField ?: string, + distinct ?: boolean, + pageIndistinct ?: boolean, + foreignKey ?: string, + loadtime ?: string, + manual ?: boolean +} + +const DefaultSelectedNode = { + text: '请选择', + value: '' +} + +export const dataPicker = defineMixin({ + props: { + localdata: { + type: Array as PropType+ ++ ++ +{{errorMessage}} ++ ++ + ++ ++ +{{item.text}} {{split}} +{{placeholder}} ++ ++ + ++ + + ++ + ++ +{{popupTitle}} ++ ++ + + +>, + default: [] as Array + }, + collection: { + type: Object, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: Object, + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 20 + }, + getcount: { + type: Boolean, + default: false + }, + gettree: { + type: Object, + default: '' + }, + gettreepath: { + type: Object, + default: '' + }, + startwith: { + type: String, + default: '' + }, + limitlevel: { + type: Number, + default: 10 + }, + groupby: { + type: String, + default: '' + }, + groupField: { + type: String, + default: '' + }, + distinct: { + type: Boolean, + default: false + }, + pageIndistinct: { + type: Boolean, + default: false + }, + foreignKey: { + type: String, + default: '' + }, + loadtime: { + type: String, + default: 'auto' + }, + manual: { + type: Boolean, + default: false + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + value: { + type: Object, + default: '' + }, + modelValue: { + type: Object, + default: '' + }, + defaultProps: { + type: Object as PropType , + } + }, + data() { + return { + loading: false, + error: null as UniCloudError | null, + treeData: [] as Array , + selectedIndex: 0, + selectedNodes: [] as Array , + selectedPages: [] as Array [], + selectedValue: '', + selectedPaths: [] as Array , + pagination: { + current: 1, + size: 20, + count: 0 + } as PaginationType + } + }, + computed: { + mappingTextName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text' + }, + mappingValueName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value' + }, + currentDataList() : Array { + if (this.selectedIndex > this.selectedPages.length - 1) { + return [] as Array + } + return this.selectedPages[this.selectedIndex] + }, + isLocalData() : boolean { + return this.localdata.length > 0 + }, + isCloudData() : boolean { + return this._checkIsNotNull(this.collection) + }, + isCloudDataList() : boolean { + return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0)) + }, + isCloudDataTree() : boolean { + return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0) + }, + dataValue() : any { + return this.hasModelValue ? this.modelValue : this.value + }, + hasCloudTreeData() : boolean { + return this.treeData.length > 0 + }, + hasModelValue() : boolean { + if (typeof this.modelValue == 'string') { + const valueString = this.modelValue as string + return (valueString.length > 0) + } else if (Array.isArray(this.modelValue)) { + const valueArray = this.modelValue as Array + return (valueArray.length > 0) + } + return false + }, + hasCloudDataValue() : boolean { + if (typeof this.dataValue == 'string') { + const valueString = this.dataValue as string + return (valueString.length > 0) + } + return false + } + }, + created() { + this.pagination.current = this.pageCurrent + this.pagination.size = this.pageSize + + this.$watch( + () : any => [ + this.pageCurrent, + this.pageSize, + this.localdata, + this.value, + this.collection, + this.field, + this.getcount, + this.orderby, + this.where, + this.groupby, + this.groupField, + this.distinct + ], + (newValue : Array , oldValue : Array ) => { + this.pagination.size = this.pageSize + if (newValue[0] !== oldValue[0]) { + this.pagination.current = this.pageCurrent + } + + this.onPropsChange() + } + ) + }, + methods: { + onPropsChange() { + this.selectedIndex = 0 + this.selectedNodes.length = 0 + this.selectedPages.length = 0 + this.selectedPaths.length = 0 + + // 加载数据 + this.$nextTick(() => { + this.loadData() + }) + }, + + onTabSelect(index : number) { + this.selectedIndex = index + }, + + onNodeClick(nodeData : UTSJSONObject) { + if (nodeData.getBoolean('disable', false)) { + return + } + + const isLeaf = this._checkIsLeafNode(nodeData) + + this._trimSelectedNodes(nodeData) + + this.$emit('nodeclick', nodeData) + + if (this.isLocalData) { + if (isLeaf || !this._checkHasChildren(nodeData)) { + this.onFinish() + } + } else if (this.isCloudDataList) { + this.onFinish() + } else if (this.isCloudDataTree) { + if (isLeaf) { + this.onFinish() + } else if (!this._checkHasChildren(nodeData)) { + // 尝试请求一次,如果没有返回数据标记为叶子节点 + this.loadCloudDataNode(nodeData) + } + } + }, + + getChangeNodes(): Array { + const nodes: Array = [] + this.selectedNodes.forEach((node : UTSJSONObject) => { + const newNode: UTSJSONObject = {} + newNode[this.mappingTextName] = node.getString(this.mappingTextName) + newNode[this.mappingValueName] = node.getString(this.mappingValueName) + nodes.push(newNode) + }) + return nodes + }, + + onFinish() { }, + + // 加载数据(自动判定环境) + loadData() { + if (this.isLocalData) { + this.loadLocalData() + } else if (this.isCloudDataList) { + this.loadCloudDataList() + } else if (this.isCloudDataTree) { + this.loadCloudDataTree() + } + }, + + // 加载本地数据 + loadLocalData() { + this.treeData = this.localdata + if (Array.isArray(this.dataValue)) { + const value = this.dataValue as Array + this.selectedPaths = value.slice(0) + this._pushSelectedTreeNodes(value, this.localdata) + } else { + this._pushSelectedNodes(this.localdata) + } + }, + + // 加载 Cloud 数据 (单列) + loadCloudDataList() { + this._loadCloudData(null, (data : Array ) => { + this.treeData = data + this._pushSelectedNodes(data) + }) + }, + + // 加载 Cloud 数据 (树形) + loadCloudDataTree() { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere(), + getTree: true + } as GetCommandOptions + if (this._checkIsNotNull(this.gettree)) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'` + } + this._loadCloudData(commandOptions, (data : Array ) => { + this.treeData = data + if (this.selectedPaths.length > 0) { + this._pushSelectedTreeNodes(this.selectedPaths, data) + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 加载 Cloud 数据 (节点) + loadCloudDataNode(nodeData : UTSJSONObject) { + const commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + } as GetCommandOptions + this._loadCloudData(commandOptions, (data : Array ) => { + nodeData['children'] = data + if (data.length == 0) { + nodeData['isleaf'] = true + this.onFinish() + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 回显 Cloud Tree Path + loadCloudDataPath() { + if (!this.hasCloudDataValue) { + return + } + + const command : GetCommandOptions = {} + + // 单列 + if (this.isCloudDataList) { + // 根据 field's as value标识匹配 where 条件 + let where : Array = []; + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + where.push(`${whereField} == '${this.dataValue as string}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + whereString = `(${this.where}) && (${whereString})` + } + + command.field = this._cloudDataPostField() + command.where = whereString + } + + // 树形 + if (this.isCloudDataTree) { + command.field = this._cloudDataPostField() + command.getTreePath = { + startWith: `${this.selfField}=='${this.dataValue as string}'` + } + } + + this._loadCloudData(command, (data : Array ) => { + this._extractTreePath(data, this.selectedPaths) + }) + }, + + _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array ) => void)) { + if (this.loading) { + return + } + this.loading = true + + this.error = null + + this._getCommand(options).then((response : UniCloudDBGetResult) => { + callback?.(response.data) + }).catch((err : any | null) => { + this.error = err as UniCloudError + }).finally(() => { + this.loading = false + }) + }, + + _cloudDataPostField() : string { + let fields = [this.field]; + if (this.parentField.length > 0) { + fields.push(`${this.parentField} as parent_value`) + } + return fields.join(',') + }, + + _cloudDataTreeWhere() : string { + let result : Array = [] + let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths + let parentField = this.parentField + if (parentField.length > 0) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selectedNodes.length > 0) { + for (var i = 0; i < selectedNodes.length - 1; i++) { + const parentFieldValue = selectedNodes[i].getString('value', '') + result.push(`${parentField} == '${parentFieldValue}'`) + } + } + + let where : Array = [] + if (this._checkIsNotNull(this.where)) { + where.push(`(${this.where as string})`) + } + + if (result.length > 0) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() : string { + const where : Array = [] + if (this.selectedNodes.length > 0) { + const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '') + where.push(`${this.parentField} == '${value}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + return `(${this.where as string}) && (${whereString})` + } + + return whereString + }, + + _getWhereByForeignKey() : string { + let result : Array = [] + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + result.push(`${whereField} == '${this.dataValue as string}'`) + } + + if (this._checkIsNotNull(this.where)) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() : string { + const fields = this.field.split(',') + let whereField = '' + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as') + if (items.length < 2) { + continue + } + if (items[1].trim() === 'value') { + whereField = items[0].trim() + break + } + } + return whereField + }, + + _getCommand(options ?: GetCommandOptions) : Promise { + let db = uniCloud.databaseForJQL() + + let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array )) : db.collection(this.collection) + + let filter : UniCloudDBFilter | null = null + if (this.foreignKey.length > 0) { + filter = collection.foreignKey(this.foreignKey) + } + + const where : any = options?.where ?? this.where + if (typeof where == 'string') { + const whereString = where as string + if (whereString.length > 0) { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + } else { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + + let query : UniCloudDBQuery | null = null + if (this.field.length > 0) { + query = (filter != null) ? filter.field(this.field) : collection.field(this.field) + } + if (this.groupby.length > 0) { + if (query != null) { + query = query.groupBy(this.groupby) + } else if (filter != null) { + query = filter.groupBy(this.groupby) + } + } + if (this.groupField.length > 0) { + if (query != null) { + query = query.groupField(this.groupField) + } else if (filter != null) { + query = filter.groupField(this.groupField) + } + } + if (this.distinct == true) { + if (query != null) { + query = query.distinct(this.field) + } else if (filter != null) { + query = filter.distinct(this.field) + } + } + if (this.orderby.length > 0) { + if (query != null) { + query = query.orderBy(this.orderby) + } else if (filter != null) { + query = filter.orderBy(this.orderby) + } + } + + const size = this.pagination.size + const current = this.pagination.current + if (query != null) { + query = query.skip(size * (current - 1)).limit(size) + } else if (filter != null) { + query = filter.skip(size * (current - 1)).limit(size) + } else { + query = collection.skip(size * (current - 1)).limit(size) + } + + const getOptions = {} + const treeOptions = { + limitLevel: this.limitlevel, + startWith: this.startwith + } + if (this.getcount == true) { + getOptions['getCount'] = this.getcount + } + + const getTree : any = options?.getTree ?? this.gettree + if (typeof getTree == 'string') { + const getTreeString = getTree as string + if (getTreeString.length > 0) { + getOptions['getTree'] = treeOptions + } + } else if (typeof getTree == 'object') { + getOptions['getTree'] = treeOptions + } else { + getOptions['getTree'] = getTree + } + + const getTreePath = options?.getTreePath ?? this.gettreepath + if (typeof getTreePath == 'string') { + const getTreePathString = getTreePath as string + if (getTreePathString.length > 0) { + getOptions['getTreePath'] = getTreePath + } + } else { + getOptions['getTreePath'] = getTreePath + } + + return query.get(getOptions) + }, + + _checkIsNotNull(value : any) : boolean { + if (typeof value == 'string') { + const valueString = value as string + return (valueString.length > 0) + } else if (value instanceof UTSJSONObject) { + return true + } + return false + }, + + _checkIsLeafNode(nodeData : UTSJSONObject) : boolean { + if (this.selectedIndex >= this.limitlevel) { + return true + } + + if (nodeData.getBoolean('isleaf', false)) { + return true + } + + return false + }, + + _checkHasChildren(nodeData : UTSJSONObject) : boolean { + const children = nodeData.getArray('children') ?? ([] as Array ) + return children.length > 0 + }, + + _pushSelectedNodes(nodes : Array ) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(nodes) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _trimSelectedNodes(nodeData : UTSJSONObject) { + this.selectedNodes.splice(this.selectedIndex) + this.selectedNodes.push(nodeData) + + if (this.selectedPages.length > 0) { + this.selectedPages.splice(this.selectedIndex + 1) + } + + const children = nodeData.getArray ('children') ?? ([] as Array ) + if (children.length > 0) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(children) + } + + this.selectedIndex = this.selectedPages.length - 1 + }, + + _pushSelectedTreeNodes(paths : Array , nodes : Array ) { + let children : Array = nodes + paths.forEach((node : UTSJSONObject) => { + const findNode = children.find((item : UTSJSONObject) : boolean => { + return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName)) + }) + if (findNode != null) { + this.selectedPages.push(children) + this.selectedNodes.push(node) + children = findNode.getArray ('children') ?? ([] as Array ) + } + }) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _extractTreePath(nodes : Array , result : Array ) { + if (nodes.length == 0) { + return + } + + const node = nodes[0] + result.push(node) + + const children = node.getArray ('children') + if (Array.isArray(children) && children!.length > 0) { + this._extractTreePath(children, result) + } + } + } +}) diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css new file mode 100644 index 0000000..39fe1c3 --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css @@ -0,0 +1,76 @@ +.uni-data-pickerview { + position: relative; + flex-direction: column; + overflow: hidden; +} + +.loading-cover { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + align-items: center; + justify-content: center; + background-color: rgba(150, 150, 150, .1); +} + +.error { + background-color: #fff; + padding: 15px; +} + +.error-text { + color: #DD524D; +} + +.selected-node-list { + flex-direction: row; + flex-wrap: nowrap; +} + +.selected-node-item { + margin-left: 10px; + margin-right: 10px; + padding: 8px 10px 8px 10px; + border-bottom: 2px solid transparent; +} + +.selected-node-item-active { + color: #007aff; + border-bottom-color: #007aff; +} + +.list-view { + flex: 1; +} + +.list-item { + flex-direction: row; + justify-content: space-between; + padding: 12px 15px; + border-bottom: 1px solid #f0f0f0; +} + +.item-text { + color: #333333; +} + +.item-text-disabled { + opacity: .5; +} + +.item-text-overflow { + overflow: hidden; +} + +.check { + margin-right: 5px; + border: 2px solid #007aff; + border-left: 0; + border-top: 0; + height: 12px; + width: 6px; + transform-origin: center; + transform: rotate(45deg); +} diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue new file mode 100644 index 0000000..f4780f3 --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue @@ -0,0 +1,69 @@ + + + + + + + + diff --git a/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue new file mode 100644 index 0000000..7ef0950 --- /dev/null +++ b/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue @@ -0,0 +1,320 @@ + ++ +{{error!.errMsg}} ++ ++ + ++ {{item[mappingTextName]}} + + ++ ++ +{{item[mappingTextName]}} ++ + ++ + + + + + + \ No newline at end of file diff --git a/src/uni_modules/uni-data-picker/package.json b/src/uni_modules/uni-data-picker/package.json new file mode 100644 index 0000000..ba69c67 --- /dev/null +++ b/src/uni_modules/uni-data-picker/package.json @@ -0,0 +1,93 @@ +{ + "id": "uni-data-picker", + "displayName": "uni-data-picker 数据驱动的picker选择器", + "version": "2.0.2", + "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景", + "keywords": [ + "uni-ui", + "uniui", + "picker", + "级联", + "省市区", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-load-more", + "uni-icons", + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "y", + "app-harmony": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/src/uni_modules/uni-data-picker/readme.md b/src/uni_modules/uni-data-picker/readme.md new file mode 100644 index 0000000..19dd0e8 --- /dev/null +++ b/src/uni_modules/uni-data-picker/readme.md @@ -0,0 +1,22 @@ +## DataPicker 级联选择 +> **组件名:uni-data-picker** +> 代码块: `uDataPicker` +> 关联组件:`uni-data-pickerview`、`uni-load-more`。 + + +`+ ++ ++ +{{item.text || ''}} ++ ++ + ++ +{{item[map.text]}} ++ ++ + ++ ` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。 + +支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。 + +候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。 + +` ` 组件尤其适用于地址选择、分类选择等选择类。 + +` ` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。 + +` ` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。 + +在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/src/uni_modules/uni-load-more/changelog.md b/src/uni_modules/uni-load-more/changelog.md new file mode 100644 index 0000000..667abdb --- /dev/null +++ b/src/uni_modules/uni-load-more/changelog.md @@ -0,0 +1,25 @@ +## 1.3.6(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.5(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.4(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.3(2022-01-20) +- 新增 showText属性 ,是否显示文本 +## 1.3.2(2022-01-19) +- 修复 nvue 平台下不显示文本的bug +## 1.3.1(2022-01-19) +- 修复 微信小程序平台样式选择器报警告的问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more) +## 1.2.1(2021-08-24) +- 新增 支持国际化 +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-05-12) +- 新增 组件示例地址 +## 1.1.7(2021-03-30) +- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +## 1.1.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 0000000..a4f14a5 --- /dev/null +++ b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "Pull up to show more", + "uni-load-more.contentrefresh": "loading...", + "uni-load-more.contentnomore": "No more data" +} diff --git a/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 0000000..f15d510 --- /dev/null +++ b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉显示更多", + "uni-load-more.contentrefresh": "正在加载...", + "uni-load-more.contentnomore": "没有更多数据了" +} diff --git a/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 0000000..a255c6d --- /dev/null +++ b/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉顯示更多", + "uni-load-more.contentrefresh": "正在加載...", + "uni-load-more.contentnomore": "沒有更多數據了" +} diff --git a/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 0000000..a203417 --- /dev/null +++ b/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,404 @@ + + + + + + + + + diff --git a/src/uni_modules/uni-load-more/package.json b/src/uni_modules/uni-load-more/package.json new file mode 100644 index 0000000..cf44bff --- /dev/null +++ b/src/uni_modules/uni-load-more/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-load-more", + "displayName": "uni-load-more 加载更多", + "version": "1.3.6", + "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。", + "keywords": [ + "uni-ui", + "uniui", + "加载更多", + "load-more" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/src/uni_modules/uni-load-more/readme.md b/src/uni_modules/uni-load-more/readme.md new file mode 100644 index 0000000..54dc1fa --- /dev/null +++ b/src/uni_modules/uni-load-more/readme.md @@ -0,0 +1,14 @@ + + +### LoadMore 加载更多 +> **组件名:uni-load-more** +> 代码块: `uLoadMore` + + +用于列表中,做滚动加载使用,展示 loading 的各种状态。 + + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/src/uni_modules/uni-segmented-control/changelog.md b/src/uni_modules/uni-segmented-control/changelog.md new file mode 100644 index 0000000..02d0c8a --- /dev/null +++ b/src/uni_modules/uni-segmented-control/changelog.md @@ -0,0 +1,15 @@ +## 1.2.3(2024-04-02) +- 修复 修复在微信小程序下inactiveColor失效bug +## 1.2.2(2024-03-28) +- 修复 在vue2下:style动态绑定导致编译失败的bug +## 1.2.1(2024-03-20) +- 新增 inActiveColor属性,可供配置未激活时的颜色 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.5(2021-05-12) +- 新增 项目示例地址 +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/src/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue b/src/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue new file mode 100644 index 0000000..a69366a --- /dev/null +++ b/src/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue @@ -0,0 +1,146 @@ + ++ + + + + + + + + ++ + + + + ++ {{ status === 'more' ? contentdownText : status === 'loading' ? contentrefreshText : contentnomoreText }} ++ + + + + + diff --git a/src/uni_modules/uni-segmented-control/package.json b/src/uni_modules/uni-segmented-control/package.json new file mode 100644 index 0000000..49f9eff --- /dev/null +++ b/src/uni_modules/uni-segmented-control/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-segmented-control", + "displayName": "uni-segmented-control 分段器", + "version": "1.2.3", + "description": "分段器由至少 2 个分段控件组成,用作不同视图的显示", + "keywords": [ + "uni-ui", + "uniui", + "分段器", + "segement", + "顶部选择" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/uni-segmented-control/readme.md b/src/uni_modules/uni-segmented-control/readme.md new file mode 100644 index 0000000..3527b03 --- /dev/null +++ b/src/uni_modules/uni-segmented-control/readme.md @@ -0,0 +1,13 @@ + + +## SegmentedControl 分段器 +> **组件名:uni-segmented-control** +> 代码块: `uSegmentedControl` + + +用作不同视图的显示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/src/uni_modules/wu-calendar/changelog.md b/src/uni_modules/wu-calendar/changelog.md new file mode 100644 index 0000000..cbd309d --- /dev/null +++ b/src/uni_modules/wu-calendar/changelog.md @@ -0,0 +1,145 @@ +## 1.5.6(2024-11-25) +1. 修复上版本日历高度错误的bug +2. 新增clearSelect方法用于清除日历选择 +3. 新增todayDefaultStyle属性用于控制是否显示今日默认样式 +## 1.5.5(2024-11-14) +1. 通过减少view数量优化日历性能 +2. 修复nvue错误日历样式以及滑动时无法切换日历的bug +3. 修复nvue警告 +## 1.5.4(2024-10-12) +修复忘记删除方法,导致运行错误 +## 1.5.3(2024-10-12) +更新nvue下可能会造成日历重叠的bug +## 1.5.2(2024-06-14) +修复错误style语法 +## 1.5.1(2024-06-11) +修复弹窗确认与取消设置颜色不生效 +## 1.5.0(2024-06-03) +1. 修复monthSwitch事件初始化时被触发的问题 +2. monthSwitch事件新增fullDate属性(用来方便直接获取字符串形式的完整日期) +3. 日历新增confirmFullDate属性,用来指定在弹窗模式下的日期点击确认按钮时是否需要选择完整日期 +## 1.4.9(2024-05-08) +更新域名 +## 1.4.8(2024-04-22) +修复日历内外高度不一致的问题 +## 1.4.7(2024-04-16) +增加 operationPosition 属性 用来控制弹窗日历取消和确认按钮的显示位置 +## 1.4.6(2024-04-16) +新增属性 actBadgeColor, 当通过 `selected` 属性设置某个日期 `badgeColor`后,如果该日期被选择且主题色与 `badgeColor` 一致时,徽标会显示本颜色 +## 1.4.5(2024-04-15) +1. 新增reset方法来重置日历数据 +2. 新增插槽-operation 用来自定义弹窗日历确认和取消按钮 +3. selected 属性新增 badgeColor 用来指定 badge 颜色 +4. close 事件改为弹窗日历点击mask关闭时触发,新增cancel事件,弹窗日历点击取消时触发。 +## 1.4.4(2024-01-19) +修复vue2初始化时使用同一引用类型造成的bug +## 1.4.3(2024-01-17) +优化切换折叠状态时的记录方式 +## 1.4.2(2024-01-12) +优化 monthShowCurrentMonth 属性, 如果仅显示当月直接不展示该元素。 +## 1.4.1(2024-01-12) +优化 monthShowCurrentMonth 属性, 如果仅显示当月直接不展示该元素。 +## 1.4.0(2024-01-11) +修复type="week"时找不到 +## 1.3.9(2024-01-10) +优化: 将日历日期宽度固定改为跟随父级来决定宽度,避免出现父元素宽度变化带来的对不齐 +## 1.3.8(2024-01-04) +1. 增加节日 +2. 日历增加自定义高度 +3. vue页面日历折叠时增加动效 +4. 增加头部插槽 +5. 仅显示当月时自动扩大间距,不会再出现下面一排空白的尴尬情况了 +## 1.3.7(2023-12-19) +修复回到今日时没有正确记录折叠日期 +修复selected变化时无法正常更新打点信息 +## 1.3.6(2023-12-13) +修复单选模式下选中时展示的错误的weeks +## 1.3.5(2023-12-13) +修复动态修改date以及其他会触发更新init的函数, swiper不对及只会更新一个下一个数据的bug +## 1.3.4(2023-12-08) +修复selectd没有启用深度监听,导致直接添加数组带来的异常 +## 1.3.3(2023-11-23) +1. 修复weeks错误类型提示 +2. 修复calendarChange返回month类型不对 +## 1.3.2(2023-11-22) +修复将今日日期打点禁用后造成的bug +## 1.3.1(2023-11-21) +1. 修复wu-icon依赖缺失 +2. 新增rangeHaveDisableTruncation属性, 用来指定范围选择遇到打点禁用日期是否进行截断 +## 1.3.0(2023-11-19) +1. 日历新增类型(周、月日历) +2. 日历新增折叠功能 +3. 日历新增以周几开始的属性(周日、周一) +## 1.2.9(2023-11-08) +1. 修复mode变化时,不会正确重置的问题 +2. 优化月份大文字显示方式 +## 1.2.8(2023-10-22) +新增maskClick用来控制是否点击遮罩层关闭 +新增disabledChoice用来控制是否禁止点击日历 +## 1.2.7(2023-09-22) +修复传date值情况下不会默认选中的bug +## 1.2.6(2023-09-22) +修改useToday描述 +## 1.2.5(2023-09-22) +新增useToday属性用来指定是否使用今天作为默认时间 +## 1.2.4(2023-09-21) +修复插入模式下顶部会显示弹窗关闭的内容 +## 1.2.3(2023-09-20) +修复恢复默认数据错误的bug +## 1.2.2(2023-09-19) +新增rangeSameDay属性用来指定选日期范围选择时起始日期是否可以为同一天 +## 1.2.1(2023-09-18) +1.修复wu-calendar回到今日错误 +2.优化wu-calendar picker日期与当前日历日期同步 +3.wu-calendar新增mode属性,用来控制单日期、多日期、日期选择范围模式 +4.优化wu-calendar date属性来更好的指定多日期、范围日期的默认值 +## 1.2.0(2023-09-17) +修复date变化时未成功重置 +## 1.1.9(2023-09-17) +1. 新增mode属性用来指定日期选择模式 +2. 增加多选 +3. 增加范围选择模式、多选模式默认值 +## 1.1.8(2023-09-12) +修复回到今日错误 +新增日历picker日期与日历同步 +## 1.1.7(2023-09-11) +自定义事件声明 +## 1.1.6(2023-09-09) +增加 `rangeEndRepick` 属性,用来指定选择完成后点击选择范围内的日期是否可以重选结束日期 +## 1.1.5(2023-09-09) +修复每月仅显示当月数据时上方星期错乱的问题 +## 1.1.4(2023-09-05) +1. 优化动态计算算法 +2. 优化弹窗模式打开缓慢的问题 +3. 优化Color方法 +## 1.1.3(2023-09-03) +新增插件预览图片 +## 1.1.2(2023-09-02) +1. 新增monthShowCurrentMonth 用来设置是否每月仅展示当月数据 +2. 修复动态加载时下一月数据更新错误问题 +3. 修复confirm和change事件选中的列表中有被禁止的日期的问题 +## 1.1.1(2023-08-31) +修复在插入模式中无法滑动的bug +## 1.1.0(2023-08-29) +修复回到今日bug(来自群里464与A毛毛大佬的测试) +## 1.0.9(2023-08-29) +修复依赖缺失 +## 1.0.8(2023-08-22) +修复v2初始化时使用不存在的属性导致不可使用的bug(来自wu-ui群内攸宁大佬的反馈) +## 1.0.7(2023-08-21) +阻止默认滑动事件执行 +## 1.0.6(2023-08-21) +修复支付宝高度消失的问题 +## 1.0.5(2023-08-21) +修改说明 +## 1.0.4(2023-08-20) +去除误加打印 +## 1.0.3(2023-08-20) +1. 修复初始化时下个月份日期计算不对的问题 +2. 增加打点禁用、设置打点徽标位置 +## 1.0.2(2023-08-20) +更新展示截图 +## 1.0.1(2023-08-20) +修改展示截图及说明 +## 1.0.0(2023-08-20) +动态滑动计算的日历插件,还可以设置滑动切换模式、自定义主题颜色、自定义文案、农历显示等功能,可以让您纵享丝滑的使用日历。 diff --git a/src/uni_modules/wu-calendar/components/i18n/en.json b/src/uni_modules/wu-calendar/components/i18n/en.json new file mode 100644 index 0000000..00b62e2 --- /dev/null +++ b/src/uni_modules/wu-calendar/components/i18n/en.json @@ -0,0 +1,14 @@ +{ + "wu-calender.ok": "ok", + "wu-calender.cancel": "cancel", + "wu-calender.year": "year", + "wu-calender.month": "month", + "wu-calender.today": "today", + "wu-calender.MON": "MON", + "wu-calender.TUE": "TUE", + "wu-calender.WED": "WED", + "wu-calender.THU": "THU", + "wu-calender.FRI": "FRI", + "wu-calender.SAT": "SAT", + "wu-calender.SUN": "SUN" +} diff --git a/src/uni_modules/wu-calendar/components/i18n/index.js b/src/uni_modules/wu-calendar/components/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/src/uni_modules/wu-calendar/components/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/src/uni_modules/wu-calendar/components/i18n/zh-Hans.json b/src/uni_modules/wu-calendar/components/i18n/zh-Hans.json new file mode 100644 index 0000000..1cfcb2d --- /dev/null +++ b/src/uni_modules/wu-calendar/components/i18n/zh-Hans.json @@ -0,0 +1,14 @@ +{ + "wu-calender.ok": "确定", + "wu-calender.cancel": "取消", + "wu-calender.year": "年", + "wu-calender.month": "月", + "wu-calender.today": "今日", + "wu-calender.SUN": "日", + "wu-calender.MON": "一", + "wu-calender.TUE": "二", + "wu-calender.WED": "三", + "wu-calender.THU": "四", + "wu-calender.FRI": "五", + "wu-calender.SAT": "六" +} diff --git a/src/uni_modules/wu-calendar/components/i18n/zh-Hant.json b/src/uni_modules/wu-calendar/components/i18n/zh-Hant.json new file mode 100644 index 0000000..5ac1476 --- /dev/null +++ b/src/uni_modules/wu-calendar/components/i18n/zh-Hant.json @@ -0,0 +1,14 @@ +{ + "wu-calender.ok": "確定", + "wu-calender.cancel": "取消", + "wu-calender.year": "年", + "wu-calender.month": "月", + "wu-calender.today": "今日", + "wu-calender.SUN": "日", + "wu-calender.MON": "一", + "wu-calender.TUE": "二", + "wu-calender.WED": "三", + "wu-calender.THU": "四", + "wu-calender.FRI": "五", + "wu-calender.SAT": "六" +} diff --git a/src/uni_modules/wu-calendar/components/wu-calendar-block/props.js b/src/uni_modules/wu-calendar/components/wu-calendar-block/props.js new file mode 100644 index 0000000..355ef0a --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar-block/props.js @@ -0,0 +1,73 @@ +export default { + props: { + showMonth: { + type: Boolean, + default: false + }, + // 折叠状态 + FoldStatus: { + type: String, + default: null + }, + month: { + type: [Number, String], + default: null + }, + color: { + type: String, + default: '#3c9cff' + }, + startText: { + type: String, + default: '开始' + }, + endText: { + type: String, + default: '结束' + }, + weeks: { + type: [Object, Array], + default: ()=> { + return [] + } + }, + calendar: { + type: Object, + default: () => { + return {} + } + }, + selected: { + type: Array, + default: () => { + return [] + } + }, + lunar: { + type: Boolean, + default: false + }, + itemHeight: { + type: Number, + default: 64 + }, + monthShowCurrentMonth: { + type: Boolean, + default: false + }, + actBadgeColor: { + type: String, + default: '#fff' + }, + // 默认边距 + defaultMargin: { + type: Number, + default: 8 + }, + // 是否显示今日默认样式(默认为true) + todayDefaultStyle: { + type: Boolean, + default: true + }, + } +} \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar-block/wu-calendar-block.vue b/src/uni_modules/wu-calendar/components/wu-calendar-block/wu-calendar-block.vue new file mode 100644 index 0000000..fd8e4b9 --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar-block/wu-calendar-block.vue @@ -0,0 +1,111 @@ + ++ ++ + +{{ item }} ++ + + + + + \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar-item/props.js b/src/uni_modules/wu-calendar/components/wu-calendar-item/props.js new file mode 100644 index 0000000..d66be3b --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar-item/props.js @@ -0,0 +1,55 @@ +export default { + props: { + color: { + type: String, + default: '#3c9cff' + }, + startText: { + type: String, + default: '开始' + }, + endText: { + type: String, + default: '结束' + }, + weeks: { + type: Object, + default () { + return {} + } + }, + calendar: { + type: Object, + default: () => { + return {} + } + }, + selected: { + type: Array, + default: () => { + return [] + } + }, + lunar: { + type: Boolean, + default: false + }, + itemHeight: { + type: Number, + default: 64 + }, + actBadgeColor: { + type: String, + default: '#fff', + }, + weekItemStyle: { + type: Object, + default: {} + }, + // 是否显示今日默认样式(默认为true) + todayDefaultStyle: { + type: Boolean, + default: true + }, + } +} \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar-item/wu-calendar-item.vue b/src/uni_modules/wu-calendar/components/wu-calendar-item/wu-calendar-item.vue new file mode 100644 index 0000000..ec0868b --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar-item/wu-calendar-item.vue @@ -0,0 +1,252 @@ + ++ + +{{month}} ++ + ++ + + + + + + + + \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar/calendar.js b/src/uni_modules/wu-calendar/components/wu-calendar/calendar.js new file mode 100644 index 0000000..2761a6d --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar/calendar.js @@ -0,0 +1,664 @@ +/** + * @1900-2100区间内的公历、农历互转 + * @charset UTF-8 + * @github https://github.com/jjonline/calendar.js + * @Author Jea杨(JJonline@JJonline.Cn) + * @Time 2014-7-21 + * @Time 2016-8-13 Fixed 2033hex、Attribution Annals + * @Time 2016-9-25 Fixed lunar LeapMonth Param Bug + * @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year + * @Version 1.0.3 + * @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] + * @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] + */ +/* eslint-disable */ +var calendar = { + + /** + * 农历1900-2100的润大小信息表 + * @Array Of Property + * @return Hex + */ + lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, + 0x055d2, // 1900-1909 + 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919 + 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929 + 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939 + 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949 + 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959 + 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969 + 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979 + 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989 + 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999 + 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009 + 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019 + 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 + 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039 + 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049 + /** Add By JJonline@JJonline.Cn**/ + 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059 + 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069 + 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079 + 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089 + 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099 + 0x0d520 + ], // 2100 + + /** + * 公历每个月份的天数普通表 + * @Array Of Property + * @return Number + */ + solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + + /** + * 天干地支之天干速查表 + * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] + * @return Cn string + */ + Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'], + + /** + * 天干地支之地支速查表 + * @Array Of Property + * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] + * @return Cn string + */ + Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', + '\u620c', '\u4ea5' + ], + + /** + * 天干地支之地支速查表<=>生肖 + * @Array Of Property + * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] + * @return Cn string + */ + Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', + '\u72d7', '\u732a' + ], + + /** + * 24节气速查表 + * @Array Of Property + * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] + * @return Cn string + */ + solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', + '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', + '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', + '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3' + ], + + /** + * 1900-2100各年的24节气日期速查表 + * @Array Of Property + * @return 0x string For splice + */ + sTermInfo: [ + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', + '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', + 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', + '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', + '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', + '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', + '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', + '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', + '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', + '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', + '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', + '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722' + ], + + festivals: { + '1-1': '元旦', + '2-14': '情人节', + '3-8': '妇女节', + '3-12': '植树节', + '4-1': '愚人节', + '5-1': '劳动节', + '5-4': '青年节', + '5-12': '护士节', + '6-1': '儿童节', + '8-1': '建军节', + '9-10': '教师节', + '10-1': '国庆', + '11-1': '万圣节', + '12-24': '圣诞节', + '正月初一': '春节', + '二月初二': '龙抬头', + '五月初五': '端午节', + '七月初七': '七夕节', + '七月十五': '中元节', + '八月十五': '中秋节', + '九月初九': '重阳节', + '腊月初八': '腊八节', + '腊月廿三': '小年', + '腊月三十': '除夕', + }, + + /** + * 数字转中文速查表 + * @Array Of Property + * @trans ['日','一','二','三','四','五','六','七','八','九','十'] + * @return Cn string + */ + nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', + '\u5341' + ], + + /** + * 日期转农历称呼速查表 + * @Array Of Property + * @trans ['初','十','廿','卅'] + * @return Cn string + */ + nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'], + + /** + * 月份转农历称呼速查表 + * @Array Of Property + * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] + * @return Cn string + */ + nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', + '\u51ac', '\u814a' + ], + + /** + * 返回农历y年一整年的总天数 + * @param lunar Year + * @return Number + * @eg:var count = calendar.lYearDays(1987) ;//count=387 + */ + lYearDays: function(y) { + var i; + var sum = 348 + for (i = 0x8000; i > 0x8; i >>= 1) { + sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 + } + return (sum + this.leapDays(y)) + }, + + /** + * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 + * @param lunar Year + * @return Number (0-12) + * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 + */ + leapMonth: function(y) { // 闰字编码 \u95f0 + return (this.lunarInfo[y - 1900] & 0xf) + }, + + /** + * 返回农历y年闰月的天数 若该年没有闰月则返回0 + * @param lunar Year + * @return Number (0、29、30) + * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 + */ + leapDays: function(y) { + if (this.leapMonth(y)) { + return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29) + } + return (0) + }, + + /** + * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 + * @param lunar Year + * @return Number (-1、29、30) + * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 + */ + monthDays: function(y, m) { + if (m > 12 || m < 1) { + return -1 + } // 月份参数从1至12,参数错误返回-1 + return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29) + }, + + /** + * 返回公历(!)y年m月的天数 + * @param solar Year + * @return Number (-1、28、29、30、31) + * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 + */ + solarDays: function(y, m) { + if (m > 12 || m < 1) { + return -1 + } // 若参数错误 返回-1 + var ms = m - 1 + if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29 + return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28) + } else { + return (this.solarMonth[ms]) + } + }, + + /** + * 农历年份转换为干支纪年 + * @param lYear 农历年的年份数 + * @return Cn string + */ + toGanZhiYear: function(lYear) { + var ganKey = (lYear - 3) % 10 + var zhiKey = (lYear - 3) % 12 + if (ganKey == 0) ganKey = 10 // 如果余数为0则为最后一个天干 + if (zhiKey == 0) zhiKey = 12 // 如果余数为0则为最后一个地支 + return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1] + }, + + /** + * 公历月、日判断所属星座 + * @param cMonth [description] + * @param cDay [description] + * @return Cn string + */ + toAstro: function(cMonth, cDay) { + var s = + '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf' + var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22] + return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7' // 座 + }, + + /** + * 传入offset偏移量返回干支 + * @param offset 相对甲子的偏移量 + * @return Cn string + */ + toGanZhi: function(offset) { + return this.Gan[offset % 10] + this.Zhi[offset % 12] + }, + + /** + * 传入公历(!)y年获得该年第n个节气的公历日期 + * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 + * @return day Number + * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 + */ + getTerm: function(y, n) { + if (y < 1900 || y > 2100) { + return -1 + } + if (n < 1 || n > 24) { + return -1 + } + var _table = this.sTermInfo[y - 1900] + var _info = [ + parseInt('0x' + _table.substr(0, 5)).toString(), + parseInt('0x' + _table.substr(5, 5)).toString(), + parseInt('0x' + _table.substr(10, 5)).toString(), + parseInt('0x' + _table.substr(15, 5)).toString(), + parseInt('0x' + _table.substr(20, 5)).toString(), + parseInt('0x' + _table.substr(25, 5)).toString() + ] + var _calday = [ + _info[0].substr(0, 1), + _info[0].substr(1, 2), + _info[0].substr(3, 1), + _info[0].substr(4, 2), + + _info[1].substr(0, 1), + _info[1].substr(1, 2), + _info[1].substr(3, 1), + _info[1].substr(4, 2), + + _info[2].substr(0, 1), + _info[2].substr(1, 2), + _info[2].substr(3, 1), + _info[2].substr(4, 2), + + _info[3].substr(0, 1), + _info[3].substr(1, 2), + _info[3].substr(3, 1), + _info[3].substr(4, 2), + + _info[4].substr(0, 1), + _info[4].substr(1, 2), + _info[4].substr(3, 1), + _info[4].substr(4, 2), + + _info[5].substr(0, 1), + _info[5].substr(1, 2), + _info[5].substr(3, 1), + _info[5].substr(4, 2) + ] + return parseInt(_calday[n - 1]) + }, + + /** + * 传入农历数字月份返回汉语通俗表示法 + * @param lunar month + * @return Cn string + * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' + */ + toChinaMonth: function(m) { // 月 => \u6708 + if (m > 12 || m < 1) { + return -1 + } // 若参数错误 返回-1 + var s = this.nStr3[m - 1] + s += '\u6708' // 加上月字 + return s + }, + + /** + * 传入农历日期数字返回汉字表示法 + * @param lunar day + * @return Cn string + * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' + */ + toChinaDay: function(d) { // 日 => \u65e5 + var s + switch (d) { + case 10: + s = '\u521d\u5341'; + break + case 20: + s = '\u4e8c\u5341'; + break + break + case 30: + s = '\u4e09\u5341'; + break + break + default: + s = this.nStr2[Math.floor(d / 10)] + s += this.nStr1[d % 10] + } + return (s) + }, + + /** + * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” + * @param y year + * @return Cn string + * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' + */ + getAnimal: function(y) { + return this.Animals[(y - 4) % 12] + }, + + /** + * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON + * @param y solar year + * @param m solar month + * @param d solar day + * @return JSON object + * @eg:console.log(calendar.solar2lunar(1987,11,01)); + */ + solar2lunar: function(y, m, d) { // 参数区间1900.1.31~2100.12.31 + // 年份限定、上限 + if (y < 1900 || y > 2100) { + return -1 // undefined转换为数字变为NaN + } + // 公历传参最下限 + if (y == 1900 && m == 1 && d < 31) { + return -1 + } + // 未传参 获得当天 + if (!y) { + var objDate = new Date() + } else { + var objDate = new Date(y, parseInt(m) - 1, d) + } + var i; + var leap = 0; + var temp = 0 + // 修正ymd参数 + var y = objDate.getFullYear() + var m = objDate.getMonth() + 1 + var d = objDate.getDate() + var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, + 31)) / 86400000 + for (i = 1900; i < 2101 && offset > 0; i++) { + temp = this.lYearDays(i) + offset -= temp + } + if (offset < 0) { + offset += temp; + i-- + } + + // 是否今天 + var isTodayObj = new Date() + var isToday = false + if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) { + isToday = true + } + // 星期几 + var nWeek = objDate.getDay() + var cWeek = this.nStr1[nWeek] + // 数字表示周几顺应天朝周一开始的惯例 + if (nWeek == 0) { + nWeek = 7 + } + // 农历年 + var year = i + var leap = this.leapMonth(i) // 闰哪个月 + var isLeap = false + + // 效验闰月 + for (i = 1; i < 13 && offset > 0; i++) { + // 闰月 + if (leap > 0 && i == (leap + 1) && isLeap == false) { + --i + isLeap = true; + temp = this.leapDays(year) // 计算农历闰月天数 + } else { + temp = this.monthDays(year, i) // 计算农历普通月天数 + } + // 解除闰月 + if (isLeap == true && i == (leap + 1)) { + isLeap = false + } + offset -= temp + } + // 闰月导致数组下标重叠取反 + if (offset == 0 && leap > 0 && i == leap + 1) { + if (isLeap) { + isLeap = false + } else { + isLeap = true; + --i + } + } + if (offset < 0) { + offset += temp; + --i + } + // 农历月 + var month = i + // 农历日 + var day = offset + 1 + // 天干地支处理 + var sm = m - 1 + var gzY = this.toGanZhiYear(year) + + // 当月的两个节气 + // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` + var firstNode = this.getTerm(y, (m * 2 - 1)) // 返回当月「节」为几日开始 + var secondNode = this.getTerm(y, (m * 2)) // 返回当月「节」为几日开始 + + // 依据12节气修正干支月 + var gzM = this.toGanZhi((y - 1900) * 12 + m + 11) + if (d >= firstNode) { + gzM = this.toGanZhi((y - 1900) * 12 + m + 12) + } + + // 传入的日期的节气与否 + var isTerm = false + var Term = null + if (firstNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 2] + } + if (secondNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 1] + } + + // 计算农历日期 + const IMonthCn = (isLeap ? '\u95f0' : '') + this.toChinaMonth(month) + // 农历日期的汉字表述法 + let IDayCn = this.toChinaDay(day) + + // 节日 + let festival = ''; + // 农历的月日汉字表述 + let lMDcn = IMonthCn + IDayCn; + // 月份日期 + let MD = m + '-' + d; + if (this.festivals.hasOwnProperty(lMDcn)) { + festival = this.festivals[lMDcn] + } else if(this.festivals.hasOwnProperty(MD)) { + festival = this.festivals[MD] + } + + // 日柱 当月一日与 1900/1/1 相差天数 + var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10 + var gzD = this.toGanZhi(dayCyclical + d - 1) + // 该日期所属的星座 + var astro = this.toAstro(m, d) + + return { + 'lYear': year, + 'lMonth': month, + 'lDay': day, + 'Animal': this.getAnimal(year), + 'IMonthCn': IMonthCn, + 'IDayCn': IDayCn, + 'cYear': y, + 'cMonth': m, + 'cDay': d, + 'gzYear': gzY, + 'gzMonth': gzM, + 'gzDay': gzD, + 'isToday': isToday, + 'isLeap': isLeap, + 'nWeek': nWeek, + 'ncWeek': '\u661f\u671f' + cWeek, + 'isTerm': isTerm, + 'Term': Term, + 'astro': astro, + 'festival': festival + } + }, + + /** + * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON + * @param y lunar year + * @param m lunar month + * @param d lunar day + * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] + * @return JSON object + * @eg:console.log(calendar.lunar2solar(1987,9,10)); + */ + lunar2solar: function(y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1 + var isLeapMonth = !!isLeapMonth + var leapOffset = 0 + var leapMonth = this.leapMonth(y) + var leapDay = this.leapDays(y) + if (isLeapMonth && (leapMonth != m)) { + return -1 + } // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 + if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { + return -1 + } // 超出了最大极限值 + var day = this.monthDays(y, m) + var _day = day + // bugFix 2016-9-25 + // if month is leap, _day use leapDays method + if (isLeapMonth) { + _day = this.leapDays(y, m) + } + if (y < 1900 || y > 2100 || d > _day) { + return -1 + } // 参数合法性效验 + + // 计算农历的时间差 + var offset = 0 + for (var i = 1900; i < y; i++) { + offset += this.lYearDays(i) + } + var leap = 0; + var isAdd = false + for (var i = 1; i < m; i++) { + leap = this.leapMonth(y) + if (!isAdd) { // 处理闰月 + if (leap <= i && leap > 0) { + offset += this.leapDays(y); + isAdd = true + } + } + offset += this.monthDays(y, i) + } + // 转换闰月农历 需补充该年闰月的前一个月的时差 + if (isLeapMonth) { + offset += day + } + // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) + var stmap = Date.UTC(1900, 1, 30, 0, 0, 0) + var calObj = new Date((offset + d - 31) * 86400000 + stmap) + var cY = calObj.getUTCFullYear() + var cM = calObj.getUTCMonth() + 1 + var cD = calObj.getUTCDate() + + return this.solar2lunar(cY, cM, cD) + } +} + +export default calendar \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar/props.js b/src/uni_modules/wu-calendar/components/wu-calendar/props.js new file mode 100644 index 0000000..b412251 --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar/props.js @@ -0,0 +1,166 @@ +export default { + props: { + // 自定义当前时间 + date: { + type: [String, Array], + default: '' + }, + // 日历类型(默认为month) + type: { + type: String, + default: 'month', + validator(value) { + return ['month', 'week'].includes(value) + } + }, + // 日期选择模式 + mode: { + type: String, + default: 'single' + }, + // 是否使用默认日期(今天,默认为true) + useToday: { + type: Boolean, + default: true + }, + // 是否显示今日默认样式(默认为true) + todayDefaultStyle: { + type: Boolean, + default: true + }, + // 是否使用折叠功能 + fold: { + type: Boolean, + default: null + }, + // 主题色 + color: { + type: String, + default: '#3c9cff' + }, + // 日历中每一项日期的高度(默认70),单位px + itemHeight: { + type: Number, + default: 70 + }, + // 取消文字的颜色 + cancelColor: { + type: String, + default: '#333' + }, + // 确定文字的颜色 + confirmColor: { + type: String, + default: '#333' + }, + // mode=range时,第一个日期底部的提示文字 + startText: { + type: String, + default: '开始' + }, + // mode=range时,最后一个日期底部的提示文字 + endText: { + type: String, + default: '结束' + }, + // 日历以周几开始 + startWeek: { + type: String, + default: 'sun', + validator(value) { + return ['sun', 'mon'].includes(value) + } + }, + // 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] + selected: { + type: Array, + default () { + return [] + } + }, + // 是否显示农历 + lunar: { + type: Boolean, + default: false + }, + // 日期选择范围-开始日期 + startDate: { + type: String, + default: '' + }, + // 日期选择范围-结束日期 + endDate: { + type: String, + default: '' + }, + // 允许日期选择范围内重选结束日期 + rangeEndRepick: { + type: Boolean, + default: false + }, + // 允许日期选择范围起始日期为同一天 + rangeSameDay: { + type: Boolean, + default: false + }, + // 允许日期选择范围内遇到打点禁用日期进行截断 + rangeHaveDisableTruncation: { + type: Boolean, + default: false + }, + // 每月仅显示当月日期 + monthShowCurrentMonth: { + type: Boolean, + default: false + }, + // 插入模式,可选值,ture:插入模式;false:弹窗模式; 默认为插入模式 + insert: { + type: Boolean, + default: true + }, + // 滑动切换模式,可选值 horizontal: 横向 vertical:纵向 none: 不使用滑动切换 + slideSwitchMode: { + type: String, + default: 'horizontal' + }, + // 是否显示月份为背景 + showMonth: { + type: Boolean, + default: true + }, + // 弹窗模式是否清空上次选择内容 + clearDate: { + type: Boolean, + default: true + }, + // 是否点击遮罩层关闭 + maskClick: { + type: Boolean, + default: false + }, + // 是否禁止点击日历 + disabledChoice: { + type: Boolean, + default: false + }, + // 弹窗日历取消和确认按钮的显示位置 + operationPosition: { + type: String, + default: 'top', + validator(value) { + return ['top', 'bottom'].includes(value) + } + }, + // 弹窗日历点击确认时是否需要选择完整日期 + confirmFullDate: { + type: Boolean, + default: false + }, + // 当通过 `selected` 属性设置某个日期 `badgeColor`后,如果该日期被选择且主题色与 `badgeColor` 一致时,徽标会显示本颜色 + actBadgeColor: { + type: String, + default: '#fff' + }, + ...uni.$w?.props?.calendar + } +} \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar/util.js b/src/uni_modules/wu-calendar/components/wu-calendar/util.js new file mode 100644 index 0000000..03b351d --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar/util.js @@ -0,0 +1,552 @@ +import calendar from './calendar.js'; +import CALENDAR from './calendar.js' + +class Calendar { + constructor({ + date, + selected, + startDate, + endDate, + mode, + monthShowCurrentMonth, + rangeEndRepick, + rangeSameDay, + rangeHaveDisableTruncation, + type, + foldStatus, + startWeek + } = {}) { + // 当前日期 + this.date = this.getDate(new Date()) // 当前初入日期 + // 打点信息 + this.selected = selected || []; + // 范围开始 + this.startDate = startDate + // 范围结束 + this.endDate = endDate + // 日历以周几开始 + this.startWeek = startWeek + // 日期选择类型 + this.mode = mode + // 日历类型 + this.type = type + // 折叠状态 + this.foldStatus = foldStatus + // 允许范围内重选结束日期 + this.rangeEndRepick = rangeEndRepick + // 允许日期选择范围起始日期为同一天 + this.rangeSameDay = rangeSameDay + // 日期选择范围内遇到打点禁用日期是否截断 + this.rangeHaveDisableTruncation = rangeHaveDisableTruncation + // 每月是否仅显示当月的数据 + this.monthShowCurrentMonth = monthShowCurrentMonth + // 清理多选状态 + this.cleanRange() + // 每周日期 + this.weeks = {} + // 多个日期 + this.multiple = []; + } + /** + * 设置日期 + * @param {Object} date + */ + setDate(date) { + this.selectDate = this.getDate(date) + this._getWeek(this.selectDate.fullDate) + } + + /** + * 清除范围 + */ + cleanRange() { + this.rangeStatus = { + before: '', + after: '', + data: [] + } + } + + /** + * 清除多选 + */ + cleanMultiple() { + this.multiple = [] + } + + /** + * 重置开始日期 + */ + resetSatrtDate(startDate) { + // 范围开始 + this.startDate = startDate + } + + /** + * 重置结束日期 + */ + resetEndDate(endDate) { + // 范围结束 + this.endDate = endDate + } + + /** + * 重置是否每月仅显示当月数据 + * @param {Boolean} show 是否仅显示当月数据 + */ + resetMonthShowCurrentMonth(show) { + this.monthShowCurrentMonth = show + } + + // 重置允许范围内重选结束日期 + resetRangeEndRepick(val) { + this.rangeEndRepick = val + } + + // 重置允许日期范围选择起始日期为同一天 + resetRangeSameDay(val) { + this.rangeSameDay = val + } + + // 重置范围内遇到打点禁用日期是否截断 + resetRangeHaveDisableTruncation(val) { + this.rangeHaveDisableTruncation = val + } + + // 重置日期选择模式 + resetMode(val) { + this.mode = val + } + + // 重置折叠状态 + resetFoldStatus(val) { + this.foldStatus = val + } + + // 重置日历以周几开始 + resetStartWeek(val) { + this.startWeek = val + } + + /** + * 创建本月某一天的信息 + */ + _createCurrentDay(nowDate, full, date) { + // 是否今天 + let isDay = this.date.fullDate === nowDate + // 获取打点信息 + let info = this.selected && this.selected.find((item) => { + if (this.dateEqual(nowDate, item.date)) { + return item + } + }) + + // 日期禁用 + let disableBefore = true + let disableAfter = true + if (this.startDate) { + disableBefore = this.dateCompare(this.startDate, nowDate) + } + + if (this.endDate) { + disableAfter = this.dateCompare(nowDate, this.endDate) + } + + // 范围选择模式 + let ranges = this.rangeStatus.data + let checked = false + if (this.mode == 'range') { + checked = ranges.findIndex((item) => this.dateEqual(item, nowDate)) !== -1 ? true : false; + } + + // 多日期选择模式 + let multiples = this.multiple + let multiplesChecked = false + if (this.mode == 'multiple') { + multiplesChecked = multiples.findIndex(item => this.dateEqual(item, nowDate)) !== -1; + } + + let data = { + fullDate: nowDate, + year: full.year, + date, + type: this.type, + mode: this.mode, + multiples: this.mode == 'multiple' ? multiplesChecked : false, + rangeMultiple: this.mode == 'range' ? checked : false, + beforeRange: this.dateEqual(this.rangeStatus.before, nowDate), + afterRange: this.dateEqual(this.rangeStatus.after, nowDate), + month: full.month, + lunar: this.getlunar(full.year, full.month, date), + disable: !(disableBefore && disableAfter), + isDay + } + + + if (info) { + data.extraInfo = info; + data.disable = info.disable || false; + } + + return data + } + + /** + * 获取任意时间 + */ + getDate(date, AddDayCount = 0, str = 'day') { + if (!date) { + date = new Date() + } + if (typeof date !== 'object') { + date = date.replace(/-/g, '/') + } + const dd = new Date(date) + switch (str) { + case 'day': + dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期 + break + case 'month': + if (dd.getDate() === 31 && AddDayCount > 0) { + dd.setDate(dd.getDate() + AddDayCount) + } else { + const preMonth = dd.getMonth() + dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期 + const nextMonth = dd.getMonth() + // 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题 + if (AddDayCount < 0 && preMonth !== 0 && nextMonth - preMonth > AddDayCount) { + dd.setMonth(nextMonth + (nextMonth - preMonth + AddDayCount)) + } + // 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题 + if (AddDayCount > 0 && nextMonth - preMonth > AddDayCount) { + dd.setMonth(nextMonth - (nextMonth - preMonth - AddDayCount)) + } + } + break + case 'week': + dd.setDate(dd.getDate() + (AddDayCount * 7)) + break; + case 'year': + dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期 + break + } + const y = dd.getFullYear() + const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0 + const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0 + return { + fullDate: y + '-' + m + '-' + d, + year: y, + month: m, + date: d, + day: dd.getDay() + } + } + + + /** + * 获取上月剩余天数 + */ + _getLastMonthDays(firstDay, full) { + let dateArr = [] + for (let i = firstDay; i > 0; i--) { + const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate() + dateArr.push({ + date: beforeDate, + month: full.month - 1, + year: full.year, + lunar: this.getlunar(full.year, full.month - 1, beforeDate), + disable: true + }) + } + return dateArr + } + /** + * 获取本月天数 + */ + _currentMonthDays(dateData, full) { + let dateArr = [] + let fullDate = this.date.fullDate + for (let i = 1; i <= dateData; i++) { + let nowDate = full.year + '-' + (full.month < 10 ? + full.month : full.month) + '-' + (i < 10 ? + '0' + i : i) + dateArr.push(this._createCurrentDay(nowDate, full, i)) + } + return dateArr + } + /** + * 获取下月天数 + */ + _getNextMonthDays(surplus, full) { + let dateArr = [] + for (let i = 1; i < surplus + 1; i++) { + dateArr.push({ + date: i, + month: Number(full.month) + 1, + lunar: this.getlunar(full.year, Number(full.month) + 1, i), + disable: true + }) + } + return dateArr + } + /** + * 获取任意日期的一周 + */ + _getWeekDays(dateData) { + let dateArr = []; + let oneDayTime = 1000 * 60 * 60 * 24 + let today = new Date(dateData); + // 获取这个日期是星期几 + let todayDay; + let startDate; + // 如果日历以周一开始 + if(this.startWeek == 'mon') { + todayDay = today.getDay() || 7; + startDate = new Date(today.getTime() - oneDayTime * (todayDay - 1)); + } else { + todayDay = today.getDay(); + startDate = new Date(today.getTime() - oneDayTime * todayDay); + } + + for (let i = 0; i < 7; i++) { + let temp = new Date(startDate.getTime() + i * oneDayTime) + let newDate = this.getDate(`${temp.getFullYear()}-${temp.getMonth() + 1}-${temp.getDate()}`) + dateArr.push(this._createCurrentDay(newDate.fullDate, newDate, Number(newDate.date))) + } + + return dateArr; + } + + /** + * 获取当前日期详情 + * @param {Object} date + */ + getInfo(date) { + if (!date) { + date = new Date() + } + const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate) + return dateInfo + } + + /** + * 比较时间大小 + */ + dateCompare(startDate, endDate) { + // 计算截止时间 + startDate = new Date(startDate.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + endDate = new Date(endDate.replace('-', '/').replace('-', '/')) + if (startDate <= endDate) { + return true + } else { + return false + } + } + + /** + * 比较时间是否相等 + */ + dateEqual(before = '', after = '') { + // 计算截止时间 + before = new Date(before.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + after = new Date(after.replace('-', '/').replace('-', '/')) + if (before.getTime() - after.getTime() === 0) { + return true + } else { + return false + } + } + + + /** + * 获取日期范围内所有日期 + * @param {Object} begin + * @param {Object} end + */ + getDateAll(begin, end) { + // 找出所有打点中已禁用的部分 不让其被添加在日期选择范围内 + let disableList = this.selected.filter(item => item.date && item.disable).map(item => item.date) + + var arr = [] + var ab = begin.split('-') + var ae = end.split('-') + var db = new Date() + db.setFullYear(ab[0], ab[1] - 1, ab[2]) + var de = new Date() + de.setFullYear(ae[0], ae[1] - 1, ae[2]) + var wuxDb = db.getTime() - 24 * 60 * 60 * 1000 + var wuxDe = de.getTime() - 24 * 60 * 60 * 1000 + for (var k = wuxDb; k <= wuxDe;) { + k = k + 24 * 60 * 60 * 1000 + let fullDate = this.getDate(new Date(parseInt(k))).fullDate + // 如果要在选择范围内截断日期 + if(this.rangeHaveDisableTruncation) { + // 如果不在打点禁止列表中 + if (disableList.includes(fullDate)) return arr; + arr.push(fullDate) + } else { + if (!disableList.includes(fullDate)) arr.push(fullDate); + } + } + return arr + } + /** + * 计算阴历日期显示 + */ + getlunar(year, month, date) { + return CALENDAR.solar2lunar(year, month, date) + } + /** + * 设置打点 + */ + setSelectInfo(data, value) { + this.selected = value + this._getWeek(data) + } + + /** + * 设置范围 + */ + setRange(fullDate) { + let { + before, + after + } = this.rangeStatus; + + // 非范围选择不再执行 + if (this.mode != 'range') return + + // 判断目前的日期 是否 比before日期小或者等于before日期 如果为true就要重置 + let reset = this.dateCompare(fullDate, before); + // 如果日期选择范围允许为同一天 且 目前是需要重置的 + if (this.rangeSameDay && before && reset) { + // 判断是否需要相等 如果 不相等 则 重置 如果相等 则不重置 + reset = !this.dateEqual(fullDate, before); + } + + if ((before && after || reset) && (!this.rangeEndRepick || (this.rangeEndRepick && this.rangeStatus.data + .indexOf(fullDate) == -1))) { + this.rangeStatus.before = fullDate; + this.rangeStatus.after = ''; + this.rangeStatus.data = []; + } else { + if (!before) { + this.rangeStatus.before = fullDate + } else { + if (this.dateCompare(this.rangeStatus.before, fullDate)) { + this.rangeStatus.data = this.getDateAll(this.rangeStatus.before, fullDate); + } else { + this.rangeStatus.data = this.getDateAll(fullDate, this.rangeStatus.before); + } + this.rangeStatus.after = this.rangeStatus.data[this.rangeStatus.data.length - 1] + } + } + this._getWeek(fullDate) + } + + /** + * 设置多选 + */ + setMultiple(fullDate) { + // 非多选不再执行 + if (this.mode != 'multiple') return + // 检查是否已经多选 + let index = this.multiple.findIndex((item) => { + if (this.dateEqual(fullDate, item)) { + return item + } + }); + if (index === -1) { + this.multiple.push(fullDate) + this.setDate(fullDate) + } else { + this.multiple = this.multiple.filter((item, i) => i != index) + } + this._getWeek(fullDate) + } + + /** + * 获取每周数据 + * @param {Object} dateData + */ + _getWeek(dateData, useWeeks = true) { + const { + year, + month + } = this.getDate(dateData) + + let weeks = {} + // 日历数据 + let canlender = []; + + if (this.foldStatus === 'open') { + // 默认以周末开始 + let firstDay = new Date(year, month - 1, 1).getDay(); + // 如果以周一开始 + if(this.startWeek === 'mon') { + firstDay = firstDay === 0 ? 6 : firstDay - 1; + } + let currentDay = new Date(year, month, 0).getDate() + // 日期数据 + let dates = { + lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天 + currentMonthDys: this._currentMonthDays(currentDay, this.getDate(dateData)), // 本月天数 + weeks: [] + } + // 下月开始几天 + const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length) + dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData)) + + // 如果仅显示当月 + if (this.monthShowCurrentMonth) { + // 日历数据 + canlender = canlender.concat( + dates.lastMonthDays.map(item => item = { + empty: true, + lunar: {}, + }), + dates.currentMonthDys, + dates.nextMonthDays.map(item => item = { + empty: true, + lunar: {}, + }), + ); + + } else { + // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天 + canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays) + } + + } else { + canlender = this._getWeekDays(dateData) + } + + for (let i = 0; i < canlender.length; i++) { + if (i % 7 === 0) { + weeks[parseInt(i / 7)] = new Array(7) + } + weeks[parseInt(i / 7)][i % 7] = canlender[i] || {}; + } + + if (useWeeks) { + this.canlender = canlender + this.weeks = weeks + } + + return weeks + } + + + //静态方法 + // static init(date) { + // if (!this.instance) { + // this.instance = new Calendar(date); + // } + // return this.instance; + // } +} + + +export default Calendar \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/components/wu-calendar/wu-calendar.vue b/src/uni_modules/wu-calendar/components/wu-calendar/wu-calendar.vue new file mode 100644 index 0000000..1316542 --- /dev/null +++ b/src/uni_modules/wu-calendar/components/wu-calendar/wu-calendar.vue @@ -0,0 +1,1069 @@ + ++ + +{{weeks.extraInfo.topInfo}} + ++ + {{weeks.date}} + +{{todayText}} + +{{dayText}} + +{{multipleText}} + +{{weeks.extraInfo.info}} ++ + + + + + \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/package.json b/src/uni_modules/wu-calendar/package.json new file mode 100644 index 0000000..bd01fd7 --- /dev/null +++ b/src/uni_modules/wu-calendar/package.json @@ -0,0 +1,91 @@ +{ + "id": "wu-calendar", + "displayName": "wu-calendar 最全日历,动态滑动切换、多滑动模式、多日历类型、多日期选择模式等,全端兼容,无论平台,一致体验。", + "version": "1.5.6", + "description": "唯一支持动态滑动计算的日历插件,多滑动切换模式(纵、横、不滑动)、多日历类型(周、月)、多日期选择模式(单选、多选、范围)、日历周几(周日、周一)、自定义主题、农历显示等,可以让您纵享丝滑的使用日历", + "keywords": [ + "wu-calendar", + "日历", + "多日历类型", + "动态滑动计算", + "wu-ui" +], + "repository": "", + "engines": { + "HBuilderX": "^3.5.5" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [ + "wu-ui-tools", + "wu-icon", + "wu-safe-bottom" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "n", + "快手": "n", + "飞书": "n", + "京东": "n" + }, + "快应用": { + "华为": "n", + "联盟": "n" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/wu-calendar/readme.md b/src/uni_modules/wu-calendar/readme.md new file mode 100644 index 0000000..c69121d --- /dev/null +++ b/src/uni_modules/wu-calendar/readme.md @@ -0,0 +1,16 @@ +## wu-calendar 最全日历 + +> **组件名:wu-calendar** + +目前插件市场上唯一可以动态滑动计算的日历插件,多滑动切换模式(纵、横向滑动,不滑动)、多日历类型(周、月日历)、多日历选择模式(日期单选、多选、范围选择)、多日历起始周几设置(周日、周一)、自定义主题颜色(副色自动生成)、自定义文案、农历显示等功能,可以让您纵享丝滑的使用日历。 + +## [查看文档](https://wuui.cn/zh-CN/components/calendar.html) + +## [更多组件, 请查看 `wu-ui` 组件库](https://ext.dcloud.net.cn/plugin?name=wu--ui) +(请勿下载插件zip) + + ++ + + ++ + ++ ++ +{{cancelText}} ++ +{{okText}} ++ ++ + + ++ ++ + +{{ (nowDate.year||'') + YearText + ( nowDate.month||'') + MonthText }} ++ {{todayText}} + + + ++ ++ + +{{ (nowDate.year||'') + YearText + ( nowDate.month||'') + MonthText }} ++ ++ {{todayText}} + ++ ++ + ++ +{{SUNText}} ++ +{{monText}} ++ +{{TUEText}} ++ +{{WEDText}} ++ +{{THUText}} ++ +{{FRIText}} ++ +{{SATText}} ++ +{{SUNText}} ++ + + + + + ++ ++ + ++ + + ++ + + + + ++ + + ++ ++ +{{cancelText}} ++ +{{okText}} ++ + + +**如使用过程中有任何问题,或者您对wu-ui有一些好的建议。
欢迎加入 [wu-ui 交流群](https://wuui.cn/zh-CN/components/qqFeedBack.html)** \ No newline at end of file diff --git a/src/uni_modules/wu-icon/changelog.md b/src/uni_modules/wu-icon/changelog.md new file mode 100644 index 0000000..8b940ba --- /dev/null +++ b/src/uni_modules/wu-icon/changelog.md @@ -0,0 +1,10 @@ +## 1.0.4(2024-05-08) +更新域名 +## 1.0.3(2023-08-08) +修复链接引入错误 +## 1.0.2(2023-08-07) +修复引入错误 +## 1.0.1(2023-08-07) +支持自定义(包括nvue)文字与图片图标 +## 1.0.0(2023-08-03) +基于字体的图标集,包含了大多数常见场景的图标,支持自定义,支持自定义图片图标等。可自定义颜色、大小。 diff --git a/src/uni_modules/wu-icon/components/wu-icon/icons.js b/src/uni_modules/wu-icon/components/wu-icon/icons.js new file mode 100644 index 0000000..1eb5e4f --- /dev/null +++ b/src/uni_modules/wu-icon/components/wu-icon/icons.js @@ -0,0 +1,159 @@ +export default { + 'wuicon-level': 'e68f', + 'wuicon-download': 'e670', + 'wuicon-search': 'e632', + 'wuicon-reload': 'e627', + 'wuicon-scan': 'e631', + 'wuicon-calendar': 'e65c', + 'wuicon-bag': 'e647', + 'wuicon-checkbox-mark': 'e659', + 'wuicon-attach': 'e640', + 'wuicon-wifi-off': 'e6cc', + + 'wuicon-woman': 'e626', + 'wuicon-man': 'e675', + 'wuicon-chat': 'e656', + 'wuicon-chat-fill': 'e63f', + 'wuicon-red-packet': 'e6c3', + 'wuicon-folder': 'e694', + 'wuicon-order': 'e695', + 'wuicon-arrow-up-fill': 'e636', + 'wuicon-arrow-down-fill': 'e638', + 'wuicon-backspace': 'e64d', + 'wuicon-photo': 'e60d', + 'wuicon-photo-fill': 'e6b4', + 'wuicon-lock': 'e69d', + 'wuicon-lock-fill': 'e6a6', + 'wuicon-lock-open': 'e68d', + 'wuicon-lock-opened-fill': 'e6a1', + 'wuicon-home': 'e67b', + 'wuicon-home-fill': 'e68e', + 'wuicon-star': 'e618', + 'wuicon-star-fill': 'e61e', + 'wuicon-share': 'e629', + 'wuicon-share-fill': 'e6bb', + 'wuicon-share-square': 'e6c4', + 'wuicon-volume': 'e605', + 'wuicon-volume-fill': 'e624', + 'wuicon-volume-off': 'e6bd', + 'wuicon-volume-off-fill': 'e6c8', + 'wuicon-trash': 'e623', + 'wuicon-trash-fill': 'e6ce', + 'wuicon-shopping-cart': 'e6cb', + 'wuicon-shopping-cart-fill': 'e630', + 'wuicon-question-circle': 'e622', + 'wuicon-question-circle-fill': 'e6bc', + 'wuicon-plus': 'e625', + 'wuicon-plus-circle': 'e603', + 'wuicon-plus-circle-fill': 'e611', + 'wuicon-tags': 'e621', + 'wuicon-tags-fill': 'e613', + 'wuicon-pause': 'e61c', + 'wuicon-pause-circle': 'e696', + 'wuicon-pause-circle-fill': 'e60c', + 'wuicon-play-circle': 'e6af', + 'wuicon-play-circle-fill': 'e62a', + 'wuicon-map': 'e665', + 'wuicon-map-fill': 'e6a8', + 'wuicon-phone': 'e6ba', + 'wuicon-phone-fill': 'e6ac', + 'wuicon-list': 'e690', + 'wuicon-list-dot': 'e6a9', + 'wuicon-info-circle': 'e69f', + 'wuicon-info-circle-fill': 'e6a7', + 'wuicon-minus': 'e614', + 'wuicon-minus-circle': 'e6a5', + 'wuicon-mic': 'e66d', + 'wuicon-mic-off': 'e691', + 'wuicon-grid': 'e68c', + 'wuicon-grid-fill': 'e698', + 'wuicon-eye': 'e664', + 'wuicon-eye-fill': 'e697', + 'wuicon-eye-off': 'e69c', + 'wuicon-eye-off-outline': 'e688', + 'wuicon-file-text': 'e687', + 'wuicon-file-text-fill': 'e67f', + 'wuicon-edit-pen': 'e65d', + 'wuicon-edit-pen-fill': 'e679', + 'wuicon-email': 'e673', + 'wuicon-email-fill': 'e683', + 'wuicon-checkmark': 'e64a', + 'wuicon-checkmark-circle': 'e643', + 'wuicon-checkmark-circle-fill': 'e668', + 'wuicon-clock': 'e66c', + 'wuicon-clock-fill': 'e64b', + 'wuicon-close': 'e65a', + 'wuicon-close-circle': 'e64e', + 'wuicon-close-circle-fill': 'e666', + 'wuicon-car': 'e64f', + 'wuicon-car-fill': 'e648', + 'wuicon-bell': 'e651', + 'wuicon-bell-fill': 'e604', + 'wuicon-play-left': 'e6bf', + 'wuicon-play-right': 'e6b3', + 'wuicon-play-left-fill': 'e6ae', + 'wuicon-play-right-fill': 'e6ad', + 'wuicon-skip-back-left': 'e6c5', + 'wuicon-skip-forward-right': 'e61f', + 'wuicon-setting': 'e602', + 'wuicon-setting-fill': 'e6d0', + 'wuicon-more-dot-fill': 'e66f', + 'wuicon-more-circle': 'e69e', + 'wuicon-more-circle-fill': 'e684', + 'wuicon-arrow-upward': 'e641', + 'wuicon-arrow-downward': 'e634', + 'wuicon-arrow-leftward': 'e63b', + 'wuicon-arrow-rightward': 'e644', + 'wuicon-arrow-up': 'e633', + 'wuicon-arrow-down': 'e63e', + 'wuicon-arrow-left': 'e646', + 'wuicon-arrow-right': 'e63c', + 'wuicon-thumb-up': 'e612', + 'wuicon-thumb-up-fill': 'e62c', + 'wuicon-thumb-down': 'e60a', + 'wuicon-thumb-down-fill': 'e628', + 'wuicon-coupon': 'e65f', + 'wuicon-coupon-fill': 'e64c', + 'wuicon-kefu-ermai': 'e660', + 'wuicon-server-fill': 'e610', + 'wuicon-server-man': 'e601', + 'wuicon-warning': 'e6c1', + 'wuicon-warning-fill': 'e6c7', + 'wuicon-camera': 'e642', + 'wuicon-camera-fill': 'e650', + 'wuicon-pushpin': 'e6d1', + 'wuicon-pushpin-fill': 'e6b6', + 'wuicon-heart': 'e6a2', + 'wuicon-heart-fill': 'e68b', + 'wuicon-account': 'e63a', + 'wuicon-account-fill': 'e653', + 'wuicon-integral': 'e693', + 'wuicon-integral-fill': 'e6b1', + 'wuicon-gift': 'e680', + 'wuicon-gift-fill': 'e6b0', + + + 'wuicon-empty-data': 'e671', + 'wuicon-empty-address': 'e68a', + 'wuicon-empty-favor': 'e662', + 'wuicon-empty-car': 'e656', + 'wuicon-empty-order': 'e66b', + 'wuicon-empty-list': 'e671', + 'wuicon-empty-search': 'e677', + 'wuicon-empty-permission': 'e67c', + 'wuicon-empty-news': 'e67d', + 'wuicon-empty-history': 'e684', + 'wuicon-empty-coupon': 'e69b', + 'wuicon-empty-page': 'e60e', + + 'wuicon-apple-fill': 'e635', + 'wuicon-zhifubao-circle-fill': 'e617', + 'wuicon-weixin-circle-fill': 'e6cd', + 'wuicon-weixin-fill': 'e620', + 'wuicon-qq-fill': 'e608', + 'wuicon-qq-circle-fill': 'e6b9', + 'wuicon-moments': 'e6a0', + 'wuicon-moments-circel-fill': 'e6c2', + 'wuicon-twitter': 'e607', + 'wuicon-twitter-circle-fill': 'e6cf', +} \ No newline at end of file diff --git a/src/uni_modules/wu-icon/components/wu-icon/props.js b/src/uni_modules/wu-icon/components/wu-icon/props.js new file mode 100644 index 0000000..d35f2c4 --- /dev/null +++ b/src/uni_modules/wu-icon/components/wu-icon/props.js @@ -0,0 +1,90 @@ +export default { + props: { + // 图标类名 + name: { + type: String, + default: '' + }, + // 图标颜色,可接受主题色 + color: { + type: String, + default: '#606266' + }, + // 字体大小,单位px + size: { + type: [String, Number], + default: '16px' + }, + // 是否显示粗体 + bold: { + type: Boolean, + default: false + }, + // 点击图标的时候传递事件出去的index(用于区分点击了哪一个) + index: { + type: [String, Number], + default: null + }, + // 触摸图标时的类名 + hoverClass: { + type: String, + default: '' + }, + // 自定义扩展前缀,方便用户扩展自己的图标库 + customPrefix: { + type: String, + default: 'wuicon' + }, + // 图标右边或者下面的文字 + label: { + type: [String, Number], + default: '' + }, + // label的位置,只能右边或者下边 + labelPos: { + type: String, + default: 'right' + }, + // label的大小 + labelSize: { + type: [String, Number], + default: '15px' + }, + // label的颜色 + labelColor: { + type: String, + default: '#606266' + }, + // label与图标的距离 + space: { + type: [String, Number], + default: '3px' + }, + // 图片的mode + imgMode: { + type: String, + default: '' + }, + // 用于显示图片小图标时,图片的宽度 + width: { + type: [String, Number], + default: '' + }, + // 用于显示图片小图标时,图片的高度 + height: { + type: [String, Number], + default: '' + }, + // 用于解决某些情况下,让图标垂直居中的用途 + top: { + type: [String, Number], + default: 0 + }, + // 是否阻止事件传播 + stop: { + type: Boolean, + default: false + }, + ...uni.$w?.props?.icon + } +} \ No newline at end of file diff --git a/src/uni_modules/wu-icon/components/wu-icon/wu-icon.vue b/src/uni_modules/wu-icon/components/wu-icon/wu-icon.vue new file mode 100644 index 0000000..dea833f --- /dev/null +++ b/src/uni_modules/wu-icon/components/wu-icon/wu-icon.vue @@ -0,0 +1,225 @@ + ++ + + + + + + \ No newline at end of file diff --git a/src/uni_modules/wu-icon/components/wu-icon/wuicons.ttf b/src/uni_modules/wu-icon/components/wu-icon/wuicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9aedef864f7e685fbe1dac7e0f36fda281d35a7c GIT binary patch literal 39632 zcmeFad7K{{ label }} ++ {{icon}} + +{{ label }} +5dCv2EpXHngOb`UWuvZX;X$#k^8_Qi$I$sdjblhFLVohIlW^B=|_ $zvJ2ib>loj|7CX dq6lqI~xkhJ5rZ!yP7gn|CEiU{?zswDm*$ zaoqceduG2As*HL-@QAqkU;JBn!u;*R0gG8ba{5CMUl8^p+mXG&>4pC{{og+L-$?@? zInXn>iy(Bn j +yk*(yYZm=G5d zLJ}M+4IY;fvVtyz1Vb=|un@txaEywCaqtQ@(Te$6N18x!cD?TVU@62SRnf23gJrO z!@^a py9H~yn=sD> zYsgKQ@q#t%Cd_@on&~ER0l^w^6ZnB(jk*b(L9k}K2|Plu=C}#mLa@f%1im3ybKN9t z!FisWz)J*cft$cp1Z$z2z+VJw+)dy#g0 0i~0fyoKUc+{Yc=6g0;m>;EsYtZAJp06f9~d5;&${Q9F^q zI|Yl{i3BbxSkyKo@KeE}HXwns3Kq2i2|QM?s0~Qqwt_`%Kmy+tENTOiuoq`)0}^<# zU{M>8z?B7y+JFT9ELhYAByeiMqIx5NXA2h96$#v1u&91W;NyZtbwUD17c8n15_r2{ zQJs*$ n6wm!J>B~K^h1ay&DN~L9poENRSYMMejp`tPm`E z9}=X7V9`5}AU_0)-hl*3B3SeeB*+xOqIV!cx(F7%0||0Qu;?8~kT`-x??8g=5iEKK z5~Pq|QMpJ$4reMC36e>$s9Yq-D8Zs~ksz%Ei^@fU+!8D*7YPzfux@k{WSL;y bQ9#NV13C=kg$UFWj8_A3f5QL1gR@nUv(4Y zuV8)MO_0Qbb+?-!lLhM@H$gfJ)_rb*oEEHax(O0nu)gIc$Zo;9-%XI>g7s}T3A1tD z? Q(|6PIUfv;(jHch)b z=nanRUkIHQddV0wK54vS*3FB}XTp*2Md5FT?Z^p{yCP3U{t{gf{X?ubc3SN2*q`EC z;%_8YC%&0nki0bcV(R_rSo+lTA6llh+>>d`Jd@p){cdY->w%n^J2m%KzM5a3zdZlL z{9g*G!fA!u3y&7wDlRVGU3|Um*tXl-o^7*Bcb2D>*Osp=zfoCQxxIZs`{NzcI*#tR zrqk?vwJX>)uj@e9A9~K}d23o^+V*MRoM!hARMqP0>YX)jtzJ8Gz&o&I;I@Ik3|=sJ zLtU*esNdQ6_;hLdUDJO#BRAuFL$il|JiK@K53^>@x^0# 5HuGWe7=DNCa{KKtXhhG!kIrxtFQS@5@Z;|6MuUstjq4m9NlvR4EOZW(j z$69%o#l7MO& e`g2> x1ojfae}IgNhP(I49*JIuW{u4*V7V8KAWSxWg#TfKrw `u6w@@Boa-lp> zuf`%?kDHBh)En{22rJPqcp~DhO 3 z3zst!kLS$!VLF9hT>oCq-@AVOncU~;T##G6+K7c13&o7dGvQ~nc@h5s5IMCOGKLks zGV{hTF&nW4tIxvxW!^qkZm?Rk7?oMLS|2DEypdRg8chuolfOzt?FYile9BBGqHN4$ zDf PaAp4;4WSFrqn`5Sb8A(liiSZ{yk UNMIx;^MzOpQVTbEZ-r zXpHbGI7vJfkuiu~vEZB{&aG+#Pu2&VjAEge575`C-2C11Qp0Bv-=Znms1NosFa^5V ztV$G&PWI}I-Uu!NRzZEng$E`iY2twgCOn>r2kv-YlAgcgj-N}?&+pi 5XE`mbg_V%u z39tn$R*1(7vC*l@JuopH)tap09K3kd8miiYVi7gF$EmKk$Egphc4RHz`S#3HuDaza zw{A`~PnjvosNDSVTmHG8HV+s^Alj4i`@CQTvRN6JH*b*ct=Pf&j^%7tQCEFFNme{+ z i+(tHM80m|+{9CM&xj9o|-=eDY;|u#LzV+jqy-dAXVP6GjQ|uKA zV-MR;;cn6}?g|itN*D$|e-85EnK`&^d);gHcYK+H{K}k($LPfV!`{t|z{B(c9PsGW zwZn@JJ|W&I)-W# 8D?6IBqwgdG`B8hqm`1qpTA~bZ-2Zqmwv7-eK6g| zo=vrOy?XF9KCCcb=dM{}@9pr3(S(vawl-~D4yEsiH(J|9;yxZtDlFI*ZEI0d;gtOt z^Rwi{ZFiCTf#mMDFz07Eb6#M1;x)BAaUEt5%Y{_Jj1zBo=W#tA*TsQQEN0iksW3il zqkFb5b#8~=c^p52Zm7%`#Gu#-v<`e+DiSB}Wnc-!4~T5!D2eu{Hx>uY%wn}zy@9?g zqVpQa0ov+i{N7tmzeEY%b~=v!eVcFb>x>2cw=hlhsKHzOA$+mV5_cba%x+QKeax}D zf3PBW+Zm@{?89;MKK}~M&;9z%cqr(<8A-y``eV-F{G4N)BjEt> o&~VwXU~k z{jOPCZzy jTv}^A>IYY|Rv-$pAn8Q|NyHkoLH8HbtGwWS* z$~mX3>t;KT(Nra-owA3wq^q@kS6@`?Z%H$@b=_D%lOs<5qVC7=`(Rxu(u~B+bH+(0 z8A3pYaKYdJ5hD#H0gIu{n>EwC`%%T84k%LFqp3FL*(QcmwoWtg!1<