Wn(E7>l80S($fo2 zQcccH9z2(cklud83b~Jb>`$T&NiQ|bTlj+wAQd1ct!^fkW&u!R;FXP7OK)uW68X6Y z3;Tw|E8|2IuofadI&ICb^q2qnU|u4swH9wtj0Jk%pob>u*^_epu`D)Q-hOP44i4y_ zJD!uGZ_&e+)=;fmgIn4sVM}XJPEKKk%C|#UhVs%dmaIH6g{9*=hD1h98MxVH7R1U> zR_U=?UU0lf?)qm!tY{0oZ}23@i;fp49nhX&2vowhIxbs~pQuXRA0L}9CLT2J)9rf7 zAha4=4WSnhVp5AyOqLxdQoM#H@UHW<*L-A*O}H*}Xg30Js&4*CRkVmYTw(hs3Bc+Q}Lo>QTb0?KTis zGc+xD#!~RqwmuSH2_jnqiH`)YmL8cRS3laBkY$TAN$4J4&YFDX)I#5~$Ij~ej)Z6J z{GOIf3ndPak1oU3P4coQ3)l*|>B(zM-$TXb9C_=w^uf3Tl#Uy;&UJ`bkDvj;QwWwK zK#Qy7_WiyLuNFB2m8E`vMZ6)OPUb+o*#=0ewG!SUOyk_mwX-PF@mlPD2*DNv_aQh6 z0L}?QzKSLe$&Hp%CO|u#^zlDpr;w9w#T`!;Iq5im*wdKEYk-Gad}n>v7^nXnHo>sd zxgGjw*1rl%4g{+aoP=iCJ1)~pe5>HqSV?@^2ra-Oq-rcyQm~5+)0`;W;Z7PD`$X{N zKBy~=RrS>n pAS7Z nA_;EWcuUQ_va z?u0B5_Gx|+>wv`Hfzs=w4EYn^FyA9DcIq@@CqN5dEAM$_fR`9O37?74R*li5ST>w) z2ZCD>P)yv7CE_tI0FIq&v1^F4VXQ;Up! 1tm zFDWXSp^A@m902apZ&+usgj}iQK7fHuVmp@2VcHT3Eo4iyFr*(yryM6lI?YG)j|-ZE zYHn~eQ~1Pv8*rLF8oLuQ%f%QTJmlxF0-Zr#^~NdKpJn`NH|u>NAHZ;$hroqYYTn^n zjjoWo^hP|H`%kUFzkqz0q!k8@!u=eeUM?D+Wx~4@sRrMww^r*$lblgKOO15Mpv6bz zDSsLP3On+3M=qWT;z-7g&|2cl`t_YUHdcP}on=}Aff9r>{8|^}&)gMAGhhmX7E#9H zz?+~eHEEGT%NXEfo>&o~hx@Su=^@!rw1{sZja)!`_mB>1`!CuHQ1qq*t*2b$D028O zrbxUQNE>c|btixk75KjSt<_jeG~>diHzI|fJ>Guqz7ywezU$9Bwx2)v$hkf3e1+WS zcQ4w>$A=d9BjA>%g_Kh@)WG>p=#*A7tg8V_V;G%@ OAuB~6Lf!=U7}D~w^0wbsBoV)Z#tEsa;&8K+LUQ}@uuH}lSbh%hZ9u?6 zWWWI?4}GY>mvQDQW5FmKJd~?q-Wisrs`7@jxn9h*aCf@KxdhG_!p`o9`|EL;Nt z4BN3pF;w%5 BN!Q8cYjJ58=!_XjY1Z! zKY}T}c%%e>x)I<6zZ0lAgp63|TlA+&I3)KS{q#LuG+yxAk$TK2E~iyE8fq)()T{zW z8jL)x=)o3BE&d(0@B=u-9ZaYaj$8RbWX{iBsuhrfLf2%T;7=xkYsG6T&-)gAwu)&t zI+)xsAyt0+!h;SHJq7H$0mq*iO+sQQVEb 3Lx}^?s$LDFr!!Y27 z^5>to0GHSNrCC2XXxsc2oGZ8mRq>4wo;GQkh@ts%?ty(Q*9)hnWCvtc_hF~A$R$#P zki}bJ-|txJfa{IX>>8Ahj5!9e>>CLUO*p#Q+O#(#n%O#VvWTrkXg3*Qyx|@(WV}Q) z(d&<&Fk+YiE34cr6*kcMUAe}iu)Z&S6S_|5O~``HeSrmea@-}0S+l)o<=jiFEoiKe zjXW#gd})sNcklp4i!lMbB6qKW^IqIB6hKATn-)w?j+<3$ZCwN2QR$Yqc9$am1rR}7 z7{7LDx>Y1P#l{Aw-Q)Ja1q5OwjwLVrI@b6M^hl9g|2|OO`Sm*>>Z)%pG1K)>3Fp0) z-xZdufXOds!VL&lZM6gU!4+;e%kT`w^8`m7xtYzyxYRU_JU9%*aOF?L?DE^+6@_hV zo`!+JSZIMH8Nwy!(Ta28QsKav##SwLa0E+NrBGJgJjqr>roP=70B*^f5IXu77 zgIksBzt1 %8r 6n%L)YtT>6_2|4NSDgAs{L<#e!uyhJRJAm%uk!SzC-1rt$&jJ~I2Xt-x#}6z= z<3IGB&Y#16CBs!jlYE!Z~Hq2rU$>@{+^K)=n^9cJ*hAYD_#*v zWyrJtB$fOfr1u^Gk?*X4yK1K9pOqxWQf%)5(%qoH5@SjQ12aFlHAQ*H!cK>|YUP(! zcK;-D)9(U$6gN#g39X;3;9i^_tw1wio~;~?Vfitqq52m%;RdCgv3&W+-wn!z7`6mB zG0w(*!?MXon%BTf!-iRKwS)><@}%^QV?%SJtsDb97~^_nLmV4YqQVm&hydLy--o5m zSZV N>0VIG@Xq?=o#!iUip0@ThZ?l4$|xV zHZ2wTNVz77EiE~PxYXgNh $bgI1FA*^C^s7(W)MXc5GO^#gz!otRk9;7HFbCMyf(v4Rnn7K@m& zekwE>TP#qWO6Vqdf=ex88a{c_0MG}&tlDCJBvT&$biNMmFb~az`_75;Swb?fIW~0p zMa*uARkqG&eP!=) f?veaR|qa4pn&juCd3K66Q3#F$w1}E@P^WxO6@c_0Wm_Gia35A zN7S+tEP>dgA9Xvi<7#XT`3JN*I1~)&7cw>Qt`zh)b|_gr 628p(yC5S?c?5>CY zBu4o-on;hf1Cp8)+H=%7>S2c_@yjqF++G!=OH65<$@(j8#q2hvqlLMZ8~QPy{<}*# z3fsamit>fz zu@v$>$b2v&V6dORf9Te(`d_?>lbgY8zsK>uLxk> ^~47?cpb} zKa+E%7Qd6HRU?RydNc9_BaT R?@aCIeulL@?r(+r~G(3ymXleuU<7( zrr@rFp|s^iW82vf$0p&zD*!--PwGRaO`!uQfeb(Ddb=x0AbBiC9r3G&|J@;N9R15P z15HiJ&7;`8ELSNR%|2g6$}t4_IgBWxgGE0b-ymT~0>_vNyOZuLS54$sr0`b)fE*x2 zqeO9yVR^ 94UAjhm55 zNH$C({0X~!ih#yCkEK5&0Ez_u8I-(QUeT*{UqEcKZmTAqUak8g4oUpNloj-}JHN *t FD6*dn{4TlY)x+ zFY*Lj8m>x81b_w~{((Kps!En)f}c1ME}Gi6R aga&Z)-~3_ zSG8)ZouH^#JKvw105SOO0Q`a?eE$(VP$*25BY7#xHFh@gYH|*#SV1}3&+rhmGye3& zL+2j7^ZfR`=Wac$jjRa=S FZ^JO!22T@fS?(O`)PrZs{nOAkC@S1g@_GK z0IG>jt)#G2j{HV=Dt9%B2g55b!}$jRP~%`L;=-?b+DS8S#Ie$Yb=~;c&C@`C&CyVL z*N5yTJ&;7KuWisopba__CK}d0)4{gr!D@abvf<1`Rx{y_8dlM}%ZL`&xDf_}y*^sF zYSzTr9MC}^iq;qr&n$o&P$n&& ;!gF?=0V*`vcfi{COyNw-!%=xo6)@33YtI9`PS;;bT(0H5+uNcYkhj!=KQG3&3 z=1=2v5hfDh_wbrgh%Hq&utMWp7$HgV-oS1E{nFjY?$^zvxuYHilUny01<8W6^J181 zbDomF8xnBsfd0Z*sDigD6!Pf^eHm1QZ|z<{@?S*o5-v47#t}YkSz56j(+u8%rBp1v zf~8jxAYY(kHy-qdchA^HsYht`?u_BDYcHO`Nj!fu%ZynJOeuySAuUvrWL9+Q77S3i zF#6_x%ETQkN2%P-&IDvMbO#$$6qFI4jUt%?pt~zqw(Ma2jg?S81Gzm|IkSUZ4J;pg zD|n(Q{{@ySS-aW5viUgs0t85rf7kprG9buWz7U%i>F8DaK#J2@{utwb*8@N0z?&&j zOMEFHUmIe@9k;OOl^wUSjV$-n9(GaZCCVv#2t^rE6S7;(qq^>FajtPA2d0`!N{mDFt5696%7DG-aLPz`=G_B$aM8~A3M{?tT?WT0? zXBoz80Ijt>R%UP*pWEJcJ1b{4V#NfY>~aRF{@i~NQ_;Cb9?(-Z!^gnrk*_0i?_dSS z<
rD3se!Bh>$w33CZ!@zgHBWXx{MV| z!(c`=smZClem6^8fvbTp4tZ)_Qn|RAE(OCi4|;So!nF8~jKgWP|H?NWZ)-o4Q-B@K z@SQ5VTatJY*0;gP+E;S=;A62e^d6Q?zg?l4IJ}*#ZBQ+CJ6^_t752yeaHAT&+|B18 z`Yl*tn2SFXupOV@!Do}kSnZw;{a6Nxa0?=AL$DXY0R(p;IE3In1V<4(M#q=WVexqc zZy-oU@G*i<5u8WxHv|^}s7Cq*8GXNre}}bjVh-CI1fvj)M=%w^7;IgMr5Xh55Y!=X zBj5-;@WorWxr@bS1lthoM{p;Cg9r{Iz}MjX83g#YmA{1mUo-OGB6ttMX#}4j_yWN< z2=J_#PBl3m&2c=y;&__G;}PKAo_leF$#KKNaYw)*=@vL9ksLh<$E<==6vjZxF>r8n z^5i!;dI^p;OKQx|;EG9Y$?ICi*15$-mvcOK0}7BLNb^CT;CB-k`% u9=is%CmmsH^ks3ZqN`BQ*={M=TClg^ zeOA=T628=xFmtd&pDqJDb}eM>M;~Cb^tzQ(l`oI7`N ci8UO$Q delta 23142 zcmb_^34B!5)%d%!FPY4e$-ajKG6{r)O+XYv5_SS;KnTk) Y|S~a4riq!tkxo@^4LrZ_ZZ~S?3-@WJE zd+s^so^$TG_wmjPs)09DiN7-#bR7IVk9_XhWIvRcMofpsjrYl0l&z|IRjayQ-KweA zv})_Mt-5+0;dsK!TJ-gL_^W71Xf@OuSe>#ZvDH{_WMx&0snuL>Zne}~T9fLNpibRP z>aD!ycCJ2|*8)s|w{ oOt^Oh%*o{%GX z99Lh!Tlr)@g-<;y=hOIfK7*Aq`7A!0m2&u8K9801k1FcNILB;WC{%7r@)hu7_(E1+ z#E<32u~IQ_<4ahnlpoJeV5KsCB45r*6-Sj%5NT8(ei9H|#LGheP3ET@Rq|7Bm(`Eu zr$Ng&{u+SA{B(deeg?o2{z-o3?WDexzZRaxui|IHp9%bR0L%F60Z!y+11tx$Ie=Ed zSHjaIelEbtd= HxghA~SwjGB`@4t`Yxf8)qG@s2q7)e-znqxx@%gI^QD-#CgVd>s6FVf-Rz%uE~O zV9pO?mNvy;HpjtSz`H;<7l!eRHpk#^iG#l=j9J<;YL2aO@E3>ii`rs(ZjXbxB#c?w zF{ <9F+F?ZVBQ$UEbSWA^DS}k>mvA_qwsxk@K;9gyGL<*cO3jxVf^d5N9p#h zaqw^AZv#DC&EF1i4Sxr~`fv|LKZwlT!rvL^-L+xN(mf;QV&V73!Cx1_ziY%?Ed0JW z`0Hcvhii_7-ya8mLm0p4?ik7s#KE+OF-s4QqP!;#{>BLYp;43{j)U(A;};1rl-v^s zb5j_z^xjdF+!qJGA%ZWCkgtV55(l4;;2#==e}5c&XBfXi95vGi;@~&(KLnj=3cpo) zG-kdJ#=&pq9|C+=7+)w&&}CZq-Z+?>!#JhKM{(xiIQUz__(lH}L&GC+Fk8ZyNso@| z`A5PWeX=|hF_b 26LIi6cF4wX&g?>tE+(8) zwt1GY`|Tt$8)F*rt`?$K)n^W`H6-%Ja741X67huckF=KhtTkMZYX39axb5;a+%{tS zvG8!>TA~yT#>xIF<6L6R-Q;N4;%wt5Zffatc2HNF$30Q-o5m~CA-qWzJ~XYLm F4w_0*V @*n zAsk9uNbVDUpOz{9@lKK>l&7aFG+NFp%vqeHRC+a=6M?1HX ~tkPWV1OIU70-V@Cfr%5UU&&Z8B|Gt$Rh z5o0(NLPth2(F#Av$QKHZCy5;yL}zgqUV##`@LfhpwkkSexCHuUg@7K%etKo5us+iw zEIXAT?8+=osREp!Vzaxwjn+Vs&O Q<-Q?Pzk+5<#9d zk1Q1yWo7vEG#@+AQ0L8^PPfNR75HenL3*s&-r(%;fLxeX(Z$%NTjc 2K8=_ z!_(=uH?;H4pw8uXwLwK&gEOe$T@4 NO|EOO~ZyHdk1abzQZ0`6!y)Itq!^dS~kP~?!7QQ&}BnGAYn{zb?>x*uB5wa zNG4a>$$4YyJI34rV{Y%(lars@`pUw<`b_~>Yhc?gZy9}i6#m`WYe;@pwUO&HRnOqg z7z?YX$ 4%?(e{LETP! zJ7c(`#STlJb^`7`;kkktsthPKaAKZ;Sji1S-t<(#K1NOC!p-FwWU6qqEK|%?6P=83 z!m+Y6v3CX03BMbYEIj;drW~|eJf2RHg>sv2+750E=ZUBoC>AuY;r7o9TcWtFRf6x< zbln2UR*i{vm!y!_b~X!v!lem+K6vz_yYIbl;P6MkI4Ddkawu#nsuf- h4bX<|{L2&A!MHL-M;O>yRA& ze)pBeH?r>1*GA}I&-(9%Qm_y9>LoXdbiZk?l{-r2YUB@@D@$Z2&6P7`r$`!9o+{B+ zPE($mEQ7XFQwf%*$+0{`J6EYZEyMcL3W8-N)}PiW=bF{04eGg8HFw%-nLAc4IJ#2& zN5{QE<}np&hVdvGXq$#2hbZbk-G*R0fS{()>1k+ow6w6bL@74x0sv;;i{&oiq%93N z{HiTqc^gzb>i^s}Nxo!wS3#AdqXS$C>ymckd#n#7ZNjqD5tKkBZ*E~r)QwJrtw3-a ztrOCfcf#{C{(Tb`$yE~F{@<5BFY_V0=qv=d45aStSh6ALK;Qx}dU9wPBy!l4cH$$W zNflJOJkC~klq%W^jX^cm+Fd+Fj=52PfjlMr4+Q2+8LQj}H81%WPWhQ^;qb}F9Yqn; zHng{Nwzh?Pj1K2U0|@ L84)NkU SNJr3IB^x$M8!lt_s9|;R8H|>C?pti-?=n+1>J`eOMarPMfQE1bE zWp&Rc!l4OC{$;b M@LiciBTCRlqyPoR;E>(ks!Szjf(nJBRoBECJlR7sA%A*`psX$vUR-1m z9xPJ}p6N-#oNM)RnO7z_7AGr-mun=#n}K3kmt456yxi)OS91py4YFpgLAHJ&$8{;Z z3Ze3&WWoM|R`~wsTH&^rAQrP}RBp0=T>Pe-!?OL06 D7G_+B zf!~v+>T>Rvh1G@fQ+XOFo|;u$qg0$ODgyYTskla`cyUG%z%zx)>Iv#IHZ|a!DYw+f z{MC! awSG+h+Q4W?CAFI`w`Us_YU(q36rRdeHw z_NryI^A^sJa;PsMsAImn%>mI-G-#$j#$KMrUL@a+?Lk#Tdt0NcNumJd5i~S{ZN{L) z4!sC#mQFUJFPB1c6O`uof4H=qfa8CycG`FhDM9D4zK^5m&>5F0#^em#h||l#rwo7D zvW-Ol6D;G*=}(3Gm)rEUPz=iF*VNHt!t2Y^eH*aJ51@}op%q4deJW`;z!-t*BCS?t z8rra36EjcLkDv;|uFe(@eGHLLAV8Z-_X2Qh05FY+C`FFFrQN~X8#<}rT#=&uEg; r4Q6J34~eYd;XD8@B09+t5?>aVpyy|m6S z40cPN@+Kj1T}nm7A_o&XS{x0|=JpmIHbYVSJTe{@R<0{lz5}Bj@ZYlTIyvzRzqGHK ziN=`z7XmgYwns^n=!)?RK~1OINx|y7>082*jXA}SB7TGv$!r{ex>184-dLnO4-LKk zUv4zX_!td^$~uZ1k~+r~!(s#22r~2kztF@q4}8E SWJP2u5#7`YAE!EI>LH@p>Pk%G?%7ADaPq`@de61Le-1HBm6Xy z;r~5fOkfkFXe=fwVM1d~DGnS|Hncb$lyw#~@Xi(|n8t?o_AM?aMe9g^iNGv8*qEEf zqV@y_-|A|E710D%lzs}WuL*B8+M)j`O^fssUq|$)njVHn+zG)ZY!bFiM=%~i8G>@* zDVmdrd qOW!2p?{pFx!h&T>ygm zZOu;Vw0Aft>~X8GMl01|$h#ZSaLz$ODM2IrH>}w!EZ zWRS+r6!w^7H8Mg&`6A9pHevqQRzErhZ}fZ4(lhh?t0h>|fkA z77`vG+;*E@5;~$C7TRymP%Xsbqr$=4f1qNLx*%lUk?lZlB5m3=7~-)+09!{)2+_4A zB3@Jk$asp(W??r)wo)|p5CuAb@9o Xzz zaQ=?GSrML76Skn%0bjQ9_GX8>nWCKus@t5~?42+|)Zv%`*PSH1*O!tbg&z6_>U6;3 zL!Q$DXsv~9lKYZO_`|EY!e^gY{15)1R!$!B|8?*C$~-0p$dH5xL0JrwfbiFY)D&eq z)Bm+XTTeN8RyfwPEHBbjEA3_=A;i%X1gQuh9zJvpIV{XOG}ng{sQVl8^}-K-a^b#{ z7xwggbk{Ko$HAPN}fs4h|@Z z0C6G`2&$yOpXMO~TmQ_?k6=4eiOz7?FC>M|4n87 # z@b8*JX0{Jwr)YgXX1th-k6$3Th~N?7$w$&4YIy0973y!W;_sY4`_Ws7>|0KF@JGL% zu@dTn3bZP86*e!%XE2lw@W?nFn=B~b>Szh7d1s>oVza0-yyvkpk|n(On9mw9?Ljhu zS#tUhPFQs!hg1ojC&oxSNsR9(Tc<88%|hW^hX8FLy&g-m0o3&=uVDUhB{2z41vFcV zBrMpbgyIZz0+>PyZ9NrOvS8gEEVajU`W!q5RnF}m%t4HhX*c3V?GWxarC1;;Q)`Ub z3Hc;I(jq3C-6Skc1`yOie9pTtUkNr|xUVm-FtQY)HlEHz{Jl6XGf-wB*q5D*R$g+) zDBO!^Yc9)#j$p38^zm$YW-nAW!2gk7B9!Ft|CfIk8lF0s=#^0guk^}Xq>b>Lkp5w@ zqI;^xAmluqE52V%j6&dd `=?fH#zK#%6^{K=E$T~Qqy6iDnxw)D-y3DTfnmP?p-HFkB!!3-2LMmJrGXfe zcvE;353ULPu~uQc%Oos)Izev9-~>mv)yF6C)^OsSPd=(XB-{TJ*a+*ow4QY7J&xm3 zygImbA`5qUV|e?jj%;ML+rU}ZN{0n(l{CT2l8N1br8597WlnT-xF)hVY9b_1TU~Cq z4@5Wt_hs&wZ30vGb@&>K_M>^GW~>8=N#P82VhM#sc?69B>gWdmZ3anuN9Zh5*ENW` z4?!D%RrF3QQUqvy=@tZNm>?GuH7;y6Y$3gh?NPJZ3XefuOM3&Palur%S)K*riQQjX zvr*H62`rwFa!_u%05ozYXp{R+;qH@FiSHIy?Ad(8Hee_`>FJ&)I%-M&)a>(`;=sza z@2s>Bth5I e zb0r<*+lvalLFG2U*r%?y)Kq9rm(0DUW}3hMne+0(DM&nH>?|xX?y{*dw`jw s2bge}2W8HH38xc~g4#Mrufwr}uboP{F6JkO%Z(ny?(P9#ONfyZ^O;f2VRMtF zh3Ii)7iXV{Bp5Izv9cWjCJ*TfV8R-d+XZ3Sxm@AXPm%<~uLu0=o?EV{x*DcJpY!M< z=tQ!xi&+W5QUnhPpZ~JJSBpi)Qc01Kn{+HzGVhrXqtbD>MwcVzjrh(8b|I&12|;-S zgke#Q9>po}OHwkIEwbUPx)PT{F@vPtbR|%*8<}(_%p||z*MF1i8G{ZWWk&?V=>jQ? zsD lIQ+LeMVwm_MljF{(9?3b-v^doQ-F=C3+ zxX=`oJGVE4^U2` 4XsFHpW;%{c^F7iKG;tnMkyf zNSJ17k&bN$wj*HC$}TK1X&~j08?VDxqXZ6Tax`ukksX0|r5&m Fv7}5`d#=eeDJq-lPlBw5_T4$xlT$OeISt# zRf#Ln$xQmcB37c6gL$x=#0W+U&%BnevIDW7%l(6|ZIYEUQKIVElx%Y;g(1i``XdA= z&tWGho8K%@I-rvCAA0kMjLZ~D&fX-2XDAyuLU6UfMu)b9gE;6}A#L1eVt) jV~|_W6L65Jf&f}wut3NqS_?|NGu}Si+!-5SOcYSP%Nzs19M!V z(|R}MfwV;bqH`0JDn{xop=&S;{KNx;&-<8tk51qM^kqwqs#Q?Y*iKucsaR=A)Bu*m z5SBkuLjOSx#EtH4E>AO_4?B2TiS*?mqOslWwnOp&^O4BJ*yyqdv34S0>_9ufEW$7k zK2!L|yAz8TgT07=xdLhGdMJgb4u4?}xFTp(b^tx4{>{OS%G_y)dKkgy06u21#uxZ_ z5y2VZ eiasG7-&lY(! z>e0p6C!CbD(|Hw3p~VBG>FaO|jD4ikal9>6BGVstb9)C~^>EWJcx9!3=?Awce2k$x zu?uFgFdy3|qg%0J8-hP!$8Ib|A`B_Gpv$llxfz2Uhh=m-;_U#?7aM&b!F?J!(zmen zGu+^@Fc46q1`n+#Wz!zP3+!}+9f6vlF_hH^Gl1R()NF^C$Gu#5 Z|{|OIhH+HrgxuK 5lN=ZRo(&ZA#p`rW$5x!#G^240OuDY$QjPtQQq1Z+NMXC zdKZlK95Pkr=7cvt$raZp618yPv*p0s_deSpFODo*NcX|SBg;03r(&4DlT`4G(0#Gc z$Ml^opZ$pZGO~)veJ_^SBGy8Z#KG>x#9OMMZ466?Sa#UecREAn{9Ei{#PZZj=RuL> zxj{-QMV(u8k3C|M#%@ibin&AhRp&y=VCOowWUNfbx`YS?P#a$a5}1h!zE68fuiB3lfqNqjMF^=)t@1upNq2- zNx|W72iU3c&U7L3a=L%$+y5b|MikjB;kEDbz$< zu*m65sX;qJ9JZtQQVB3DTRZVQ^w*nhFO9ZY-8QV&@TM$at7?tFI>)1J_GGq z@wkHQ7w-K>heYT2d$UQtfBg3!5OU_;L{h<$dv($Y96Rc~2Rmi@aW9tcLm(nJg5Z7x zVa_9^4`9U)5gY{&KEHsYI+iMX2pdo~^ca?oBX}4 {~00Qkvxf~(9t~lBkY8whaSTcn&_P+pdZ=ymJ@@4p1?}fJy`kT90f@(cpPgm zV?duo@HBuCW>VayAVtc4Xqb)cx(vfUq$FPx-vNA~2LbaB%pKf~k0VWC)E#WX*$(%c z^dP>1whzP?74nF^6Vp;uP-*9XE1;*1pc5K{X=u*HyhM_$`vsuXBgZbGF6Lm0THK`} zZ-6xfuBG*F(h{{SdBhwZf=(`FBfoAKHH)Z0|Ch6%Kgap}0KmwjI`LCI$x;3aS~~kp z2}Bn%%>P}I!AWPwLby=E3Q|ZT9yO7Qtavj)rwr?Dt@yEtlo!1OPk7fcl*{pAX*0^91pqpK z4pdaU-VEcv22YQO4l{WT#xJvwWSJhvr>F6qSz@h~tQ-5kSaHQs^-|FAsu-}6RYi{= zE_=a+r7H}*IGGeGgD}Liq9>XBMY^UUWB2l8f02nhQ^+eNT`Dif%eO!xg~Ejop5yg+ zb=0eZw4OS2A*Be?dTOs)aO5V7d1|7?TPVpf&v^A@9Aw-yfOUoUAoUmf8a_6M-qONb zT6fIY9yv^j{dhI6;Z?lCMV{1#zffBTt&rPObSb@x-AbPG!bKINxQXl1dr%M9?}^ag zt^}_R>4t kVRvbAl_6TQzfQq<^
s<0Ge(-FzQyC|F; z*qMU6S;!mIh3eo;9a4X=Pm#{ogF3h&l4+N2SOisYn%U&!;cV0C#LH)HdYAZpHc5p9 z?Z>HPoc_;1*lFOnyN`&OX{6O>%@7wIT6ARVIqTT7*6}9_x|a^B^?SO`s 9}JA1XdF<=(Or>$?{P%uCIHLq#{E9`GC*cd{){%uRi$u7imysJ+RckW}oe`uREs4)y`iU& `@F_QX~R}vOVfSxHGhQK%duJ{n&!z3r=h}S2*hh-PywRiw2D;N1D$X z#}1lOM8hG&5&kXHm_bvTm~bfJ$W3pXiiY%@dBRWvmtg6cawI9B&k88AzP(t=S!&6* zL9@e+q0OmDDK({v)7m721t~S >0})-aD2j+ zYrwh@y2oP{O_NBvxUY*OWk|XDCJq*|E|j0gg{*@GF>owdc;Um)f{Z-+AaRb%Sl^}N zIaoMKnxN&POUfJhToc+7XtFoKtKUkf*^>%Xvmc+>#PLS2+^gVC(T_X9m?TiSH=zlR z8@&2111!`;uc4Y-{}Z6b$Sb-`a7W(6tGosyZ{{sW6 76R~o%W-ngY2nv`B6ROiKrC^fE#Qm-H)g(RX_@mNqi!zLdURe6k3 zU&Yj;LX#W4Nus$Lu6`cNO@xb*p_Y>^TJfQkMCBXFpO6XHZNr=BxWQ&W4_aLIYm~vQ zbQK P^@v!F~4MN8a&)ilVH*PZZR~Ubcb3qWPN<8$tRC7-A{T z{4JKAMP!UF>ZEXd4p#mF03_<7`@>UM`yPVx2wp^RW&*r*DK+Md3%98gS{-eW6^cFH z+KWSc3ttFW)p&CE<# xzwu;FX|eR*R!`6Yscw z=a^`kB{WjmEOs2_z8(q^QXYhKZsdA5cS7;BrcZOy`b6T{;%lGF4-{X^t|vl9xE F1!H{ zsS6t6D;T;X^6U<3!F$`Qr7P*E6G5HyKIZho1i+;t2i#a^F~T~)i8*W5;v+^7?lidD zk}AxZq$rdUspe4 *4$q#d12FYOU~u4`}vZSQ(mcibM>pM1FPy^-_Wag zOmkdw!un|9b4vo6tU&I%!K}Q1CjDJ~Dt>ffJ6|~NM8dhksR2{|7b-3xJCHvqFtc_b z-&cD+DWlhOa?=YHukZoK=7G#D=aO0i2`%qd%nf9YAIO*xSg>x7anPEwNBjG siv9HDE1!Hz{jy;&gb(7_g2%Ur{~iv!)MPCk$qegP3EIWx!O{qdJm!0%Hzq zK_CelY$v7#GAqtnD+V+2j+NYB(!1(h#`v=tlTONd)Pt!x;;uuxdapT`T6#9M;sotc z44Ts4G35=I@_MarnZ^#L &|3-76nR8q?c(Hfj7b)xJR> zz?5;samd)C8>--vQiqgWdhyUSPHQ=sxHoYi^V%2c_9VWgS#;i%)U!}X+@plaA2CDZ z V<%}9*X0s_*|!&$$+*1r 1ezhM$dd8sCc!cBP#k{SD%EW1kwya4E2#f0+b;3zE@I!6asikc2B| zf3?t>7yiMf^$$fPP5C{Hxv2kA5q_$b(XT8f6<5Pc*sHMVMQ0XeGs_{QUBSOhly L?>@0b8=Br=ZM+JDOg@;AI(|JS|g;@uO;A0@41=?(a&SVBhv@#g+AbUHHm z0SQXx!bT=2;}XqmeZ QAP+%O=wt=?%X+qo%5eVW zjG_+!LPWvnV15$30Y@?00Lj%6eES0V8X-YCxKsl=(f~i;)TK!zTd9UYf7YKhnOsol zV}=tA(@CoDRqTVU-FL9WR;*k~paihu5(2g~-^WrsRz}n)#80*snHJ$Do4$#F^)-N{ zvj~79xc& U1y0!@>MF_3{tspl5p=G9$F*d>qCAG9NC6vRI8z~p zV%%Unct{+YO^T$W->YF}bV>euW?n5Xscr^L2~I)dF2=|#)* k46CYlJnf8MXGBnGr_NmXQnx{9gzVeFd)%fk;{M#S21r5wH^mLg45NXh;` zD^|9WBop+_#hOC#okb)+8JDw^-PwyJCV 7YO zg4;|27`{rUsU|3~l^p|Mk$<*?WU9tON15t=<5JR~BW0rdCQ`b9b&hL0Xn;HUuGY?0 z_=eim-~@%l+S;i1#*ZQKF0ISy1~YRC$zzVD6v;D*7j7cccxD95Sixj+70S!5e0})* zgC9M0By>lb^(+Y|GKK}aOhRCli8rq%tFJ;}%p`yUU(qDs +3S;`%eDRgvxeLv zhb6IcJ()~YY)RO}0~^T1E8By3eu~PWHwasB`3BXJ aN>FRC|=xnD^ZBuc0xlQHen;VuwjJ3v!Ngj@aC1(;)-*i3V1K< zI#H=Xo0mJl EB_dxQOMk`>MM*Gad$zs1r153D;gA2=JEaisWSje8@E_McdH zw-M+A?T`IQF{Fv52&9Yz+7UOM3!}^6QkFYQCU*Epp11)r1pU``k}qYx6FAL(d1@R? zkQO~(#mxN?ly3A4StEr)4`6NN44FQNkA4Kv -bEgkEns6eBJsE)Vo$4?dSB5toWfV42in= 7OyxdKm4~y;8ZZbYUA~rf7rL+LR2(z7dD;cL;0redyfC*yLtz;!g;a9hU zrTV{;LLrlacz!oYbkW5~$PxrGeE%78C&G8S6r0&sW24vsGY+PQJYeYhN$fJa5#GEt z$|n){^eZv_PO=r|)N?1fDDyGRV(~)M6)~M+D<1==VOw@7l0tgMBVfT)C6=zJf|p?~ zA$4M&iOHZFDp}kErdA3{M`SD_fe$Um-lNNlnXTda1nsO-Hj4^GcLQ67?T_H`M9BYi z?<1+om4Nl5{-gWg@D?~>x|@^{J>vw10hdylfR;}DH;(sZ7-i(%o5eKr8t8sRs3Jaj zfaEGyL&NK0-~c%a!?qqI{X`N#l=sZ*--MI+_g+6fTdyh)#Mp>w3>3hB;>SmAE|~^~ z_E1sP3*FS&LF-{E@1q8O#z}@gZ!Ad?=Nu-#_Th4+Q&AHL`;ydlb5L!!^X(0GyYv;A ztldqoN2C=vh_Vqr=-fi(Si$x&%;u=@5sfI#f}VnA_^bPG@IRncE59^}9Sfq>n*0 zogP< 7Hm)q`TRl9pkp2NOyh0LGJ6c?JxSdP!JdSRG zL8MQo^YAerG4u=By)XEp1O6c?wX{)pgH$UK6v#_1FwC`M3*U^+H0z|sl?D-o *0e0y_c+0=za&I}mgs zxDCOb2<}2~2m#)0qt77t2?D$iMSlUnM}LLI=Mmru3Cj-AKV#_|1ejo?m>y&4CW`4F zsz-qPa*7*8irW#2;XcJkn_^T+QL|ZiL768;XG+msP_*h44I;(WPggSohU!UA;f$F! zvdxcXR%<)o+2XvOHbW~=!MXFr&+a8@+COo|_qeLJxhgUFJ~CI_bssrdG?d6yOnpJ| zN_F6-wE<_-SDb}pUM$fP)x|UwNxo=-D^(W@#8o1(DU(Rf#qs^Oi{RL;8D!d*a!zJK zkUgY;$Dx`18TXSWdD&Q!J#+*76U_QMb9d+V gT(lStey~c = total or not rows: - break - group_page += 1 - all_items.sort(key=lambda item: item.get('id') or 0, reverse=True) - total = len(all_items) - offset = (page - 1) * page_size - return jsonify({ - 'success': True, - 'items': [_format_shop_manage_item(item) for item in all_items[offset:offset + page_size]], - 'total': total, - 'page': page, - 'page_size': page_size, - }) - params = {'page': page, 'pageSize': page_size} if current_row and current_row.get('id'): params['operatorId'] = current_row.get('id') diff --git a/backend/config.py b/backend/config.py index 4e042f5..ccb1747 100644 --- a/backend/config.py +++ b/backend/config.py @@ -23,9 +23,9 @@ bucket_path = "nanri-image/" file_url_pre = f"https://{bucket}.oss-cn-hangzhou.aliyuncs.com/" import os -# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/') +backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/') # backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://8.136.19.173:18080').rstrip('/') -backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://47.111.163.154:18080').rstrip('/') +# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://47.111.163.154:18080').rstrip('/') os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret os.environ['SECRET_KEY'] = "ddffc7c1d02121d9554d7b080b2511b6" diff --git a/backend/utils/__pycache__/auth.cpython-312.pyc b/backend/utils/__pycache__/auth.cpython-312.pyc index f8172f67ddca9266ff28dfa131c5f0f34e6fba1a..4638aec3e92df46a922f5dbc0093c4b975808a42 100644 GIT binary patch delta 2062 zcma)7O>7fK6rS1j`fvRcud}ve=f{CG!6AQ$LP|n`;1IQxgi1w~fV9SVw~2$}q_dkQ zsJ0TRRTZREi91MXs~&QrC>Nw0dJg1PQ6Yj osmRUCj7iWAURnC-^a!dhE{frnz)unwtuLb;q``OCu!1`od{4`|MEXrC^W zCv-Mr4uw}N%Pa;)9_KKTbC^C7WIFA1M04oMK7 UkF8p~!49zJC7@Bxj{A7$ftdtcY!I2jvJQ~F?vBquW} zX&ui@45hP!my@Y0YE~JX(9;=hkmmWi{yKP1grBwwFoXVd`sVjv+rN-rcSdL88=|M^ zt=yEVeyYD$({Za|UFw|qV8bRYe7QJXm|oJ?gDtoC`@w@nuYZfH5ajRdef66z|9t jN9L-x!)b8%*YpSc IK`F4ikoGDH+rnHxcE}RA)2&Cu!rWY{UJB-AL9lFOsx$NFFcY8 z02;L&n|7N5B|heq7?i}xEI)%v1~LP7C`xh_G@Yc!4Iwi&sS*+be@q}%Y`TU)gh4ff zdVpQEl3I8)0<6E3&rFj3W^+zAgTIl5x`3@W>auE!lZEi6N4}oCSJm>fvhF!J%Wrt4 zh1B9uVd#5>jxK5U1I?TMD*DcBZ_y_&MhcPZHA{Po75+uBAQmf=MLD$4_f+70(v}?s z!;6_hhGrM|XCjJ7bz3gv_RXKZc6#m%WG(t@%4(+X+tssmNUB??dGR!gT=F);LU_Yl zwZ+5zxpn}`{;>!5)}z%(L$A!Q9uI?kJKWO+w>4Slt+lO%ZOpEB^tSSAEx5OpzObK) zzXdN6w&)lpZ2d9LWXr$_jkUdKw8WO2)?SijHkhO`n$D6o2#K$J +&}_a+29`0JGprI|X|(W6*ufZ={K; zkW&!w5v}($<92#iyts11^AJavBKt@eOVG{W7=z;sTIh|6_E$>yqr!iJ5oGGj;GyoA zm7HLX9tKQeq!qy6)v1(Ol*ay)SbL1lm?V-oecRWF6Dt>edvIefOukyNN$GCIry<}| zsJN2;A_Z)0#RD;kK9G(~n`gtYn;o@HxlC9uB_>m5foxMuQq4sZmggoSCS~Rh*pH5m zDH9p>82J#UK BpJINY-Bl 7%Q6yDj{U9bPvj(<}BB#qUCBpXGxOjALc#6XNIh}!hffRys%y53D=*RjK_ zEjyJXiqu1qA}VVRh+L?|smcLC5bCwb1;ha=fz+(v0H_idq{u<42q5uhokRid%xb@V z`~K$bd*AHckq?HHuiS122kTbmmqNqUQbOoTYbfzF;xwcQCHs=&vIAuC7I)dHNq{cR z2I$sgKt;0ydNc>1x3xBb#MT$_*6%UCjOd5r^U4NG3~LoNQPD;bABmsgR{17hw08{0 zQNvAc0d4Rd9pb>t2_exS)&zDPv!J4zCiz|uHiA`jn4_qGt|zv_uZaCzk~2`9N8CJz z;95&I@H|&X{an>cKjy>8a#iNJ6~4}OOsYip_}A?>PF>2J&!p#KbR9>%vvaDQ$gqKl zujy6dpbzorglW$-^7?YMP${c|iE9PT6!MjF*~Ix8F)^vs4FN)8u=ayjbNTCfSxeNa zg_4n=y3pqcgV71MafiMqgz+x#qF)Qqo^L{v_l^4t-?}o7e8KleTcb37JN-oDl<2NR zonrX9$N$6wZ@1t0<2Nto3br|341O ofw)gYVIjK*DhE{rSHP&xQ@O!Z$JfOFStzkO9NeB>Ilj zLqCyv +GMns|Y~#Qld4 zYe#(W9p)V12xfdaMhO?i@&&sKJXC&m_69BB^JtbX%Bi;<7AuGwOoW{tqA>6<@G|HE zFh!$E3d^Qgs?>Et{Gd`r5@6;agKh>V7(@XK5rA lb DDCdwM@ zxE|IVEEq>6*9@I>>L!el oe?8Ai74L1BaLCN1hR+(u?lbHdXIq z6lHWcN5)u!GYp<(FwS6*s=maV$4X#I_M;>0Xb~F&Ha?3ACWfz2C32Q2CKxalkRbpQ z>y5lsqQL?gCt^1(R*)(Bxo;4?viXDW6dFu{@t^e{@Z_-m7r|kUJ{1_Tv2UMMyXdQd z@r)^3Kcl#IwL@L2T~=LeP*!KHFDESg9!IRcS)7z7mnvGVq^HOX-3j!Lq`u=)kGW`D f>O#Tx@Cg)YkMU@34WTJe7aXzycm diff --git a/backend/utils/__pycache__/db.cpython-312.pyc b/backend/utils/__pycache__/db.cpython-312.pyc index 7b0e8ace4856a93b43747b263bab1ed37729d453..036fe34ceb48a13a75a58cdd4eb84809e28288b5 100644 GIT binary patch delta 925 zcmccbJl9qIG%qg~0}v$N`IvcFnt|alhyw#GP{!xHiRuRR?2HU4j47-+thpRfoM1K^ zkj)jv4Q8_g**sCaj0~xaS#mG~5OkIzf(>J(@T9V@W`gjd*a+#XhiPMANa0Q8glps= zq!CFUUn)0T9~TMw_)~dTyTV+`lOoW<5G9x*2qcA4gn*=QC6h8kDxV5N5hyG;qS#Y7 zqc~H5A(O%##T&`c(^<|?!5qm@&ZsFoxrouZp79n}Ze?*{PJBjwafv3JS6ZA}1my8S z #Rn0W2yhGz4)+gofeE-chB!Jo2D@%{W71}{(RH(mDJaU% zN=+__NiIq(&q*!PEyyWN&&-QSN=(j9%}a?XEy>I&j!8+ UHYa=$F-(ZF{DtLP^-4o0?5V#18P zpLOyW8D)Nah-PHq5dLJrz{03?Lqhoii|7prIS?rWBqeXiXkKEG{J;s6{8cOnbnPSw SCl!W6D!fi6%!iB_fg}KdGwJ96 delta 669 zcmbR1df!?7G%qg~0}ym 5|ulo?XFR2Yhi85vR;v&3M=!0E{c`9zgdSX0 xVOK$N&L;@UxgTwuUTy8PIL|hz0gdCk5gI#ZN=O$)WWG3dN$0ufP zE@9GUR1!`~OwLZtOVKYa$;>I%Pf5}%sJz9No>~&0l2jxQ3`oJvx0!8N7-cp~a5RcA z8f~5> e(1w8Sk_BUS{$A zB*4MQ_DM{bk@vGs9wVd7j}L*23>?Cr7+8QxZU_obmzpRwU2dY>0-hDwmj$gFyimo` zE(@9h#YDxYM@@{H9yc-Wf{Mw8q|2g~4Sr~XxtB# %p@KSh82#c MP72J2 ' + (item.name || item.route_path) + ''; - }).join(''); - } - document.querySelectorAll('#adminTabs .tab').forEach(function (tab) { - tab.onclick = function () { - activateAdminTab(tab.dataset.tab); - }; - }); - var fallbackTab = activeAdminTabName && knownItems.some(function (item) { return item.route_path === activeAdminTabName; }) - ? activeAdminTabName - : knownItems[0].route_path; - activateAdminTab(fallbackTab); - } - function loadAdminMenus(preferredTab) { - if (preferredTab) activeAdminTabName = preferredTab; - fetch('/api/admin/current-user/menus') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - if (adminTabsEl) adminTabsEl.innerHTML = ' 鑿滃崟鍔犺浇澶辫触'; - hideAllAdminPanels(); - return; - } - renderAdminTabs(res.items || []); - }) - .catch(function () { - if (adminTabsEl) adminTabsEl.innerHTML = '鑿滃崟鍔犺浇澶辫触'; - hideAllAdminPanels(); - }); - } - hideAllAdminPanels(); - - // ========== 鐢ㄦ埛绠$悊 ========== - var userPage = 1, userPageSize = 15; - var currentUserId = null; - var currentUserRole = 'admin'; - var currentUserUsername = ''; - var adminsList = []; - function roleLabel(role) { - if (role === 'super_admin') return '瓒呯骇绠$悊鍛?; - if (role === 'admin') return '绠$悊鍛?; - return '鏅€氳处鍙?; - } - function buildUserListQuery(page) { - var q = 'page=' + (page || 1) + '&page_size=' + userPageSize; - var kw = (document.getElementById('searchUsername').value || '').trim(); - if (kw) q += '&username=' + encodeURIComponent(kw); - var cby = document.getElementById('filterCreatedBy').value; - if (cby) q += '&created_by_id=' + encodeURIComponent(cby); - return q; - } - function loadUsers(page) { - userPage = page || 1; - fetch('/api/admin/users?' + buildUserListQuery(userPage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('userListBody'); - if (!res.success) { - tbody.innerHTML = ''; - return; - } - currentUserId = res.current_user_id || null; - currentUserRole = res.current_user_role || 'admin'; - currentUserUsername = (res.current_user_username || '').trim(); - adminsList = res.admins || []; - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (u) { - return ' 鏆傛棤鐢ㄦ埛 '; - }).join(''); - } - renderPagination('userPagination', res.total, res.page, res.page_size, loadUsers); - bindUserActions(); - updateCreateFormByRole(); - updateUserFilterByRole(); - }) - .catch(function () { - document.getElementById('userListBody').innerHTML = ' ' + u.id + ' ' + (u.username || '') + ' ' + - roleLabel(u.role || 'normal') + ' ' + (u.creator_username || '-') + ' ' + (u.created_at || '') + ' ' + - ' ' + - '' + - ' '; - }); - } - function updateUserFilterByRole() { - var grp = document.getElementById('filterCreatedByGroup'); - var sel = document.getElementById('filterCreatedBy'); - if (currentUserRole === 'super_admin') { - grp.style.display = 'block'; - var cur = sel.value; - sel.innerHTML = ''; - adminsList.forEach(function (a) { - var opt = document.createElement('option'); - opt.value = a.id; - opt.textContent = a.username; - sel.appendChild(opt); - }); - sel.value = cur || ''; - } else { - grp.style.display = 'none'; - } - } - - function updateDedupeTotalDataAccess() { - var tab = document.querySelector('.tab[data-tab="dedupe-total-data"]'); - var panel = document.getElementById('panel-dedupe-total-data'); - var canUse = currentUserRole === 'super_admin' || (currentUserRole === 'admin' && currentUserUsername === ''); - if (tab) tab.style.display = canUse ? '' : 'none'; - if (panel) panel.style.display = canUse ? '' : 'none'; - if (!canUse && tab && tab.classList.contains('active')) { - tab.classList.remove('active'); - if (panel) panel.classList.remove('active'); - var usersTab = document.querySelector('.tab[data-tab="users"]'); - var usersPanel = document.getElementById('panel-users'); - if (usersTab) usersTab.classList.add('active'); - if (usersPanel) usersPanel.classList.add('active'); - } - } - function updateShopManageAccess() { - var tab = document.querySelector('.tab[data-tab="shop-manage"]'); - var panel = document.getElementById('panel-shop-manage'); - if (!tab || !panel) return; - var canUse = currentUserRole === 'super_admin' || - !!currentUserAdminPermissionKeys['admin_shop_manage'] || - !!currentUserAdminPermissionRoutes['shop-manage']; - tab.style.display = canUse ? '' : 'none'; - panel.style.display = canUse ? '' : 'none'; - if (!canUse && tab.classList.contains('active')) { - tab.classList.remove('active'); - panel.classList.remove('active'); - var usersTab = document.querySelector('.tab[data-tab="users"]'); - var usersPanel = document.getElementById('panel-users'); - if (usersTab) usersTab.classList.add('active'); - if (usersPanel) usersPanel.classList.add('active'); - } - } - function loadCurrentUserAdminPermissions() { - currentUserAdminPermissionKeys = {}; - currentUserAdminPermissionRoutes = {}; - if (!currentUserId || currentUserRole === 'super_admin') { - updateShopManageAccess(); - return; - } - fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - updateShopManageAccess(); - return; - } - (res.items || []).forEach(function (item) { - var columnKey = (item.column_key || '').trim(); - var routePath = (item.route_path || '').trim(); - if (columnKey) currentUserAdminPermissionKeys[columnKey] = true; - if (routePath) currentUserAdminPermissionRoutes[routePath] = true; - }); - updateShopManageAccess(); - }) - .catch(function () { - updateShopManageAccess(); - }); - } - function applyTabAccess(tabName, canUse) { - var tab = document.querySelector('.tab[data-tab="' + tabName + '"]'); - var panel = document.getElementById('panel-' + tabName); - if (tab) tab.style.display = canUse ? '' : 'none'; - if (panel) panel.style.display = canUse ? '' : 'none'; - if (!canUse && tab && tab.classList.contains('active')) { - tab.classList.remove('active'); - if (panel) panel.classList.remove('active'); - var usersTab = document.querySelector('.tab[data-tab="users"]'); - var usersPanel = document.getElementById('panel-users'); - if (usersTab) usersTab.classList.add('active'); - if (usersPanel) usersPanel.classList.add('active'); - } - } - function hasAdminTabAccess(tabName) { - var config = ADMIN_TAB_ACCESS_CONFIG[tabName]; - if (!config) return true; - if (currentUserRole === 'super_admin') return true; - if (config.superAdminOnly) return false; - return !!currentUserAdminPermissionKeys[config.columnKey] || - !!currentUserAdminPermissionRoutes[config.routePath]; - } - function refreshAdminTabAccess() { - Object.keys(ADMIN_TAB_ACCESS_CONFIG).forEach(function (tabName) { - applyTabAccess(tabName, hasAdminTabAccess(tabName)); - }); - } - function loadCurrentUserAdminPermissions() { - currentUserAdminPermissionKeys = {}; - currentUserAdminPermissionRoutes = {}; - if (!currentUserId || currentUserRole === 'super_admin') { - refreshAdminTabAccess(); - return; - } - fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - refreshAdminTabAccess(); - return; - } - (res.items || []).forEach(function (item) { - var columnKey = (item.column_key || '').trim(); - var routePath = (item.route_path || '').trim(); - if (columnKey) currentUserAdminPermissionKeys[columnKey] = true; - if (routePath) currentUserAdminPermissionRoutes[routePath] = true; - }); - refreshAdminTabAccess(); - }) - .catch(function () { - refreshAdminTabAccess(); - }); - } - var allColumnsList = []; - function loadColumnsForPermission() { - fetch('/api/admin/columns?menu_type=admin') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) return; - allColumnsList = res.items || []; - renderColumnPermissionWrap('createColumnPermissionWrap'); - renderColumnPermissionWrap('editColumnPermissionWrap'); - var selCreate = document.getElementById('createColumnPermissionWrap'); - var selEdit = document.getElementById('editColumnPermissionWrap'); - if (selCreate && !selCreate._colCardsBound) { - selCreate._colCardsBound = true; - selCreate.onchange = function () { renderColumnCards('createColumnPermissionWrap'); }; - } - if (selEdit && !selEdit._colCardsBound) { - selEdit._colCardsBound = true; - selEdit.onchange = function () { renderColumnCards('editColumnPermissionWrap'); }; - } - }) - .catch(function () { }); - } - var columnCardsContainerMap = { createColumnPermissionWrap: 'createColumnCards', editColumnPermissionWrap: 'editColumnCards' }; - function renderColumnCards(selectId) { - var sel = document.getElementById(selectId); - var cardsId = columnCardsContainerMap[selectId]; - var cardsEl = cardsId ? document.getElementById(cardsId) : null; - if (!sel || sel.tagName !== 'SELECT' || !cardsEl) return; - cardsEl.innerHTML = ''; - for (var i = 0; i < sel.options.length; i++) { - var opt = sel.options[i]; - if (opt.disabled || !opt.selected) continue; - var card = document.createElement('span'); - card.className = 'column-permission-card'; - card.textContent = opt.textContent; - var btn = document.createElement('button'); - btn.type = 'button'; - btn.className = 'col-card-remove'; - btn.setAttribute('aria-label', '绉婚櫎'); - btn.textContent = '脳'; - (function (option, seldId) { - btn.onclick = function () { - option.selected = false; - renderColumnCards(seldId); - }; - })(opt, selectId); - card.appendChild(btn); - cardsEl.appendChild(card); - } - } - function renderColumnPermissionWrap(wrapId) { - var sel = document.getElementById(wrapId); - if (!sel || sel.tagName !== 'SELECT') return; - sel.innerHTML = ''; - allColumnsList.forEach(function (c) { - var opt = document.createElement('option'); - opt.value = c.id; - opt.textContent = c.name + ' (' + c.column_key + ')'; - sel.appendChild(opt); - }); - if (allColumnsList.length === 0) { - var opt = document.createElement('option'); - opt.disabled = true; - opt.textContent = '鏆傛棤鑿滃崟锛岃鍏堝湪鈥滄爮鐩潈闄愰厤缃€濅腑鏂板鑿滃崟'; - sel.appendChild(opt); - } - renderColumnCards(wrapId); - } - function getSelectedColumnIds(wrapId) { - var sel = document.getElementById(wrapId); - if (!sel || sel.tagName !== 'SELECT') return []; - var ids = []; - for (var i = 0; i < sel.options.length; i++) { - if (sel.options[i].selected) { - var v = parseInt(sel.options[i].value, 10); - if (!isNaN(v)) ids.push(v); - } - } - return ids; - } - function setColumnPermissionCheckboxes(wrapId, columnIds) { - var sel = document.getElementById(wrapId); - if (!sel || sel.tagName !== 'SELECT') return; - var set = {}; - (columnIds || []).forEach(function (id) { set[id] = true; }); - for (var i = 0; i < sel.options.length; i++) { - var opt = sel.options[i]; - if (opt.disabled) continue; - opt.selected = set[parseInt(opt.value, 10)] || false; - } - renderColumnCards(wrapId); - } - function updateCreateFormByRole() { - var roleSel = document.getElementById('createRole'); - var optAdmin = document.getElementById('optAdmin'); - var formCreatedBy = document.getElementById('formGroupCreatedBy'); - var selCreatedBy = document.getElementById('createCreatedBy'); - if (currentUserRole === 'super_admin') { - if (optAdmin) optAdmin.style.display = ''; - formCreatedBy.style.display = (roleSel.value === 'normal') ? 'block' : 'none'; - selCreatedBy.innerHTML = ''; - (res.items || []).forEach(function (u) { - var opt = document.createElement('option'); - opt.value = u.id; - opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')'; - sel.appendChild(opt); - }); - sel.value = cur || ''; - }); - } - var shopManageGroupUsers = []; - function refreshShopManageGroupUserSelect(selectedUserId) { - var sel = document.getElementById('shopManageGroupUserSelect'); - if (!sel) return; - var opts = ['']; - shopManageGroupUsers.forEach(function (u) { - opts.push(''); - }); - sel.innerHTML = opts.join(''); - if (selectedUserId != null && selectedUserId !== '') { - sel.value = String(selectedUserId); - } - syncShopManageGroupNameWithUser(); - } - function syncShopManageGroupNameWithUser() { - var sel = document.getElementById('shopManageGroupUserSelect'); - var input = document.getElementById('shopManageGroupInput'); - if (!sel || !input) return; - var selectedUser = null; - shopManageGroupUsers.some(function (u) { - if (String(u.id) === String(sel.value || '')) { - selectedUser = u; - return true; - } - return false; - }); - input.value = selectedUser ? (selectedUser.username || '') : ''; - } - function loadUserOptions() { - return fetch('/api/admin/users?page=1&page_size=999') - .then(function (r) { return r.json(); }) - .then(function (res) { - var items = res.items || []; - shopManageGroupUsers = items.map(function (u) { - return { id: u.id, username: u.username || '', role: u.role || 'normal' }; - }); - refreshShopManageGroupUserSelect(document.getElementById('shopManageGroupUserSelect') ? document.getElementById('shopManageGroupUserSelect').value : ''); - var sel = document.getElementById('filterUser'); - var cur = sel.value; - sel.innerHTML = ''; - items.forEach(function (u) { - var opt = document.createElement('option'); - opt.value = u.id; - opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')'; - sel.appendChild(opt); - }); - sel.value = cur || ''; - }); - } - document.getElementById('btnFilterHistory').onclick = function () { loadHistory(1); }; - - // ========== 鏁版嵁鍘婚噸鎬绘暟鎹?========== - var dedupeTotalDataPage = 1, dedupeTotalDataPageSize = 15; - function buildDedupeTotalDataQuery(page) { - var q = 'page=' + (page || 1) + '&page_size=' + dedupeTotalDataPageSize; - var keyword = (document.getElementById('searchDedupeTotalData').value || '').trim(); - if (keyword) q += '&keyword=' + encodeURIComponent(keyword); - return q; - } - function loadDedupeTotalData(page) { - dedupeTotalDataPage = page || 1; - fetch('/api/admin/dedupe-total-data?' + buildDedupeTotalDataQuery(dedupeTotalDataPage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('dedupeTotalDataListBody'); - if (!res.success) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (item) { - return ' 鏆傛棤鎬绘暟鎹?/td> '; - }).join(''); - } - renderPagination('dedupeTotalDataPagination', res.total, res.page, res.page_size, loadDedupeTotalData); - bindDedupeTotalDataActions(); - }) - .catch(function () { - document.getElementById('dedupeTotalDataListBody').innerHTML = ' ' + item.id + ' ' + (item.data_value || '') + ' ' + (item.created_at || '') + ' ' + - ' ' + - '' + - ' '; - }); - } - function bindDedupeTotalDataActions() { - document.querySelectorAll('[data-dedupe-total-edit]').forEach(function (btn) { - btn.onclick = function () { - document.getElementById('editDedupeTotalDataId').value = btn.dataset.dedupeTotalEdit || ''; - document.getElementById('editDedupeTotalDataValue').value = (btn.dataset.value || '').replace(/"/g, '"'); - document.getElementById('msgEditDedupeTotalData').textContent = ''; - document.getElementById('msgEditDedupeTotalData').className = 'msg'; - document.getElementById('editDedupeTotalDataModal').classList.add('show'); - }; - }); - document.querySelectorAll('[data-dedupe-total-delete]').forEach(function (btn) { - btn.onclick = function () { - var value = (btn.dataset.value || '').replace(/"/g, '"'); - if (!confirm('纭畾鍒犻櫎鎬绘暟鎹€? + value + '鈥濆悧锛?)) return; - fetch('/api/admin/dedupe-total-data/' + btn.dataset.dedupeTotalDelete, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { loadDedupeTotalData(dedupeTotalDataPage); } - else { alert(res.error || '鍒犻櫎澶辫触'); } - }); - }; - }); - } - document.getElementById('btnSearchDedupeTotalData').onclick = function () { loadDedupeTotalData(1); }; - var dedupeImportPollTimer = null; - var dedupeDeleteImportPollTimer = null; - function stopDedupeImportProgress() { - if (dedupeImportPollTimer) { - clearInterval(dedupeImportPollTimer); - dedupeImportPollTimer = null; - } - } - function stopDedupeDeleteImportProgress() { - if (dedupeDeleteImportPollTimer) { - clearInterval(dedupeDeleteImportPollTimer); - dedupeDeleteImportPollTimer = null; - } - } - function setDedupeImportProgress(percent, text) { - var wrap = document.getElementById('dedupeTotalDataProgressWrap'); - var fill = document.getElementById('dedupeTotalDataProgressFill'); - var textEl = document.getElementById('dedupeTotalDataProgressText'); - wrap.style.display = 'block'; - fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%'; - textEl.textContent = text || ''; - } - function setDedupeDeleteImportProgress(percent, text) { - var wrap = document.getElementById('dedupeTotalDataDeleteProgressWrap'); - var fill = document.getElementById('dedupeTotalDataDeleteProgressFill'); - var textEl = document.getElementById('dedupeTotalDataDeleteProgressText'); - wrap.style.display = 'block'; - fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%'; - textEl.textContent = text || ''; - } - function pollDedupeImport(importId) { - stopDedupeImportProgress(); - function tick() { - fetch('/api/admin/dedupe-total-data/import/' + encodeURIComponent(importId)) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - stopDedupeImportProgress(); - document.getElementById('msgDedupeTotalData').textContent = res.error || '鏌ヨ瀵煎叆杩涘害澶辫触'; - document.getElementById('msgDedupeTotalData').className = 'msg err'; - return; - } - var progress = res.progress || {}; - var totalRows = progress.total_rows || 0; - var processedRows = progress.processed_rows || 0; - var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0; - setDedupeImportProgress(percent, '澶勭悊涓細宸插鐞?' + processedRows + ' / ' + totalRows + '锛屾柊澧?' + (progress.inserted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0)); - if (progress.status === 'success') { - stopDedupeImportProgress(); - document.getElementById('msgDedupeTotalData').textContent = '瀵煎叆鎴愬姛锛氭€昏鏁?' + (progress.total_rows || 0) + '锛孉SIN 鏁伴噺 ' + (progress.asin_count || 0) + '锛屾柊澧?' + (progress.inserted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0); - document.getElementById('msgDedupeTotalData').className = 'msg ok'; - loadDedupeTotalData(1); - } else if (progress.status === 'failed') { - stopDedupeImportProgress(); - document.getElementById('msgDedupeTotalData').textContent = progress.error_message || '瀵煎叆澶辫触'; - document.getElementById('msgDedupeTotalData').className = 'msg err'; - } - }) - .catch(function () { - stopDedupeImportProgress(); - document.getElementById('msgDedupeTotalData').textContent = '鏌ヨ瀵煎叆杩涘害澶辫触'; - document.getElementById('msgDedupeTotalData').className = 'msg err'; - }); - } - tick(); - dedupeImportPollTimer = setInterval(tick, 1000); - } - function pollDedupeDeleteImport(importId) { - stopDedupeDeleteImportProgress(); - function tick() { - fetch('/api/admin/dedupe-total-data/delete-import/' + encodeURIComponent(importId)) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - stopDedupeDeleteImportProgress(); - document.getElementById('msgDeleteDedupeTotalData').textContent = res.error || '鏌ヨ鍒犻櫎杩涘害澶辫触'; - document.getElementById('msgDeleteDedupeTotalData').className = 'msg err'; - return; - } - var progress = res.progress || {}; - var totalRows = progress.total_rows || 0; - var processedRows = progress.processed_rows || 0; - var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0; - setDedupeDeleteImportProgress(percent, '澶勭悊涓細宸插鐞?' + processedRows + ' / ' + totalRows + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0)); - if (progress.status === 'success') { - stopDedupeDeleteImportProgress(); - document.getElementById('msgDeleteDedupeTotalData').textContent = '鍒犻櫎鎴愬姛锛氭€昏鏁?' + (progress.total_rows || 0) + '锛孉SIN 鏁伴噺 ' + (progress.asin_count || 0) + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0); - document.getElementById('msgDeleteDedupeTotalData').className = 'msg ok'; - loadDedupeTotalData(1); - } else if (progress.status === 'failed') { - stopDedupeDeleteImportProgress(); - document.getElementById('msgDeleteDedupeTotalData').textContent = progress.error_message || '鍒犻櫎澶辫触'; - document.getElementById('msgDeleteDedupeTotalData').className = 'msg err'; - } - }) - .catch(function () { - stopDedupeDeleteImportProgress(); - document.getElementById('msgDeleteDedupeTotalData').textContent = '鏌ヨ鍒犻櫎杩涘害澶辫触'; - document.getElementById('msgDeleteDedupeTotalData').className = 'msg err'; - }); - } - tick(); - dedupeDeleteImportPollTimer = setInterval(tick, 1000); - } - - document.getElementById('btnAddDedupeTotalData').onclick = function () { - var fileInput = document.getElementById('dedupeTotalDataFile'); - var msgEl = document.getElementById('msgDedupeTotalData'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - stopDedupeImportProgress(); - document.getElementById('dedupeTotalDataProgressWrap').style.display = 'none'; - if (!fileInput.files || fileInput.files.length === 0) { - msgEl.textContent = '璇烽€夋嫨 Excel 鏂囦欢'; - msgEl.classList.add('err'); - return; - } - var file = fileInput.files[0]; - var lowerName = (file.name || '').toLowerCase(); - if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) { - msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢'; - msgEl.classList.add('err'); - return; - } - var formData = new FormData(); - formData.append('file', file); - var xhr = new XMLHttpRequest(); - xhr.open('POST', '/api/admin/dedupe-total-data/import', true); - xhr.upload.onprogress = function (event) { - if (event.lengthComputable) { - var percent = Math.round(event.loaded * 100 / event.total); - setDedupeImportProgress(percent, '涓婁紶涓細' + percent + '%'); - } - }; - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4) return; - if (xhr.status < 200 || xhr.status >= 300) { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - return; - } - var res; - try { res = JSON.parse(xhr.responseText || '{}'); } catch (e) { res = { success: false, error: '杩斿洖鏍煎紡閿欒' }; } - if (!res.success) { - msgEl.textContent = res.error || '瀵煎叆澶辫触'; - msgEl.className = 'msg err'; - return; - } - setDedupeImportProgress(100, '涓婁紶瀹屾垚锛屽悗绔鐞嗕腑...'); - pollDedupeImport(res.import_id); - fileInput.value = ''; - }; - xhr.onerror = function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }; - xhr.send(formData); - }; - document.getElementById('btnDeleteImportDedupeTotalData').onclick = function () { - var fileInput = document.getElementById('dedupeTotalDataDeleteFile'); - var msgEl = document.getElementById('msgDeleteDedupeTotalData'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - stopDedupeDeleteImportProgress(); - document.getElementById('dedupeTotalDataDeleteProgressWrap').style.display = 'none'; - if (!fileInput.files || fileInput.files.length === 0) { - msgEl.textContent = '璇烽€夋嫨 Excel 鏂囦欢'; - msgEl.classList.add('err'); - return; - } - var file = fileInput.files[0]; - var lowerName = (file.name || '').toLowerCase(); - if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) { - msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢'; - msgEl.classList.add('err'); - return; - } - if (!confirm('纭畾鎸?Excel 涓殑 ASIN 鎵归噺鍒犻櫎鍖归厤鐨勬€绘暟鎹悧锛?)) { - return; - } - var formData = new FormData(); - formData.append('file', file); - var xhr = new XMLHttpRequest(); - xhr.open('POST', '/api/admin/dedupe-total-data/delete-import', true); - xhr.upload.onprogress = function (event) { - if (event.lengthComputable) { - var percent = Math.round(event.loaded * 100 / event.total); - setDedupeDeleteImportProgress(percent, '涓婁紶涓細' + percent + '%'); - } - }; - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4) return; - if (xhr.status < 200 || xhr.status >= 300) { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - return; - } - var res; - try { res = JSON.parse(xhr.responseText || '{}'); } catch (e) { res = { success: false, error: '杩斿洖鏍煎紡閿欒' }; } - if (!res.success) { - msgEl.textContent = res.error || '鍒犻櫎澶辫触'; - msgEl.className = 'msg err'; - return; - } - setDedupeDeleteImportProgress(100, '涓婁紶瀹屾垚锛屽悗绔鐞嗕腑...'); - pollDedupeDeleteImport(res.import_id); - fileInput.value = ''; - }; - xhr.onerror = function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }; - xhr.send(formData); - }; - document.getElementById('btnSaveDedupeTotalData').onclick = function () { - var itemId = document.getElementById('editDedupeTotalDataId').value; - var value = (document.getElementById('editDedupeTotalDataValue').value || '').trim(); - var msgEl = document.getElementById('msgEditDedupeTotalData'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!value) { - msgEl.textContent = '璇峰~鍐欐€绘暟鎹€?; - msgEl.classList.add('err'); - return; - } - fetch('/api/admin/dedupe-total-data/' + itemId, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ data_value: value }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - document.getElementById('editDedupeTotalDataModal').classList.remove('show'); - loadDedupeTotalData(dedupeTotalDataPage); - } else { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.classList.add('err'); - } - }); - }; - document.getElementById('btnCloseEditDedupeTotalData').onclick = function () { - document.getElementById('editDedupeTotalDataModal').classList.remove('show'); - }; - - // ========== 搴楅摵瀵嗛挜绠$悊 ========== - var shopKeyPage = 1, shopKeyPageSize = 15; - function buildShopKeyQuery(page) { - return 'page=' + (page || 1) + '&page_size=' + shopKeyPageSize; - } - function loadShopKeys(page) { - shopKeyPage = page || 1; - fetch('/api/admin/shop-keys?' + buildShopKeyQuery(shopKeyPage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('shopKeyListBody'); - if (!res.success) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (item, index) { - var rowNo = (shopKeyPage - 1) * shopKeyPageSize + index + 1; - return ' 鏆傛棤搴楅摵瀵嗛挜 '; - }).join(''); - } - renderPagination('shopKeyPagination', res.total, res.page, res.page_size, loadShopKeys); - bindShopKeyActions(); - }) - .catch(function () { - document.getElementById('shopKeyListBody').innerHTML = ' ' + rowNo + ' ' + (item.ziniao_account_name || '') + ' ' + (item.ziniao_token || '') + ' ' + (item.created_at || '') + ' ' + (item.updated_at || '') + ' ' + - ' ' + - '' + - ' '; - }); - } - function bindShopKeyActions() { - document.querySelectorAll('[data-shop-key-edit]').forEach(function (btn) { - btn.onclick = function () { - var item = {}; - try { item = JSON.parse((btn.dataset.shopKey || '').replace(/"/g, '"')); } catch (e) { item = {}; } - document.getElementById('editShopKeyId').value = item.id || ''; - document.getElementById('editShopKeyZiniaoAccountName').value = item.ziniao_account_name || ''; - document.getElementById('editShopKeyZiniaoToken').value = item.ziniao_token || ''; - document.getElementById('msgEditShopKey').textContent = ''; - document.getElementById('msgEditShopKey').className = 'msg'; - document.getElementById('editShopKeyModal').classList.add('show'); - }; - }); - document.querySelectorAll('[data-shop-key-delete]').forEach(function (btn) { - btn.onclick = function () { - var name = (btn.dataset.ziniaoAccountName || '').replace(/"/g, '"'); - if (!confirm('纭畾鍒犻櫎搴楅摵瀵嗛挜鈥? + name + '鈥濆悧锛?)) return; - fetch('/api/admin/shop-key/' + btn.dataset.shopKeyDelete, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { loadShopKeys(shopKeyPage); } - else { alert(res.error || '鍒犻櫎澶辫触'); } - }); - }; - }); - } - document.getElementById('btnCreateShopKey').onclick = function () { - var ziniaoAccountName = (document.getElementById('shopKeyZiniaoAccountName').value || '').trim(); - var ziniaoToken = (document.getElementById('shopKeyZiniaoToken').value || '').trim(); - var msgEl = document.getElementById('msgShopKey'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!ziniaoAccountName || !ziniaoToken) { - msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?; - msgEl.classList.add('err'); - return; - } - fetch('/api/admin/shop-key', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - ziniao_account_name: ziniaoAccountName, - ziniao_token: ziniaoToken - }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - document.getElementById('shopKeyZiniaoAccountName').value = ''; - document.getElementById('shopKeyZiniaoToken').value = ''; - msgEl.textContent = res.msg || '鍒涘缓鎴愬姛'; - msgEl.className = 'msg ok'; - loadShopKeys(1); - } else { - msgEl.textContent = res.error || '鍒涘缓澶辫触'; - msgEl.className = 'msg err'; - } - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }); - }; - document.getElementById('btnSaveShopKey').onclick = function () { - var itemId = document.getElementById('editShopKeyId').value; - var ziniaoAccountName = (document.getElementById('editShopKeyZiniaoAccountName').value || '').trim(); - var ziniaoToken = (document.getElementById('editShopKeyZiniaoToken').value || '').trim(); - var msgEl = document.getElementById('msgEditShopKey'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!ziniaoAccountName || !ziniaoToken) { - msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?; - msgEl.classList.add('err'); - return; - } - fetch('/api/admin/shop-key/' + itemId, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - ziniao_account_name: ziniaoAccountName, - ziniao_token: ziniaoToken - }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - document.getElementById('editShopKeyModal').classList.remove('show'); - loadShopKeys(shopKeyPage); - } else { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.classList.add('err'); - } - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.classList.add('err'); - }); - }; - document.getElementById('btnCloseEditShopKey').onclick = function () { - document.getElementById('editShopKeyModal').classList.remove('show'); - }; - - // ========== 搴楅摵绠$悊 ========== - var shopManagePage = 1, shopManagePageSize = 15; - var shopManageGroups = []; - - function buildShopManageQuery(page) { - var query = 'page=' + (page || 1) + '&page_size=' + shopManagePageSize; - var groupId = (document.getElementById('shopManageFilterGroupId').value || '').trim(); - var shopName = (document.getElementById('shopManageFilterShopName').value || '').trim(); - if (groupId) query += '&group_id=' + encodeURIComponent(groupId); - if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); - return query; - } - - function refreshShopGroupSelects(selectedCreateId, selectedEditId) { - var createSel = document.getElementById('shopManageGroupSelect'); - var editSel = document.getElementById('editShopManageGroupSelect'); - var filterSel = document.getElementById('shopManageFilterGroupId'); - var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect'); - var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId'); - var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId'); - var selectedFilterId = filterSel ? filterSel.value : ''; - var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : ''; - var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : ''; - var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : ''; - var createOpts = ['']; - var filterOpts = ['']; - shopManageGroups.forEach(function (g) { - var option = ''; - createOpts.push(option); - filterOpts.push(option); - }); - createSel.innerHTML = createOpts.join(''); - editSel.innerHTML = createOpts.join(''); - if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join(''); - if (filterSel) filterSel.innerHTML = filterOpts.join(''); - if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join(''); - if (chooseSkipShopSel) chooseSkipShopSel.innerHTML = filterOpts.join(''); - if (selectedCreateId != null) createSel.value = String(selectedCreateId); - if (selectedEditId != null) editSel.value = String(selectedEditId); - if (filterSel && selectedFilterId) filterSel.value = selectedFilterId; - if (skipCreateSel && selectedSkipCreateId) skipCreateSel.value = selectedSkipCreateId; - if (skipFilterSel && selectedSkipFilterId) skipFilterSel.value = selectedSkipFilterId; - if (chooseSkipShopSel && selectedChooseSkipShopId) chooseSkipShopSel.value = selectedChooseSkipShopId; - } - - function loadShopManageGroups(selectedCreateId, selectedEditId) { - return fetch('/api/admin/shop-manage-groups') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触'); - shopManageGroups = res.items || []; - refreshShopGroupSelects(selectedCreateId, selectedEditId); - return shopManageGroups; - }) - .catch(function () { - shopManageGroups = []; - refreshShopGroupSelects(); - return []; - }); - } - - function openShopManageGroupModal() { - document.getElementById('shopManageGroupEditId').value = ''; - document.getElementById('shopManageGroupInput').value = ''; - document.getElementById('msgShopManageGroup').textContent = ''; - document.getElementById('msgShopManageGroup').className = 'msg'; - loadShopManageGroups().then(function () { - renderShopManageGroupRows(); - document.getElementById('shopManageGroupModal').classList.add('show'); - }); - } - - function renderShopManageGroupRows() { - var tbody = document.getElementById('shopManageGroupListBody'); - if (!shopManageGroups.length) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - tbody.innerHTML = shopManageGroups.map(function (item, index) { - return ' 鏆傛棤鍒嗙粍 '; - }).join(''); - - document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) { - btn.onclick = function () { - document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit; - document.getElementById('shopManageGroupInput').value = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); - }; - }); - - document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) { - btn.onclick = function () { - var gid = btn.dataset.shopGroupDelete; - var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); - if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return; - fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - alert(res.error || '鍒犻櫎澶辫触'); - return; - } - loadShopManageGroups().then(function () { - renderShopManageGroupRows(); - loadShopManage(shopManagePage); - loadSkipPriceAsin(skipPriceAsinPage); - }); - }); - }; - }); - } - - function loadShopManage(page) { - shopManagePage = page || 1; - fetch('/api/admin/shop-manages?' + buildShopManageQuery(shopManagePage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('shopManageListBody'); - if (!res.success) { - tbody.innerHTML = ' ' + (index + 1) + ' ' + (item.group_name || '') + ' ' + (item.created_at || '') + ' ' + (item.updated_at || '') + ' ' + - ' ' + - '' + - ' '; - return; - } - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (item, index) { - var rowNo = (shopManagePage - 1) * shopManagePageSize + index + 1; - return ' 鏆傛棤搴楅摵 '; - }).join(''); - } - renderPagination('shopManagePagination', res.total, res.page, res.page_size, loadShopManage); - bindShopManageActions(); - }) - .catch(function () { - document.getElementById('shopManageListBody').innerHTML = ' ' + rowNo + ' ' + (item.group_name || '') + ' ' + (item.shop_name || '') + ' ' + (item.mall_name || '') + ' ' + (item.account || '') + ' ' + (item.password || '') + ' ' + (item.created_at || '') + ' ' + (item.updated_at || '') + ' ' + - ' ' + - '' + - ' '; - }); - } - - function bindShopManageActions() { - document.querySelectorAll('[data-shop-manage-edit]').forEach(function (btn) { - btn.onclick = function () { - var item = {}; - try { item = JSON.parse((btn.dataset.shopManage || '').replace(/"/g, '"')); } catch (e) { item = {}; } - document.getElementById('editShopManageId').value = item.id || ''; - document.getElementById('editShopManageShopName').value = item.shop_name || ''; - document.getElementById('editShopManageMallName').value = item.mall_name || ''; - document.getElementById('editShopManageAccount').value = item.account || ''; - document.getElementById('editShopManagePassword').value = item.password || ''; - document.getElementById('msgEditShopManage').textContent = ''; - document.getElementById('msgEditShopManage').className = 'msg'; - loadShopManageGroups(null, item.group_id).then(function () { - document.getElementById('editShopManageModal').classList.add('show'); - }); - }; - }); - document.querySelectorAll('[data-shop-manage-delete]').forEach(function (btn) { - btn.onclick = function () { - var name = (btn.dataset.shopManageName || '').replace(/"/g, '"'); - if (!confirm('纭畾鍒犻櫎搴楅摵鈥? + name + '鈥濆悧锛?)) return; - fetch('/api/admin/shop-manage/' + btn.dataset.shopManageDelete, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { loadShopManage(shopManagePage); } - else { alert(res.error || '鍒犻櫎澶辫触'); } - }); - }; - }); - } - - document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal; - document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal; - document.getElementById('btnSearchShopManage').onclick = function () { - loadShopManage(1); - }; - document.getElementById('shopManageFilterShopName').addEventListener('keydown', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - loadShopManage(1); - } - }); - document.getElementById('btnCloseShopManageGroupModal').onclick = function () { - document.getElementById('shopManageGroupModal').classList.remove('show'); - }; - document.getElementById('btnCancelShopManageGroupEdit').onclick = function () { - document.getElementById('shopManageGroupEditId').value = ''; - document.getElementById('shopManageGroupInput').value = ''; - }; - document.getElementById('btnSaveShopManageGroup').onclick = function () { - var editId = (document.getElementById('shopManageGroupEditId').value || '').trim(); - var groupName = (document.getElementById('shopManageGroupInput').value || '').trim(); - var msgEl = document.getElementById('msgShopManageGroup'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!groupName) { - msgEl.textContent = '璇疯緭鍏ュ垎缁勫悕绉?; - msgEl.className = 'msg err'; - return; - } - var method = editId ? 'PUT' : 'POST'; - var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group'; - fetch(url, { - method: method, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ group_name: groupName }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.className = 'msg err'; - return; - } - document.getElementById('shopManageGroupEditId').value = ''; - document.getElementById('shopManageGroupInput').value = ''; - msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; - msgEl.className = 'msg ok'; - loadShopManageGroups().then(function () { - renderShopManageGroupRows(); - loadShopManage(shopManagePage); - loadSkipPriceAsin(skipPriceAsinPage); - }); - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }); - }; - - function refreshShopGroupSelects(selectedCreateId, selectedEditId) { - var createSel = document.getElementById('shopManageGroupSelect'); - var editSel = document.getElementById('editShopManageGroupSelect'); - var filterSel = document.getElementById('shopManageFilterGroupId'); - var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect'); - var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId'); - var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId'); - var selectedFilterId = filterSel ? filterSel.value : ''; - var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : ''; - var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : ''; - var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : ''; - var createOpts = ['']; - var filterOpts = ['']; - shopManageGroups.forEach(function (g) { - var option = ''; - createOpts.push(option); - filterOpts.push(option); - }); - createSel.innerHTML = createOpts.join(''); - editSel.innerHTML = createOpts.join(''); - if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join(''); - if (filterSel) filterSel.innerHTML = filterOpts.join(''); - if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join(''); - if (chooseSkipShopSel) chooseSkipShopSel.innerHTML = filterOpts.join(''); - if (selectedCreateId != null) createSel.value = String(selectedCreateId); - if (selectedEditId != null) editSel.value = String(selectedEditId); - if (filterSel && selectedFilterId) filterSel.value = selectedFilterId; - if (skipCreateSel && selectedSkipCreateId) skipCreateSel.value = selectedSkipCreateId; - if (skipFilterSel && selectedSkipFilterId) skipFilterSel.value = selectedSkipFilterId; - if (chooseSkipShopSel && selectedChooseSkipShopId) chooseSkipShopSel.value = selectedChooseSkipShopId; - } - - function loadShopManageGroups(selectedCreateId, selectedEditId) { - return fetch('/api/admin/shop-manage-groups') - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触'); - shopManageGroups = res.items || []; - refreshShopGroupSelects(selectedCreateId, selectedEditId); - return shopManageGroups; - }) - .catch(function () { - shopManageGroups = []; - refreshShopGroupSelects(); - return []; - }); - } - - function resetShopManageGroupForm() { - document.getElementById('shopManageGroupEditId').value = ''; - document.getElementById('shopManageGroupInput').value = ''; - document.getElementById('msgShopManageGroup').textContent = ''; - document.getElementById('msgShopManageGroup').className = 'msg'; - refreshShopManageGroupUserSelect(''); - } - - function openShopManageGroupModal() { - resetShopManageGroupForm(); - loadUserOptions() - .then(function () { return loadShopManageGroups(); }) - .then(function () { - renderShopManageGroupRows(); - document.getElementById('shopManageGroupModal').classList.add('show'); - }); - } - - function renderShopManageGroupRows() { - var tbody = document.getElementById('shopManageGroupListBody'); - if (!shopManageGroups.length) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - tbody.innerHTML = shopManageGroups.map(function (item, index) { - return ' 鏆傛棤鍒嗙粍 '; - }).join(''); - - document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) { - btn.onclick = function () { - document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit; - refreshShopManageGroupUserSelect(btn.dataset.shopGroupUserId || ''); - }; - }); - - document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) { - btn.onclick = function () { - var gid = btn.dataset.shopGroupDelete; - var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); - if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return; - fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - alert(res.error || '鍒犻櫎澶辫触'); - return; - } - loadShopManageGroups().then(function () { - renderShopManageGroupRows(); - loadShopManage(shopManagePage); - loadSkipPriceAsin(skipPriceAsinPage); - }); - }); - }; - }); - } - - document.getElementById('shopManageGroupUserSelect').onchange = syncShopManageGroupNameWithUser; - document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal; - document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal; - document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal; - document.getElementById('btnCloseShopManageGroupModal').onclick = function () { - document.getElementById('shopManageGroupModal').classList.remove('show'); - }; - document.getElementById('btnCancelShopManageGroupEdit').onclick = resetShopManageGroupForm; - document.getElementById('btnSaveShopManageGroup').onclick = function () { - var editId = (document.getElementById('shopManageGroupEditId').value || '').trim(); - var groupName = (document.getElementById('shopManageGroupInput').value || '').trim(); - var userId = (document.getElementById('shopManageGroupUserSelect').value || '').trim(); - var msgEl = document.getElementById('msgShopManageGroup'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!userId || !groupName) { - msgEl.textContent = '璇烽€夋嫨鍏宠仈鐢ㄦ埛'; - msgEl.className = 'msg err'; - return; - } - var method = editId ? 'PUT' : 'POST'; - var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group'; - fetch(url, { - method: method, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ group_name: groupName, user_id: Number(userId) }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.className = 'msg err'; - return; - } - resetShopManageGroupForm(); - msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; - msgEl.className = 'msg ok'; - loadShopManageGroups().then(function () { - renderShopManageGroupRows(); - loadShopManage(shopManagePage); - loadSkipPriceAsin(skipPriceAsinPage); - }); - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }); - }; - - document.getElementById('btnCreateShopManage').onclick = function () { - var groupId = (document.getElementById('shopManageGroupSelect').value || '').trim(); - var shopName = (document.getElementById('shopManageShopName').value || '').trim(); - var mallName = (document.getElementById('shopManageMallName').value || '').trim(); - var account = (document.getElementById('shopManageAccount').value || '').trim(); - var password = (document.getElementById('shopManagePassword').value || '').trim(); - var msgEl = document.getElementById('msgShopManage'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!groupId || !shopName || !mallName || !account || !password) { - msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?; - msgEl.classList.add('err'); - return; - } - fetch('/api/admin/shop-manage', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - document.getElementById('shopManageGroupSelect').value = ''; - document.getElementById('shopManageShopName').value = ''; - document.getElementById('shopManageMallName').value = ''; - document.getElementById('shopManageAccount').value = ''; - document.getElementById('shopManagePassword').value = ''; - msgEl.textContent = res.msg || '鍒涘缓鎴愬姛'; - msgEl.className = 'msg ok'; - loadShopManage(1); - } else { - msgEl.textContent = res.error || '鍒涘缓澶辫触'; - msgEl.className = 'msg err'; - } - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }); - }; - - document.getElementById('btnSaveShopManage').onclick = function () { - var itemId = document.getElementById('editShopManageId').value; - var groupId = (document.getElementById('editShopManageGroupSelect').value || '').trim(); - var shopName = (document.getElementById('editShopManageShopName').value || '').trim(); - var mallName = (document.getElementById('editShopManageMallName').value || '').trim(); - var account = (document.getElementById('editShopManageAccount').value || '').trim(); - var password = (document.getElementById('editShopManagePassword').value || '').trim(); - var msgEl = document.getElementById('msgEditShopManage'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!groupId || !shopName || !mallName || !account || !password) { - msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?; - msgEl.classList.add('err'); - return; - } - fetch('/api/admin/shop-manage/' + itemId, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - document.getElementById('editShopManageModal').classList.remove('show'); - loadShopManage(shopManagePage); - } else { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.classList.add('err'); - } - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.classList.add('err'); - }); - }; - document.getElementById('btnCloseEditShopManage').onclick = function () { - document.getElementById('editShopManageModal').classList.remove('show'); - }; - - // ========== 鐗堟湰绠$悊 ========== - // ========== 璺宠繃璺熶环 ASIN ========== - var skipPriceAsinPage = 1, skipPriceAsinPageSize = 15; - var chooseSkipPriceAsinShopPage = 1, chooseSkipPriceAsinShopPageSize = 10; - var skipPriceCountryColumns = [ - { code: 'DE', field: 'asin_de', label: '寰峰浗' }, - { code: 'UK', field: 'asin_uk', label: '鑻卞浗' }, - { code: 'FR', field: 'asin_fr', label: '娉曞浗' }, - { code: 'IT', field: 'asin_it', label: '鎰忓ぇ鍒? }, - { code: 'ES', field: 'asin_es', label: '瑗跨彮鐗? } - ]; - function buildChooseSkipPriceAsinShopQuery(page) { - var query = 'page=' + (page || 1) + '&page_size=' + chooseSkipPriceAsinShopPageSize; - var groupId = (document.getElementById('chooseSkipPriceAsinShopGroupId').value || '').trim(); - var shopName = (document.getElementById('chooseSkipPriceAsinShopKeyword').value || '').trim(); - if (groupId) query += '&group_id=' + encodeURIComponent(groupId); - if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); - return query; - } - function loadChooseSkipPriceAsinShops(page) { - chooseSkipPriceAsinShopPage = page || 1; - fetch('/api/admin/shop-manages?' + buildChooseSkipPriceAsinShopQuery(chooseSkipPriceAsinShopPage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('chooseSkipPriceAsinShopListBody'); - if (!res.success) { - tbody.innerHTML = ' ' + (index + 1) + ' ' + (item.group_name || '') + ' ' + (item.username || '') + ' ' + (item.created_at || '') + ' ' + (item.updated_at || '') + ' ' + - ' ' + - '' + - ' '; - return; - } - var items = res.items || []; - if (!items.length) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (item, index) { - var rowNo = (chooseSkipPriceAsinShopPage - 1) * chooseSkipPriceAsinShopPageSize + index + 1; - return ' 鏆傛棤搴楅摵 '; - }).join(''); - } - renderPagination('chooseSkipPriceAsinShopPagination', res.total, res.page, res.page_size, loadChooseSkipPriceAsinShops); - bindChooseSkipPriceAsinShopActions(); - }) - .catch(function () { - document.getElementById('chooseSkipPriceAsinShopListBody').innerHTML = ' ' + rowNo + ' ' + (item.group_name || '') + ' ' + (item.shop_name || '') + ' ' + (item.mall_name || '') + ' ' + (item.account || '') + ' ' + - '' + - ' '; - }); - } - function bindChooseSkipPriceAsinShopActions() { - document.querySelectorAll('[data-choose-skip-price-asin-shop]').forEach(function (btn) { - btn.onclick = function () { - document.getElementById('skipPriceAsinShopName').value = (btn.dataset.shopName || '').replace(/"/g, '"'); - if (!document.getElementById('skipPriceAsinGroupSelect').value && btn.dataset.groupId) { - document.getElementById('skipPriceAsinGroupSelect').value = btn.dataset.groupId; - } - document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show'); - }; - }); - } - function openChooseSkipPriceAsinShopModal() { - var currentGroupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim(); - if (currentGroupId) { - document.getElementById('chooseSkipPriceAsinShopGroupId').value = currentGroupId; - } - document.getElementById('chooseSkipPriceAsinShopKeyword').value = (document.getElementById('skipPriceAsinShopName').value || '').trim(); - document.getElementById('chooseSkipPriceAsinShopModal').classList.add('show'); - loadChooseSkipPriceAsinShops(1); - } - function setupSkipPriceAsinShopPicker() { - var input = document.getElementById('skipPriceAsinShopName'); - var button = document.getElementById('btnChooseSkipPriceAsinShop'); - if (!input || !button) return; - var inputParent = input.parentNode; - if (inputParent && inputParent.style && inputParent.style.display === 'flex') return; - var legacyWrap = button.parentNode; - var wrapper = document.createElement('div'); - wrapper.style.display = 'flex'; - wrapper.style.gap = '8px'; - wrapper.style.alignItems = 'center'; - input.parentNode.insertBefore(wrapper, input); - wrapper.appendChild(input); - wrapper.appendChild(button); - button.style.whiteSpace = 'nowrap'; - button.style.marginTop = '0'; - if (legacyWrap && legacyWrap !== wrapper) { - legacyWrap.style.display = 'none'; - } - } - function getSelectedSkipPriceCountries() { - return Array.from(document.getElementById('skipPriceAsinCountries').selectedOptions).map(function (option) { - return option.value; - }); - } - function renderSkipPriceAsinInputs() { - var container = document.getElementById('skipPriceAsinInputs'); - var selectedCountries = getSelectedSkipPriceCountries(); - var existingValues = {}; - container.querySelectorAll('[data-skip-price-country-input]').forEach(function (input) { - existingValues[input.getAttribute('data-skip-price-country-input')] = input.value; - }); - if (!selectedCountries.length) { - container.innerHTML = ' 璇锋眰澶辫触 璇烽€夋嫨鍥藉鍚庤緭鍏?ASIN'; - return; - } - container.innerHTML = selectedCountries.map(function (countryCode) { - var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; }); - var label = country ? country.label : countryCode; - var value = existingValues[countryCode] || ''; - return '' + - '' + label + '' + - '' + - ''; - }).join(''); - } - function collectSkipPriceAsinMappings(countries) { - var mappings = {}; - for (var i = 0; i < countries.length; i++) { - var countryCode = countries[i]; - var input = document.querySelector('[data-skip-price-country-input="' + countryCode + '"]'); - var asin = input ? (input.value || '').trim().toUpperCase() : ''; - if (!asin) { - var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; }); - var label = country ? country.label : countryCode; - throw new Error(label + ' ASIN 涓嶈兘涓虹┖'); - } - mappings[countryCode] = asin; - } - return mappings; - } - function buildSkipPriceAsinQuery(page) { - var query = 'page=' + (page || 1) + '&page_size=' + skipPriceAsinPageSize; - var groupId = (document.getElementById('skipPriceAsinFilterGroupId').value || '').trim(); - var shopName = (document.getElementById('skipPriceAsinFilterShopName').value || '').trim(); - var asin = (document.getElementById('skipPriceAsinFilterAsin').value || '').trim(); - if (groupId) query += '&group_id=' + encodeURIComponent(groupId); - if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); - if (asin) query += '&asin=' + encodeURIComponent(asin); - return query; - } - function renderSkipPriceAsinCell(item, country) { - var value = item[country.field] || ''; - if (!value) return '-'; - return '' + - '' + value + '' + - '' + - '' + - ''; - } - function bindSkipPriceAsinActions() { - document.querySelectorAll('[data-skip-price-asin-edit]').forEach(function (btn) { - btn.onclick = function () { - var shopName = (btn.dataset.shopName || '').replace(/"/g, '"'); - var countryCode = btn.dataset.country || ''; - var currentAsin = (btn.dataset.asin || '').replace(/"/g, '"'); - var nextAsin = prompt('璇疯緭鍏ュ簵閾衡€? + shopName + '鈥濆湪 ' + countryCode + ' 鐨?ASIN', currentAsin); - if (nextAsin === null) return; - nextAsin = (nextAsin || '').trim(); - if (!nextAsin) { - alert('ASIN 涓嶈兘涓虹┖'); - return; - } - fetch('/api/admin/skip-price-asin/' + btn.dataset.skipPriceAsinEdit + '/country/' + countryCode, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ asin: nextAsin }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) loadSkipPriceAsin(skipPriceAsinPage); - else alert(res.error || '淇濆瓨澶辫触'); - }); - }; - }); - document.querySelectorAll('[data-skip-price-asin-delete]').forEach(function (btn) { - btn.onclick = function () { - var shopName = (btn.dataset.shopName || '').replace(/"/g, '"'); - var countryCode = btn.dataset.country || ''; - if (!confirm('纭畾鍒犻櫎搴楅摵鈥? + shopName + '鈥濆湪 ' + countryCode + ' 鐨?ASIN 鍚楋紵')) return; - fetch('/api/admin/skip-price-asin/' + btn.dataset.skipPriceAsinDelete + '/country/' + countryCode, { - method: 'DELETE' - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) loadSkipPriceAsin(skipPriceAsinPage); - else alert(res.error || '鍒犻櫎澶辫触'); - }); - }; - }); - } - function loadSkipPriceAsin(page) { - skipPriceAsinPage = page || 1; - fetch('/api/admin/skip-price-asins?' + buildSkipPriceAsinQuery(skipPriceAsinPage)) - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('skipPriceAsinListBody'); - if (!res.success) { - tbody.innerHTML = ''; - return; - } - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (item, index) { - var rowNo = (skipPriceAsinPage - 1) * skipPriceAsinPageSize + index + 1; - return ' 鏆傛棤鏁版嵁 '; - }).join(''); - } - renderPagination('skipPriceAsinPagination', res.total, res.page, res.page_size, loadSkipPriceAsin); - bindSkipPriceAsinActions(); - }) - .catch(function () { - document.getElementById('skipPriceAsinListBody').innerHTML = ' ' + rowNo + ' ' + (item.group_name || '') + ' ' + (item.shop_name || '') + ' ' + - skipPriceCountryColumns.map(function (country) { - return '' + renderSkipPriceAsinCell(item, country) + ' '; - }).join('') + - ''; - }); - } - document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal; - document.getElementById('btnChooseSkipPriceAsinShop').onclick = openChooseSkipPriceAsinShopModal; - document.getElementById('btnSearchChooseSkipPriceAsinShop').onclick = function () { - loadChooseSkipPriceAsinShops(1); - }; - document.getElementById('chooseSkipPriceAsinShopGroupId').onchange = function () { - loadChooseSkipPriceAsinShops(1); - }; - document.getElementById('chooseSkipPriceAsinShopKeyword').addEventListener('keydown', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - loadChooseSkipPriceAsinShops(1); - } - }); - document.getElementById('btnCloseChooseSkipPriceAsinShopModal').onclick = function () { - document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show'); - }; - document.getElementById('skipPriceAsinCountries').addEventListener('change', renderSkipPriceAsinInputs); - document.getElementById('btnSearchSkipPriceAsin').onclick = function () { - loadSkipPriceAsin(1); - }; - document.getElementById('skipPriceAsinFilterShopName').addEventListener('keydown', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - loadSkipPriceAsin(1); - } - }); - document.getElementById('skipPriceAsinFilterAsin').addEventListener('keydown', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - loadSkipPriceAsin(1); - } - }); - document.getElementById('btnCreateSkipPriceAsin').onclick = function () { - var groupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim(); - var shopName = (document.getElementById('skipPriceAsinShopName').value || '').trim(); - var countries = getSelectedSkipPriceCountries(); - var msgEl = document.getElementById('msgSkipPriceAsin'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!groupId || !shopName || !countries.length) { - msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸浗瀹跺拰 ASIN'; - msgEl.className = 'msg err'; - return; - } - var asinMappings = {}; - try { - asinMappings = collectSkipPriceAsinMappings(countries); - } catch (err) { - msgEl.textContent = err.message || '璇疯緭鍏?ASIN'; - msgEl.className = 'msg err'; - return; - } - var fallbackAsin = ''; - Object.keys(asinMappings).some(function (countryCode) { - fallbackAsin = asinMappings[countryCode] || ''; - return !!fallbackAsin; - }); - fetch('/api/admin/skip-price-asin', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - group_id: Number(groupId), - shop_name: shopName, - countries: countries, - asin: fallbackAsin, - asin_mappings: asinMappings - }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (!res.success) { - msgEl.textContent = res.error || '淇濆瓨澶辫触'; - msgEl.className = 'msg err'; - return; - } - document.getElementById('skipPriceAsinGroupSelect').value = ''; - document.getElementById('skipPriceAsinShopName').value = ''; - Array.from(document.getElementById('skipPriceAsinCountries').options).forEach(function (option) { - option.selected = false; - }); - renderSkipPriceAsinInputs(); - msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; - msgEl.className = 'msg ok'; - loadSkipPriceAsin(1); - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.className = 'msg err'; - }); - }; - setupSkipPriceAsinShopPicker(); - renderSkipPriceAsinInputs(); - function loadVersions() { - fetch('/api/admin/versions') - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('versionListBody'); - if (!res.success) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - var items = res.items || []; - if (items.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = items.map(function (v) { - var url = (v.file_url || '').replace(/"/g, '"'); - return ' 鏆傛棤鐗堟湰璁板綍 '; - }).join(''); - } - }) - .catch(function () { - document.getElementById('versionListBody').innerHTML = ' ' + (v.version || '') + ' ' + url + ' ' + (v.created_at || '') + ' 涓嬭浇 '; - }); - } - document.getElementById('btnUploadVersion').onclick = function () { - var version = (document.getElementById('versionNumber').value || '').trim(); - var fileInput = document.getElementById('versionZip'); - var msgEl = document.getElementById('msgVersion'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!version) { - msgEl.textContent = '璇峰~鍐欑増鏈彿'; - msgEl.classList.add('err'); - return; - } - if (!fileInput.files || fileInput.files.length === 0) { - msgEl.textContent = '璇烽€夋嫨 zip 鍘嬬缉鍖?; - msgEl.classList.add('err'); - return; - } - var file = fileInput.files[0]; - if (!(file.name || '').toLowerCase().endsWith('.zip')) { - msgEl.textContent = '浠呮敮鎸?.zip 鏍煎紡'; - msgEl.classList.add('err'); - return; - } - var formData = new FormData(); - formData.append('version', version); - formData.append('file', file); - msgEl.textContent = '涓婁紶涓?..'; - msgEl.classList.remove('err', 'ok'); - fetch('/api/admin/version', { - method: 'POST', - body: formData - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - msgEl.textContent = '鍙戝竷鎴愬姛銆傜増鏈細' + res.version + '锛岄摼鎺ワ細' + (res.file_url || ''); - msgEl.classList.add('ok'); - document.getElementById('versionNumber').value = ''; - fileInput.value = ''; - loadVersions(); - } else { - msgEl.textContent = res.error || '涓婁紶澶辫触'; - msgEl.classList.add('err'); - } - }) - .catch(function () { - msgEl.textContent = '璇锋眰澶辫触'; - msgEl.classList.add('err'); - }); - }; - - // ========== 鏍忕洰鏉冮檺閰嶇疆 ========== - function loadColumns() { - fetch('/api/admin/columns') - .then(function (r) { return r.json(); }) - .then(function (res) { - var tbody = document.getElementById('columnListBody'); - if (!res.success) { - tbody.innerHTML = ' 璇锋眰澶辫触 '; - return; - } - allColumnsList = res.items || []; - if (allColumnsList.length === 0) { - tbody.innerHTML = ' 鍔犺浇澶辫触: ' + (res.error || '') + ' '; - } else { - tbody.innerHTML = allColumnsList.map(function (c) { - return ' 鏆傛棤鑿滃崟锛岃鍦ㄤ笂鏂规柊澧?/td> '; - }).join(''); - } - bindColumnActions(); - }) - .catch(function () { - document.getElementById('columnListBody').innerHTML = ' ' + c.id + ' ' + (c.name || '') + ' ' + (c.column_key || '') + ' ' + (c.created_at || '') + ' ' + - ' ' + - ' '; - }); - } - function bindColumnActions() { - document.querySelectorAll('[data-column-edit]').forEach(function (btn) { - btn.onclick = function () { - document.getElementById('editColumnId').value = btn.dataset.columnEdit || ''; - document.getElementById('editColumnName').value = (btn.dataset.name || '').replace(/"/g, '"'); - document.getElementById('editColumnKey').value = (btn.dataset.key || '').replace(/"/g, '"'); - document.getElementById('msgEditColumn').textContent = ''; - document.getElementById('editColumnModal').classList.add('show'); - }; - }); - document.querySelectorAll('[data-column-delete]').forEach(function (btn) { - btn.onclick = function () { - if (!confirm('纭畾鍒犻櫎鑿滃崟鈥? + (btn.dataset.name || '').replace(/"/g, '"') + '鈥濆悧锛?)) return; - fetch('/api/admin/column/' + btn.dataset.columnDelete, { method: 'DELETE' }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { loadColumns(); loadColumnsForPermission(); loadAdminMenus(getActiveAdminTabName()); } - else { alert(res.error || '鍒犻櫎澶辫触'); } - }); - }; - }); - } - document.getElementById('btnAddColumn').onclick = function () { - var name = (document.getElementById('columnName').value || '').trim(); - var key = (document.getElementById('columnKey').value || '').trim(); - var msgEl = document.getElementById('msgColumn'); - msgEl.textContent = ''; - msgEl.className = 'msg'; - if (!name) { msgEl.textContent = '璇峰~鍐欒彍鍗曞悕绉?; msgEl.classList.add('err'); return; } - if (!key) { - msgEl.textContent = '璇峰~鍐欐爮鐩爣璇?; msgEl.classList.add('err'); return; - } - fetch('/api/admin/column', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: name, column_key: key }) - }) - .then(function (r) { return r.json(); }) - .then(function (res) { - if (res.success) { - msgEl.textContent = res.msg || '鏂板鎴愬姛'; - msgEl.classList.add('ok'); - document.getElementById('columnName').value = ''; - document.getElementById('columnKey').value = ''; - loadColumns(); - loadColumnsForPermission(); - loadAdminMenus(getActiveAdminTabName()); - } else { diff --git a/backend/web_source/admin.html b/backend/web_source/admin.html index ccfb20b..04c7c99 100644 --- a/backend/web_source/admin.html +++ b/backend/web_source/admin.html @@ -336,6 +336,178 @@ font-size: 16px; } + #shopManageGroupModal .shop-group-modal { + width: min(1180px, calc(100vw - 48px)); + max-width: none; + max-height: calc(100vh - 48px); + padding: 0; + overflow: hidden; + display: flex; + flex-direction: column; + } + + .shop-group-modal-header { + padding: 20px 24px 14px; + border-bottom: 1px solid #edf0f5; + flex: 0 0 auto; + } + + .shop-group-modal-header h3 { + margin: 0; + } + + .shop-group-editor { + padding: 18px 24px 14px; + display: grid; + grid-template-columns: minmax(180px, 240px) minmax(240px, 320px) minmax(360px, 1fr); + gap: 16px; + align-items: start; + flex: 0 0 auto; + } + + .shop-group-editor .form-group { + margin-bottom: 0; + } + + .shop-group-member-select { + min-height: 128px; + max-height: 180px; + } + + .shop-group-help { + color: #777; + font-size: 12px; + line-height: 1.5; + margin-top: 6px; + } + + .shop-group-action-bar { + padding: 0 24px 12px; + display: flex; + gap: 8px; + justify-content: flex-end; + align-items: center; + flex: 0 0 auto; + } + + #msgShopManageGroup { + margin: 0; + padding: 0 24px 10px; + min-height: 18px; + flex: 0 0 auto; + } + + .shop-group-table-wrap { + margin: 0 24px; + border: 1px solid #edf0f5; + border-radius: 8px; + overflow: auto; + min-height: 220px; + flex: 1 1 auto; + } + + .shop-group-table { + min-width: 1040px; + table-layout: fixed; + } + + .shop-group-table th { + position: sticky; + top: 0; + z-index: 1; + } + + .shop-group-table th, + .shop-group-table td { + vertical-align: top; + } + + .shop-group-table .col-index { + width: 58px; + } + + .shop-group-table .col-name { + width: 130px; + } + + .shop-group-table .col-leader { + width: 110px; + } + + .shop-group-table .col-count { + width: 86px; + } + + .shop-group-table .col-members { + width: auto; + } + + .shop-group-table .col-time { + width: 120px; + } + + .shop-group-table .col-action { + width: 128px; + } + + .shop-group-time-cell, + .shop-group-action-cell { + white-space: nowrap; + } + + .shop-group-name-cell, + .shop-group-leader-cell { + word-break: break-word; + } + + .shop-group-members { + display: flex; + flex-wrap: wrap; + gap: 6px; + max-height: 96px; + overflow-y: auto; + padding-right: 4px; + } + + .shop-group-member-chip { + display: inline-flex; + align-items: center; + max-width: 150px; + padding: 3px 8px; + border-radius: 999px; + background: #eef1ff; + color: #4f63d8; + font-size: 12px; + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .shop-group-modal-footer { + padding: 14px 24px 18px; + display: flex; + gap: 8px; + justify-content: flex-end; + border-top: 1px solid #edf0f5; + flex: 0 0 auto; + } + + @media (max-width: 900px) { + #shopManageGroupModal .shop-group-modal { + width: calc(100vw - 24px); + max-height: calc(100vh - 24px); + } + + .shop-group-editor { + grid-template-columns: 1fr; + } + + .shop-group-table-wrap { + margin: 0 16px; + } + } + .column-permission-cards { display: flex; flex-wrap: wrap; @@ -347,6 +519,97 @@ overflow: hidden; } + .multi-select-native { + position: absolute; + opacity: 0; + pointer-events: none; + width: 1px !important; + height: 1px !important; + min-height: 0 !important; + padding: 0 !important; + border: 0 !important; + } + + .multi-select-dropdown { + position: relative; + width: 100%; + } + + .multi-select-trigger { + width: 100%; + min-height: 42px; + padding: 10px 34px 10px 12px; + border: 1px solid #ddd; + border-radius: 6px; + background: #fff; + color: #333; + font-size: 14px; + text-align: left; + cursor: pointer; + position: relative; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .multi-select-trigger::after { + content: ""; + position: absolute; + right: 12px; + top: 50%; + width: 7px; + height: 7px; + border-right: 1.5px solid #666; + border-bottom: 1.5px solid #666; + transform: translateY(-65%) rotate(45deg); + } + + .multi-select-dropdown.open .multi-select-trigger { + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.12); + } + + .multi-select-panel { + display: none; + position: absolute; + left: 0; + right: 0; + top: calc(100% + 6px); + z-index: 30; + background: #fff; + border: 1px solid #ddd; + border-radius: 8px; + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14); + padding: 6px; + max-height: 220px; + overflow-y: auto; + } + + .multi-select-dropdown.open .multi-select-panel { + display: block; + } + + .multi-select-option { + display: flex; + align-items: center; + gap: 8px; + min-height: 34px; + padding: 7px 8px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + color: #333; + } + + .multi-select-option:hover { + background: #f4f6ff; + } + + .multi-select-option input { + width: auto; + margin: 0; + } + .column-permission-card { display: inline-flex; align-items: center; @@ -762,7 +1025,7 @@ - 璇锋眰澶辫触