From 6032c6fcba748dd3f62ae441f92fcd211e7b1f50 Mon Sep 17 00:00:00 2001 From: dfdg <2710245601@qq.com> Date: Mon, 15 Sep 2025 17:12:28 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=90=88=E8=A7=84=E6=80=A7=E6=89=8B?= =?UTF-8?q?=E7=BB=AD=E5=88=A0=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusFormalitiesAreConsolidatedServiceImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java index f4a97052..7f8f85c4 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java @@ -265,9 +265,22 @@ public class BusFormalitiesAreConsolidatedServiceImpl extends ServiceImpl ids, Boolean isValid) { if (isValid) { //TODO 做一些业务上的校验,判断是否需要校验 + for (Long id : ids) { + BusFormalitiesAreConsolidated selected = baseMapper.selectById(id); + if (selected == null || !FormalitiesStatusEnum.TOSTART.getText().equals(selected.getProcessingStatus())) { + throw new ServiceException("只能删除待开始数据"); + } + Long count = busFormalitiesAnnexService.getBaseMapper().selectCount(new LambdaQueryWrapper() + .eq(BusFormalitiesAnnex::getFormalitiesId, id)); + if (count > 0L) { + busFormalitiesAnnexService.getBaseMapper().delete(new LambdaQueryWrapper() + .eq(BusFormalitiesAnnex::getFormalitiesId, id)); + } + } } return baseMapper.deleteByIds(ids) > 0; } From e075f8f6e57999c17f5abab30a1c95b53c1215bb Mon Sep 17 00:00:00 2001 From: zt Date: Mon, 15 Sep 2025 19:14:40 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=80=83=E5=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excelTemplate/salary_template.xlsx | Bin 0 -> 9760 bytes .../SubUserSalaryDetailController.java | 21 + .../SubConstructionUserSalaryDto.java | 31 ++ .../SubConstructionUserSalaryVo.java | 83 ++++ .../service/ISubUserSalaryDetailService.java | 21 +- .../impl/SubConstructionUserServiceImpl.java | 18 +- .../impl/SubUserSalaryDetailServiceImpl.java | 342 ++++++++++++++- .../controller/BusAttendanceController.java | 14 + .../app/BusAttendanceAppController.java | 2 +- .../dto/attendance/AttendanceExportDto.java | 33 ++ .../BusAttendanceClockDateForTwoWeekVo.java | 6 +- .../project/mapper/BusAttendanceMapper.java | 6 + .../service/IBusAttendanceService.java | 15 + .../impl/BusAttendanceServiceImpl.java | 395 ++++++++++++++++-- .../impl/BusProjectTeamMemberServiceImpl.java | 34 +- .../dromara/websocket/ChatServerHandler.java | 36 +- .../controller/ChatGroupController.java | 5 + 17 files changed, 983 insertions(+), 79 deletions(-) create mode 100644 xinnengyuan/ruoyi-admin/src/main/resources/excelTemplate/salary_template.xlsx create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/usersalaryperiod/SubConstructionUserSalaryDto.java create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/usersalaryperiod/SubConstructionUserSalaryVo.java create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/AttendanceExportDto.java diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/excelTemplate/salary_template.xlsx b/xinnengyuan/ruoyi-admin/src/main/resources/excelTemplate/salary_template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4001e01f2fec7f3f5a5db67af3369b6c4505ddd9 GIT binary patch literal 9760 zcma)ibzD?i_cx7n2uOE#i*!r3NJ@7M3`m1?UnEEAlm_YUmhSGB?v8iR`&{q!xxeT0 z?mzaNIkRG)@7`<8S)n8g4TA{rG=daXg`YnEGZ4TR#sDKFAi&OnMF~uX1-|j@2U)4b z#fl6h1cVe61O)ou$qel5m|bkFlcQT@pxLk_E`1--%K&3I7bw8isrq037ZUs4TB;T-de=NCS?*S=!$zwELQ1(qn_5e++)OCXqA zkben+6d)kvx}deEb)>}1Bujg4SMkCYaNNX&r=hkS{B@W)jiRHl?{f@=RDhM6wmS_s zH}>{xK4a>LIDcpg7S-V%-l9onKQ`Y8QcGjKfC|gK&8wx+o*v(!WHjn{c+_hz5S0w# znRXzJjMkc5__`e<*-D}9i4l6|iD!Btl54~QAtk!w)?D?ud?ke$~F_jNKhN`#=vA*th`!18*(9y__A z-vR;GmOJr~n5B-SDJ>LhnTDxhWZ5n}phK@k9JgtU!&MnOaYsT0PUTGgG>@B#n zxEtwC`MHgE1z&UA34ZXhc`N_L*0vKeu68+=PrtPWm{&bJ&f9HPx#@*{YCx>m7)^SB zw$UB&od)661CxXnL6exTlp*14fDj!ZGpM^0IZlk7FlU{4pbLpTeGP$Xy*%DyWT|5p zafj#eLr3^<;+*U%f>Kp2OSAYj%0B@w-}f${0|Sl$2K@Oy0Dte`2(WpA{7aOsY&$Df z;34dzSdV7{r*5@r1gLg-Sz}}m&Z?VOEDa-l?XIpaiw>&;1$(W^ z;n`#KK25Jl(L;B$Rc~PgZ5Xgb^sS2$>ZW8Uk0_Dnv!>o2x97sM%_`t7qxVuC>F<|x zO&|G1Rvyo5)yfyV*3^C(;a)gbwU#mL5iP1IhoEUFh*v;`-(+{xuT8SA7xl+xdGd^n zqTiVOn&K5g#i)}!)KVxbOK7BjFo^NB;4w!BRFx~6@wZ`2U zxp`C7sh50g4@a4lSv@%^?)k4Rq-FrzE=`lypT5ICA^Y#11{#d4i}ep5^X~+xKM9-x zKr07x6BEbZ{Siu6u^uN_O4l<82;Bdo{lUWa!#vdIY*$&)J@qUeTTk2_Ahi(5)tDgn zW$INb7y8Pjsr9)+%B#rsz3wBDktjuSS$JLvayXdsrzrsy@$BrIq9#Z|la{8}3fm0!B!_u>Lc}5}K#rqMXZpDd=m3b}P?+(`jhqZ& zJ5y*$j&2onoG6wzm=a<-_d<$n6y2ym$xut5p`(DzOQMIPiK*4aIBN5?hDZXOaWkO3POeQuWLZqA2@3* zS&LEZicmZ%8ZjXkG$m@d;ijkzZYCk7X7$5Az9rYUDTFMRhiSMKgRahx6JQz>>I=Z4 zYON2D;P^t~I{1tt&o`cIdFZeNfxP@N7{*V@moZ@5{yWn=MT(OeM+$!6D-5Hu9cTj* zjZ2>ayyc8Cbz;zsFSTFBCWpM2qH4Q2*SSv#TH$TWCi1p<+gL-|w=_tJ#43f%lx#Ai zd6UAxaOqDNsCd=7U2Z)!yX@RzT@@ydn2q!3a459A7S9_21N+xPD0t<}MqI{Mjm3y8 zN^U_7O~T(NJRE$0^lmho9J2`rsTB(!%@ebigu(|mzZ23|PZ$>-Xu$!^%yP-2c-FT^ z#LY*>rmLXyKYrYr4xR4t^x)N-!JBVyw-9((aDvV;Zgo0J{zf!}ElnnZkm7e^!sWVO zjuRkJYO0-nEH>7#f9#ItQYrvH$A=;Ml7+VS$`jI)R;m>-lI4!%p|NF-k+Pem{yq)9 z0$oM6tMXe0u&VUk(S*&T591^B|82HUF9=|>bu>4zG5PHUp)C?JqKD|G-~5a0 z2k{SE+}BhD5J+G(QyddXx&w@8obX@2&z~;UHXoBL)gE7S5x7v`s4q{zqd7*Yd`(Fy zE}|1zV=pZHMSWF8P(JNh==j%`#Q24C1%BHkOkrUM^TzV#%gx56TaFJGJC$pn)5XXs zH>5do-xb3IQ<9O48qXsiT-1N!hN8q)2>g8P&*?`O)mmBPyi^Q)OLQ%+X z%L8)3d9Y+C)&t@-h);qaYV6ShV6CON|Z2)ThZ-eiS(Ri-mM2vo77@mZBg z&0SkH?b<=io`@VnG=>11o2Gjd5|-ym9Oq3O&Y5jca~9lR(Bn) zw5;kE-Z>w^86Shc9K?0G4RjJHb(jNLgC-&OojCSkjXP#gSUjMY3F43i#YDKVX1?U$ z9*Z;eR^kdRXCOhK7;B8cq(XqvUM<-V^%*Y|yBBLKx_x9cko zp?9ETp%0fMib7sH@S?B-jBdx*F?uNiuE(9-&0eR|&`UTjN`aRaa+G!Q5yOHXTVINW zTfM>yK9xSBkRw7M^s)W86A?0r?t zA|cX_wFOTZqIb>~v^DD#0SBt%ZR4`isi;Zf2?z^mY#k;$r+A|KcIED9l{}}ejbf;} zlvpsP#A~X#`8hlF~Qzb z2YPLw+%hM2F{{wJEswb(IlPlRIP!DyUmFkFAEBf-T8e>>%)s5Z-|#yGR*Rl-bU@M| zwR?WVq?tE+>09r(_nA``{oa(EzqCQ2CZ@TOj=;dM4!OcHN41;NRd>!5>!vDs#b(YH zZmuNwI&`Zm&$RK`C5!b4pG))}MsDae)s9V&*Ic^aqesv?wZ0cipUjGI>nau_ryHwg zT)UB8E>iSrD9Yp2QVlF>w?T34wWWbLf)rE;J4T;*?Z^Zo5YB7pQ~1HWB~ijYCr@f? zYQ#6EGK$Y5mW>4>Y)NqJO%xrMT)w@i(45*rpL<2AUhiQZG<9a@HBUQ^ThO&Bm#A2g zjm^k6GaDyIcXdG>^QKZ+c1WEoJ3f26U%jS~j(ZE3)?kMMhs14Q=BFSXx>D1OJHmFm4vUeg$dIebevnMPD7hL*VBv|(4&LgZCRbG zcbd`bI<4Wx=={3!jC4~tvct+8=HqX7Arb9oktOX$15)h~MPl4of@g4x!$hg9CsQ=T zvZc(3U*2iH3Fr%hg}NnMW|Z_j`b zFP~Y75&57qJHtxWsU$$YpkEyh7!3~8h1_lWP87*xCx-OZ$D_uO`wD9y z`XaVplqlm)N9TTFDF}Py$!IlyV-D{!XIwN@R|Cw}I5DHu zZgUYbS&SJfi=FXXwSqo}i_Ke`QU$TWt|u$-DMQ4GCNW3fJ>1|VARr)R4 z^rayJY^U#=@maqQxo){>IFu^NdD+T(*>jXRO}+)Nt)CnB4{uGKoJ_OMva=BhdPqYf zRP}jr;Gx=H34C1^MJ!}wksE;WQ3^g)nqZUhK_n+-QdE%gSMupLjE0hs>62EbtR){M z4f$^3Ut5+>fS+||i6ySWjou$aE~=*58SlbRW~tOF-1D6}`)&aSU9PY&(fr{>52mtl zNN?exi<5)P&7j*$XlM7M*^`L6y-_?KRI3z+?dI`2C$sfQrhM~UUf?BVRB!YZk)Q%b z#Zp69kbX{k1X^Rg?I=CL4Sw$k^12tm!V8Id%Q)t@78fuQIf*+Tg!H&?9 zP=4Iea#B)GD<>}&RiQ^d zsY}c7b(L%=`lzi`@Q^o;{W`bL6@TWc(K4kxJXCs8(&gRd(9q*0JMV%Cor{EjR+8)R z9zHrc&Pj0DAMmM6euL;xd8}b}y?DpVR^%(+uZ}a7TRR65P6^T=<=j}6>76m64Mf=) z>-lNq4m)&=HNGoZNA|)(mBA=MllnMxKOuTVZg-lT8+XVwZ@KZ5d2Tr(Wj~ zKdi%DVXmv|XpCdLzyzE@!6V;z)h7;*K={!xA^OceWQ(g;2*>@XE}}^2mjns5s2)E7 zq7z?!O6zAG+?Umy6ZHy1C8YQyHno_%wD+3IDm_6Sc)q@6!7rvbRYKs4e8#47c`yBk z93Kv_LUAJFKo|6yctGDFSA2v5GEqUI%y5Fv?ZQbWM-?BJgE(vXe;+Ru+>*RE^ zWY2?mKK3I{D~TorzJ-dFrE-*O2g<g-$)LX^4_-~^Lmc4@iu)J zJ)9m(GehhDKGTo7$US%{W9Y%zgclqh=qpQHVB5o?c6t0YiZv*gSH5HxQNUtNS>B<~ z+OCH<#y**c=eQg8z)(wY!|vuoTaMeP>Zl4~p%&s0^H!g$?0%>9^$D*zLrVYs_pC;* zG7Y(RjAlcL48uYw5_MZ{lL>>Fn_I+>Q2#tQ4faX=qTo;$s00Cl@~6E!x>}q3F!TwX z{f~1}c#jbskNUN~Xu;O2pBnaUsyJsV9Y=i>ETbYJ-YBdZGbQm%D^$8a%Nu4u3JUc{ z#8RNKpU;a$bM%3>pRnJ*=a8?v4f)_>W@Ep@0zMf}L-S;==6Oub&cb{TA7sF~;7Et!(8k$Apfw&9zjXr$Y zBI?+|>~&?$Tg?;;Y(!GeVI^|6c#COZy`6&Do7lNu<5;lq-EQ=4q1hKujGdB6KTFTf zwBnIy15pq_gfW9ckWZ?^v?N9?w=Zs76g3yasTND-qERxTgaV_ajbSTgUQ$cwL&I>h z7N`+$AchN6TN9N6k|*D5I&-6&q2g*$Ys#qWPZw60obJHg3{bLXvb;LYPvrg>6R2A) zZ3Z00H4A*zxH()T{KeEui!XTQ$XLi%BjB&U|Stz%V>syTP3oY|y68|Zi zGkWdvgUVic$-+ViYUGjF^FW(`5>t5kR;_aVFC|*%g6KO0?dq1b+Z+g$}qdbh8f}zwKCtV*qDK^Bftfr${hH+JFbQy)y zj!Nv#mbdtww07YrP~bqj8wa_|%BA6rDb`@VPDY_Z&dhu?>`- za{GP{d$@w9dl~B7fczS3zhn3=N}B)<1uVDQc+uW?;()1G9vA)}*~N5opY&j_<%>oN z^U@?u#*}oc^q`N=Ei0AZB;*%c*C9RI0DSAuPXc_#yRP+*k4lyOe4J)>I-}F~sz3Zr zr>(zdh^qe_WvZcMEO(30RMLytz;t~J)07{f;@Ube{#wV1gF@&NE60fg!YL>aq9i!V z>Q70J9|G}&jN6QCrp|9lR;dCCcw}IS>AqFo3v}bd9FcyXX{R_7vZL899YulCpqO3S zo!cBHN<<|DQG{*_W%z$#*TA;=){0SRDe=5@lhdvp)|cH93#e!l_P&KaiyM}Uf=P7_ z(}>wZ_Nrq+eS{_7G!KVKHEX(3F4A;?T|%9p6+$_Sf+V7_Nr0%+Cp;BF>I#E;biqX$ z!+vmgyHxh;Zd~2FH&z{6ngd~b%geZKVZ~U+C}d($O#a9sUFhssyCqSBK(orI^d3_R zvB(k0z}5FQd-bXsGZDwQlFKo37#ayOF%y%q9vFRW$Qt4uVW`7Qdekfd z@ogLKbptx5Z!G=4K+`J^0h1DQjXliJKT#0baPkndGCY>hKo=oq4!~}so9ecUskrqZ zT>U{YdMx9KA7`vUJs1Kx&jtX(L2YXiypVPCYA+31i|WK|*st}OKsrLjRFfUZMVQsV zoEE4sUW7&rD|8@1!+Fyg_V8Bp4Q_Z=PzJ6-=bTcpzv}yj@(r2X-Yjwzt)x)Ohoyvw zI*{4&z9Oe*xDCyVOtu}2Vo;ZyGyFmJ0#VX(F@0;dj&qd{YS=N|PF*ob(V+M=)B<_T z>8+g6XCF*UWV{;0YMrGL&H1)<=~gcBFY2+Hk@m312GN1T0>+beNbL;S)xLQV(|O(! zv+1HaC88Sxq8Lu9T{0qec`A{Y*L0n+&I)-t0-b7h!+vgvH;H%racWTMVVdc&rJaKc z()q5DtrE&nbU-^PvHCg=3&6wo@O{D0b#OtjZ=&gJ>@<|9;%6a)I@MH6@?rA{-wMmp zQgx1Fa))!A(?mFxNMqbkEMawZU zutE!y&9XmsfA6ALn5I>R@fJzjormdZ(!r^^u+w^)Fj%bjS1K666ZyO8*>(#}@Fc0j z@aIhfisFrT?!9}ye41Wn>Wc-Rv|K(#z^`Jv2rE>m_xIZ|uhL~uKUX%UB2HMdpfg>> zZuGb9+TD3wY}O22pwr*$)>Y{wN#{tLpdYl`pmLoHsjxg@9^{~V?PeCBWv-12g)1C7 zGusN-3x=dkpHk62*_$apr8#8JcFL)Oz7;T%V#46Bxjeb{n;H7xbo>AyXCDqBqxdTS znom~r)z+gMyZc28jEnx9iSAQlQNU@sxww10WWjTnPKT;R=NS^ zmySbTMitC+TzpRRbWWGGJIsORLp^>Ew#SJzDO7w>CHxcm2VVlyR4<^{MQ3Mb`P;*0 z_a>>2p?qJu=iFbI3_f0e3LCp5_sJbpf%;4i4a2CCBy@keH+4Ah!I}4Q`6~udz6Uaq ztG1iS*mY3O3zB=mjFvF~a>(%gmZBis#-?-X(dh6EB1JKM2RsH%=XRHaTDY*mxG1^s z^KWVa-NEF@+EOs`V&ufcp{%xK7@Q~}E*`>h7_|?b?KAhdM2Ki;w5bS`IjNm0F5)fE zQ-as`6u%AxD=0)gx#I6gF23XN;!u?xD2{kFV*7WNf!*jJ89WBG?%#s|SjDg6{Y+M;b~2 z8lOEMX0DeGA-l{JNpwBVTCZ6I(@S6}cwRoUPgidukIRa)b}4KjRYI2#NJjZcA|ITp z#Y;e}${LPoPQgkuC>sZl)9{T+KXNqf;@Ud&TByPffr2h0oF>zA zUX65Xm;N>!A;?7WuS(qfKm*kRZ~2V3hTO|=+~aj6&R8z6hN3$tH@PpMxpjkQ#0$Yh zrtis2pErum9Q8~D^vItfnm|7o{DDdSb{X4SV;ft)lO5fV`)N@hXY$d@L*9WktgHVd zY^SIWjgloHG%zPgJM04|SB|HNk0z?&HpdZcJ6~$E3p`MJ#lU2cRJqMHt-*bkkj?G} zq*q7iCqdy>NBC8HxV(AxAgelL`%Q?~dMXhxOJH|Gks%Pr>W z<1$;_=y+#rO$$a6&GYbw^aH>ck61Kr3x=EG!xppShT&%=oHSyP4J8>w6NT=@q> zie9g~(w6&2$p1TK3r@*G=mAZve=nf8^Efp;f`3~AM>9x&(J((z7J=i=4%VM>=Vp_< zGd9MIBMbSSys@YEXSv5=>gUm#`%R4^%8cW6@E_x^HxrjUjOz&&NZ+w#M>P1pSN0VK z^f)ysA9=WFEci+lHcmjhs@b){)bE@a-unA(^2g3HQ%31}s0_0Q@zKRtjC@y95>Dmg zlE`@_WJKY|-Ds<1+j}C}l}fB6&)>O7AM9QaXU`MRa18+D?+z{t#Ak{PaWJf_MJ2zt zj>Hc4^T?cTMn9K;gL^dud@tB{=qwXdSY*nCBB2xTSv7QiL#NrEF}_F%}ok;M|Ocim=Ffex~sq1 zk=c`G5ddHSaE+G(QgaJKJi#n-AXDK^?@?w+|{SKbcRnGnbKW>&{2*A#2 z^n@6ZW21RIB$};yd4<`(6`aB%F12dW105`xgR0q@%FIsD(|3GX(8ZTL+~m+Zr>nx) zH>J;Q)n?~K!Czzu0tyybAx|VAFOd=Tke!6AX^_8ij$l36>z-)-XAG2ktmR+^&Uv7~ z{wxt_ivesMO>7PGz)R|;_AG4yggUee?qO+d) z-xtrDqNQhe~u?*PvdV5EdSK^dkf1G@lSm; ze`ou%q2+goes9G1#hnU1(tj!aPg} salaryPageList(@Validated SubConstructionUserSalaryDto dto, PageQuery pageQuery) { + return subUserSalaryDetailService.salaryPageList(dto, pageQuery); + } + + + @GetMapping("/export") + public void export(HttpServletResponse response, SubConstructionUserSalaryDto dto) throws IOException { + subUserSalaryDetailService.export(response, dto); + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/usersalaryperiod/SubConstructionUserSalaryDto.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/usersalaryperiod/SubConstructionUserSalaryDto.java new file mode 100644 index 00000000..af4afefd --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/usersalaryperiod/SubConstructionUserSalaryDto.java @@ -0,0 +1,31 @@ +package org.dromara.contractor.domain.dto.usersalaryperiod; + +import com.alibaba.excel.annotation.ExcelProperty; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class SubConstructionUserSalaryDto { + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + @NotBlank(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 时间 + */ + @NotBlank(message = "时间不能为空") + private String time; +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/usersalaryperiod/SubConstructionUserSalaryVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/usersalaryperiod/SubConstructionUserSalaryVo.java new file mode 100644 index 00000000..7231f0a5 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/usersalaryperiod/SubConstructionUserSalaryVo.java @@ -0,0 +1,83 @@ +package org.dromara.contractor.domain.vo.usersalaryperiod; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.contractor.domain.SubConstructionUser; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Date; + + +/** + * 施工人员视图对象 bus_construction_user + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubConstructionUser.class) +public class SubConstructionUserSalaryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 银行卡号 + */ + private String yhkNumber; + + /** + * 开户行 + */ + private String yhkOpeningBank; + + + private BigDecimal totalSalary; + + /** + * 用户Id + */ + private Long sysUserId; + + private Double workDay; + + private BigDecimal salary; + + private String time; + + private Integer order; + + private String blank; + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubUserSalaryDetailService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubUserSalaryDetailService.java index df483b38..83d2d2d9 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubUserSalaryDetailService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubUserSalaryDetailService.java @@ -3,12 +3,17 @@ package org.dromara.contractor.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.contractor.domain.SubUserSalaryDetail; import org.dromara.contractor.domain.dto.usersalarydetail.SubUserSalaryDetailQueryReq; +import org.dromara.contractor.domain.dto.usersalaryperiod.SubConstructionUserSalaryDto; import org.dromara.contractor.domain.vo.usersalarydetail.SubUserSalaryDetailVo; +import org.dromara.contractor.domain.vo.usersalaryperiod.SubConstructionUserSalaryVo; +import org.springframework.validation.annotation.Validated; +import java.io.IOException; import java.time.LocalDate; import java.util.List; @@ -52,7 +57,7 @@ public interface ISubUserSalaryDetailService extends IService getVoPage(Page userSalaryDetailPage); + + /** + * 工资计算与导出 + */ + TableDataInfo salaryPageList(@Validated SubConstructionUserSalaryDto dto, PageQuery pageQuery); + + + /** + * 导出 + */ + void export(HttpServletResponse response, SubConstructionUserSalaryDto dto) throws IOException; + + + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java index b2008d26..c588ed74 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java @@ -918,12 +918,11 @@ public class SubConstructionUserServiceImpl extends ServiceImpl attendanceLqw = Wrappers.lambdaQuery(BusAttendance.class) .eq(BusAttendance::getProjectId, projectId); - if (ObjectUtils.isNotEmpty(clockDate)) { - String clockMonth = clockDate.substring(0, 7); + if (ObjectUtils.isNotEmpty(clockMonth)) { // 校验月份格式 if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); @@ -935,13 +934,13 @@ public class SubConstructionUserServiceImpl extends ServiceImpl userIdList = attendanceService.list(attendanceLqw) .stream().map(BusAttendance::getUserId).toList(); if (CollUtil.isNotEmpty(userIdList)) { - lqw.in(SubConstructionUser::getId, userIdList); + lqw.in(SubConstructionUser::getSysUserId, userIdList); } } // 模糊查询 @@ -967,7 +966,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl userIdList = constructionUserList.stream().map(SubConstructionUser::getId).toList(); + List userIdList = constructionUserList.stream().map(SubConstructionUser::getSysUserId).toList(); // 关联查询施工人员考勤列表 attendanceLqw.in(BusAttendance::getUserId, userIdList); Map> userIdBusAttendanceListMap = attendanceService.list(attendanceLqw) @@ -975,7 +974,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl userAttendanceTotalList = constructionUserList.stream().map(constructionUser -> { SubConstructionUserAttendanceTotalVo constructionUserAttendanceTotalResp = new SubConstructionUserAttendanceTotalVo(); - Long id = constructionUser.getId(); + Long id = constructionUser.getSysUserId(); BeanUtils.copyProperties(constructionUser, constructionUserAttendanceTotalResp); // 关联施工人员考勤信息 int attendanceDays = 0; @@ -1036,6 +1035,9 @@ public class SubConstructionUserServiceImpl extends ServiceImpl list = this.list(new LambdaQueryWrapper() + public void insertByAttendance(Long userId, LocalDate reportDate) { + //打一次卡 半天工资 如果已存在直接X2 + SubUserSalaryDetail one = this.getOne(new LambdaQueryWrapper() .eq(SubUserSalaryDetail::getUserId, userId) .eq(SubUserSalaryDetail::getReportDate, reportDate)); - if (CollUtil.isNotEmpty(list)) { - return true; + if (ObjectUtils.isNotEmpty(one)) { + one.setDailySalary(one.getDailySalary().multiply(new BigDecimal("2"))); + this.updateById(one); } SubConstructionUser constructionUser = constructionUserService.getBySysUserId(userId); @@ -127,16 +179,17 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl salaryPageList(SubConstructionUserSalaryDto dto, PageQuery pageQuery) { + + SubConstructionUserQueryReq req = new SubConstructionUserQueryReq(); + req.setProjectId(dto.getProjectId()); + req.setTeamId(dto.getTeamId()); + req.setUserName(dto.getUserName()); + + TableDataInfo subConstructionUserVoTableDataInfo = constructionUserService.queryPageList(req, pageQuery); + List rows = subConstructionUserVoTableDataInfo.getRows(); + if(CollectionUtil.isEmpty(rows)){ + return TableDataInfo.build(); + } + String time = dto.getTime(); + YearMonth parse = YearMonth.parse(time, DateTimeFormatter.ofPattern("yyyy-MM")); + LocalDate start = parse.atDay(1); + LocalDate end = parse.atEndOfMonth(); + + List userIds = rows.stream().map(SubConstructionUserVo::getSysUserId).toList(); + //考勤数据 + List attendanceList = attendanceService.lambdaQuery() + .eq(BusAttendance::getProjectId, dto.getProjectId()) + .in(BusAttendance::getUserId, userIds) + .between(BusAttendance::getClockDate, start, end) + .list(); + //工资数据 + List salaryDetailList = this.lambdaQuery() + .eq(SubUserSalaryDetail::getProjectId, dto.getProjectId()) + .in(SubUserSalaryDetail::getUserId, userIds) + .between(SubUserSalaryDetail::getReportDate, start, end) + .list(); + + + ArrayList vos = new ArrayList<>(); + for (SubConstructionUserVo row : rows) { + SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo(); + BeanUtil.copyProperties(row,vo); + vo.setSfzNumber(idCardEncryptorUtil.decrypt(vo.getSfzNumber())); + vo.setTime(dto.getTime()); + // 获取工资 + BigDecimal salary = row.getSalary(); + if (salary == null || salary.compareTo(BigDecimal.ZERO) == 0) { + String typeOfWork = row.getTypeOfWork(); + String wageMeasureUnit = row.getWageMeasureUnit(); + if (StringUtils.isNotEmpty(typeOfWork) && StringUtils.isNotEmpty(wageMeasureUnit)) { + BusWorkWage workWage = workWageService.lambdaQuery() + .eq(BusWorkWage::getProjectId, row.getProjectId()) + .eq(BusWorkWage::getWorkType, typeOfWork) + .eq(BusWorkWage::getWageMeasureUnit, wageMeasureUnit) + .one(); + if (workWage != null) { + salary = workWage.getWage(); + } else { + salary = BigDecimal.ZERO; + } + } else { + salary = BigDecimal.ZERO; + } + } + vo.setSalary(salary); + vo.setTotalSalary(salaryDetailList.stream().filter(detail -> detail.getUserId().equals(row.getSysUserId())) + .map(SubUserSalaryDetail::getDailySalary) + .reduce(BigDecimal.ZERO, BigDecimal::add) + ); + List list = attendanceList.stream().filter(attendance -> attendance.getUserId().equals(row.getSysUserId()) + && Arrays.asList("1", "2", "3", "5").contains(attendance.getClockStatus()) + ).toList(); + vo.setWorkDay(list.size()*0.5); + + vos.add(vo); + } + + return new TableDataInfo<>(vos,subConstructionUserVoTableDataInfo.getTotal()); + } + + @Override + public void export(HttpServletResponse response, SubConstructionUserSalaryDto dto) throws IOException { + // 1. 查询项目和人员数据 + BusProject project = projectService.getById(dto.getProjectId()); + if (project == null) { + throw new ServiceException("项目不存在"); + } + + List userList = constructionUserService.lambdaQuery() + .eq(SubConstructionUser::getProjectId, dto.getProjectId()) + .eq(dto.getTeamId() != null, SubConstructionUser::getTeamId, dto.getTeamId()) + .like(StringUtils.isNotBlank(dto.getUserName()), SubConstructionUser::getUserName, dto.getUserName()) + .list(); + + if (userList.isEmpty()) { + throw new ServiceException("暂无数据"); + } + + // 2. 解析年月和查询薪资明细 + YearMonth yearMonth = YearMonth.parse(dto.getTime(), DateTimeFormatter.ofPattern("yyyy-MM")); + LocalDate start = yearMonth.atDay(1); + LocalDate end = yearMonth.atEndOfMonth(); + + List userIds = userList.stream().map(SubConstructionUser::getSysUserId).toList(); + List salaryDetails = this.lambdaQuery() + .eq(SubUserSalaryDetail::getProjectId, dto.getProjectId()) + .in(SubUserSalaryDetail::getUserId, userIds) + .between(SubUserSalaryDetail::getReportDate, start, end) + .list(); + + // 3. 设置响应头(下载文件配置) + setResponseHeader(response, yearMonth.getYear(), yearMonth.getMonthValue()); + + // 5. 读取模板文件到字节数组(复用模板) + byte[] templateBytes; + try (InputStream templateStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream("excelTemplate/salary_template.xlsx")) { + if (templateStream == null) { + throw new ServiceException("模板文件不存在(路径:excelTemplate/salary_template.xlsx)"); + } + templateBytes = IOUtils.toByteArray(templateStream); + } + + // 6. POI 处理多 sheet(核心:克隆模板 + 命名) + // 存储 映射,方便后续 EasyExcel 匹配 + Map sheetMap = new LinkedHashMap<>(); + try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(templateBytes)); + ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + + // 校验模板是否有有效 sheet + if (workbook.getNumberOfSheets() == 0) { + throw new ServiceException("模板文件中无任何 sheet 页,请检查模板"); + } + + // 6.1 预处理班组信息(获取班组ID + 班组名称映射) + List teamIds = userList.stream() + .map(SubConstructionUser::getTeamId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + Map teamNameMap = new HashMap<>(); + if (!teamIds.isEmpty()) { + List teams = projectTeamService.lambdaQuery() + .in(BusProjectTeam::getId, teamIds) + .list(); + teamNameMap = teams.stream() + .collect(Collectors.toMap( + BusProjectTeam::getId, + BusProjectTeam::getTeamName, + (oldVal, newVal) -> newVal // 避免重复ID冲突 + )); + } + + // 6.2 克隆模板:为每个班组生成 sheet(关键修正) + for (Long teamId : teamIds) { + // ① 克隆原始模板 sheet(返回克隆后的 Sheet 对象) + Sheet newSheet = workbook.cloneSheet(0); + // ② 生成班组名称(避免空名称) + String teamName = teamNameMap.getOrDefault(teamId, "未知班组_" + teamId); + // ③ 给新 sheet 命名(通过 sheet 对象获取索引) + int newSheetIndex = workbook.getSheetIndex(newSheet); + workbook.setSheetName(newSheetIndex, teamName); + // ④ 存入映射,方便后续填充 + sheetMap.put(teamName, newSheet); + } + + // 6.3 克隆模板:处理“无班组”数据(如果需要) + boolean needNoTeamSheet = dto.getTeamId() == null; + if (needNoTeamSheet) { + Sheet noTeamSheet = workbook.cloneSheet(0); + String noTeamName = "无班组"; + int noTeamSheetIndex = workbook.getSheetIndex(noTeamSheet); + workbook.setSheetName(noTeamSheetIndex, noTeamName); + sheetMap.put(noTeamName, noTeamSheet); + } + + // 6.4 删除原始模板 sheet(避免最终文件保留空模板) + workbook.removeSheetAt(0); + + // 6.5 将 POI 处理后的 workbook 写入字节数组,供 EasyExcel 使用 + workbook.write(bos); + byte[] workbookBytes = bos.toByteArray(); + + // 7. EasyExcel 填充数据(按 sheet 映射顺序填充) + try (InputStream workbookStream = new ByteArrayInputStream(workbookBytes); + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) + .withTemplate(workbookStream) + .build()) { + + // 7.1 填充“班组”sheet 数据 + for (Map.Entry entry : sheetMap.entrySet()) { + String sheetName = entry.getKey(); + // 跳过“无班组”sheet,后续单独处理 + if ("无班组".equals(sheetName)) { + continue; + } + // 根据 sheet 名称反查班组ID(用于过滤数据) + Long teamId = teamNameMap.entrySet().stream() + .filter(e -> sheetName.equals(e.getValue())) + .map(Map.Entry::getKey) + .findFirst() + .orElse(null); + + // 创建 EasyExcel 的 WriteSheet(通过名称匹配 sheet) + WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build(); + FillConfig fillConfig = FillConfig.builder() + .forceNewRow(true) // 强制新增行,不覆盖模板内容 + .build(); + + // 填充列表数据和汇总数据 + excelWriter.fill(getTeamData(userList, salaryDetails, teamId), fillConfig, writeSheet); + excelWriter.fill(getTeamSummary(project, teamNameMap.get(teamId), yearMonth), writeSheet); + } + + // 7.2 填充“无班组”sheet 数据 + if (needNoTeamSheet) { + WriteSheet noTeamSheet = EasyExcel.writerSheet("无班组").build(); + FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build(); + + excelWriter.fill(getTeamData(userList, salaryDetails, null), fillConfig, noTeamSheet); + excelWriter.fill(getTeamSummary(project, null, yearMonth), noTeamSheet); + } + } + } + } + + /** + * 设置响应头信息 + */ + private void setResponseHeader(HttpServletResponse response, int year, int month) throws IOException { + // 文件名编码,解决中文乱码 + String fileName = URLEncoder.encode(year + "年" + month + "月多部门考勤表.xlsx", "UTF-8"); + // 设置内容类型 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + // 设置下载文件名 + response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + fileName); + // 禁止缓存 + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", 0); + } + + private List getTeamData(List rows, + List salaryDetailList,Long teamId){ + List list1 ; + if(teamId == null){ + list1 = rows.stream().filter(row -> row.getTeamId() == null && Arrays.asList("1","2").contains(row.getExitStatus())).toList(); + }else { + list1 = rows.stream().filter(row -> teamId.equals(row.getTeamId())).toList(); + } + ArrayList vos = new ArrayList<>(); + int i =1; + for (SubConstructionUser row : list1) { + SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo(); + BeanUtil.copyProperties(row,vo); + vo.setOrder(i); + vo.setTotalSalary(salaryDetailList.stream().filter(detail -> detail.getUserId().equals(row.getSysUserId())) + .map(SubUserSalaryDetail::getDailySalary) + .reduce(BigDecimal.ZERO, BigDecimal::add) + ); + vos.add(vo); + i++; + } + return vos; + } + + + private Map getTeamSummary(BusProject project,String teamName,YearMonth parse) { + + // 模拟汇总数据 + return Map.of( + "time", parse.format(DateTimeFormatter.ofPattern("yyyy年MM月")), + "projectName", project.getProjectName(), + "teamName", teamName == null? "无班组":teamName + ); + } } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java index 2560375a..1e4eee69 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java @@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.project.domain.dto.attendance.AttendanceExportDto; +import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import org.dromara.common.idempotent.annotation.RepeatSubmit; @@ -102,4 +104,16 @@ public class BusAttendanceController extends BaseController { @PathVariable Long[] ids) { return toAjax(busAttendanceService.deleteWithValidByIds(List.of(ids), true)); } + + + @GetMapping("/list/clockDate/twoWeek") + public R> getClockDateForTwoWeekList(Long projectId) { + return R.ok(busAttendanceService.getClockDateForTwoWeekList(projectId)); + } + + @GetMapping("/exportList") + public void exportList(AttendanceExportDto dto, HttpServletResponse response) { + busAttendanceService.getExportList(dto, response); + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java index 641ef4b4..16fe6c47 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java @@ -64,7 +64,7 @@ public class BusAttendanceAppController extends BaseController { /** * 人脸坐标打卡 */ - @RepeatSubmit(interval = 3, timeUnit = TimeUnit.SECONDS,message = "3分钟内禁止重复打卡") + @RepeatSubmit(interval = 3, timeUnit = TimeUnit.MINUTES,message = "3分钟内禁止重复打卡") @PostMapping("/punch/card/face") public R punchCardByFace(@RequestPart("file") MultipartFile file, BusAttendancePunchCardByFaceReq req) { return R.ok(attendanceService.punchCardByFace(file, req)); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/AttendanceExportDto.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/AttendanceExportDto.java new file mode 100644 index 00000000..63a884d0 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/AttendanceExportDto.java @@ -0,0 +1,33 @@ +package org.dromara.project.domain.dto.attendance; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class AttendanceExportDto { + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 工种 + */ + private String typeOfWork; + + /** + * 打卡月份 + */ + private String clockDate; +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java index e9a41a61..d509b9b0 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java @@ -5,6 +5,7 @@ import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.time.LocalDate; import java.util.Date; /** @@ -20,10 +21,7 @@ public class BusAttendanceClockDateForTwoWeekVo implements Serializable { /** * 打卡日期 */ - @JsonFormat(shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd", - timezone = "GMT+8") - private Date clockDate; + private LocalDate clockDate; /** * 出勤人数 diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java index a9a886fa..6a957402 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java @@ -1,6 +1,9 @@ package org.dromara.project.mapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.bo.BusAttendanceBo; import org.dromara.project.domain.vo.BusAttendanceVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; @@ -12,4 +15,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; */ public interface BusAttendanceMapper extends BaseMapperPlus { + + Page queryPageList(BusAttendanceBo bo, PageQuery pageQuery); + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java index 2d83ec28..5b2e8f92 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java @@ -1,7 +1,10 @@ package org.dromara.project.service; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; import org.dromara.project.domain.dto.attendance.AttendanceCountDto; +import org.dromara.project.domain.dto.attendance.AttendanceExportDto; import org.dromara.project.domain.dto.attendance.AttendanceUserCountDto; import org.dromara.project.domain.dto.attendance.BusAttendancePunchCardByFaceReq; import org.dromara.project.domain.vo.BusAttendanceVo; @@ -153,4 +156,16 @@ public interface IBusAttendanceService extends IService{ * 指定月份的打卡人员信息 */ AttendanceUserInfoVo getAttendanceUserInfo(AttendanceUserCountDto dto); + + /** + * 近两周打卡统计 + */ + List getClockDateForTwoWeekList(Long projectId); + + /** + * 获取导出的考勤数据 + */ + void getExportList(AttendanceExportDto dto,HttpServletResponse response); + + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java index 301c5e55..9a30ef49 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java @@ -6,13 +6,16 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.poi.ss.formula.functions.T; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; @@ -21,14 +24,15 @@ import org.dromara.common.domain.GeoPoint; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.utils.IdCardEncryptorUtil; import org.dromara.common.utils.JSTUtil; import org.dromara.contractor.domain.SubConstructionUser; -import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; import org.dromara.contractor.service.ISubConstructionUserService; import org.dromara.contractor.service.ISubUserSalaryDetailService; import org.dromara.project.domain.*; import org.dromara.project.domain.bo.BusAttendanceBo; import org.dromara.project.domain.dto.attendance.AttendanceCountDto; +import org.dromara.project.domain.dto.attendance.AttendanceExportDto; import org.dromara.project.domain.dto.attendance.AttendanceUserCountDto; import org.dromara.project.domain.dto.attendance.BusAttendancePunchCardByFaceReq; import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; @@ -47,10 +51,10 @@ import org.dromara.websocket.ChatServerHandler; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; +import java.io.IOException; +import java.io.OutputStream; +import java.time.*; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -98,6 +102,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl getPunchRangeByProjectIdAndUserId(Long projectId, Long userId) { BusUserProjectRelevancy relevancy = userProjectRelevancyService.getOne(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) @@ -433,7 +438,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl matchingRange = JSTUtil.findMatchingRange(req.getLat(), req.getLng(), punchRangeList); return matchingRange != null; @@ -634,7 +639,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl attendanceList = baseMapper.selectList(Wrappers.lambdaQuery() .eq(BusAttendance::getProjectId, dto.getProjectId()) - .in(BusAttendance::getClockStatus,Arrays.asList("1","2","3","5","7")) + .in(BusAttendance::getClockStatus, Arrays.asList("1", "2", "3", "5", "7")) .eq(BusAttendance::getClockDate, dto.getDate()) ); List attendanceUserIds = attendanceList.stream().map(BusAttendance::getUserId).toList(); @@ -642,7 +647,7 @@ public class BusAttendanceServiceImpl extends ServiceImpllambdaQuery() .eq(SubConstructionUser::getProjectId, dto.getProjectId())); - attendanceCountVo.setTotalCount((int)count); + attendanceCountVo.setTotalCount((int) count); //出勤人数 HashSet longs = new HashSet<>(attendanceUserIds); int size = longs.size(); @@ -656,15 +661,15 @@ public class BusAttendanceServiceImpl extends ServiceImpl attendanceList = baseMapper.selectList(Wrappers.lambdaQuery() .eq(BusAttendance::getProjectId, dto.getProjectId()) - .in(BusAttendance::getClockStatus,Arrays.asList("1","2","3","5","7")) + .in(BusAttendance::getClockStatus, Arrays.asList("1", "2", "3", "5", "7")) .eq(BusAttendance::getClockDate, dto.getDate()) ); List attendanceUserIds = attendanceList.stream().map(BusAttendance::getUserId).toList(); - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SubConstructionUser::getProjectId, dto.getProjectId()); - if("1".equals(dto.getClockStatus()) && CollectionUtil.isEmpty(attendanceUserIds)){ + if ("1".equals(dto.getClockStatus()) && CollectionUtil.isEmpty(attendanceUserIds)) { TableDataInfo rspData = new TableDataInfo<>(); rspData.setCode(cn.hutool.http.HttpStatus.HTTP_OK); rspData.setMsg("查询成功"); @@ -673,10 +678,10 @@ public class BusAttendanceServiceImpl extends ServiceImpl result = constructionUserService.page(pageQuery.build(), wrapper); List records = result.getRecords(); @@ -688,14 +693,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl earlyList = attendanceList.stream().filter(a -> "3".equals(a.getClockStatus())) + List earlyList = attendanceList.stream().filter(a -> "3".equals(a.getClockStatus())) .map(BusAttendanceVo::getClockDate) .toList(); attendanceUserCountVo.setEarlyNum(earlyList.size()); - List absentList = attendanceList.stream().filter(a -> "4".equals(a.getClockStatus())) + List absentList = attendanceList.stream().filter(a -> "4".equals(a.getClockStatus())) .map(BusAttendanceVo::getClockDate) .toList(); attendanceUserCountVo.setAbsentNum(absentList.size()); @@ -811,6 +816,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl getClockDateForTwoWeekList(Long projectId) { + LocalDate now = LocalDate.now(); + //往前14天,包含今天 + LocalDate startDate = now.minusDays(13); + List list = list(Wrappers.lambdaQuery().eq(BusAttendance::getProjectId, projectId) + .between(BusAttendance::getClockDate, startDate, now) + ); + + // 按日期分组 + Map> groupedByDate = list.stream() + .collect(Collectors.groupingBy(BusAttendance::getClockDate)); + + // 按日期和用户ID分组 + Map>> dateUserMap = new HashMap<>(); + for (Map.Entry> entry : groupedByDate.entrySet()) { + LocalDate date = entry.getKey(); + Map> userAttendanceMap = entry.getValue().stream() + .collect(Collectors.groupingBy(BusAttendance::getUserId)); + dateUserMap.put(date, userAttendanceMap); + } + + // 统计全勤、半勤、缺卡人数 + ArrayList busAttendanceClockDateForTwoWeekVos = new ArrayList<>(); + + List list1 = Arrays.asList("1", "2", "3", "5"); + + for (Map.Entry>> dateEntry : dateUserMap.entrySet()) { + LocalDate date = dateEntry.getKey(); + Map> userAttendanceMap = dateEntry.getValue(); + + int full = 0, half = 0, absent = 0; + + for (Map.Entry> userEntry : userAttendanceMap.entrySet()) { + List records = userEntry.getValue(); + + int a = 0; + for (BusAttendance record : records) { + if (list1.contains(record.getClockStatus())) { + a += 1; + } + } + if (a >= 2) { + full++; + } else if (a == 1) { + half++; + } else { + absent++; + } + } + BusAttendanceClockDateForTwoWeekVo busAttendanceClockDateForTwoWeekVo = new BusAttendanceClockDateForTwoWeekVo(); + busAttendanceClockDateForTwoWeekVo.setClockDate(date); + busAttendanceClockDateForTwoWeekVo.setAttendance(full); + busAttendanceClockDateForTwoWeekVo.setHalfAttendance(half); + busAttendanceClockDateForTwoWeekVo.setAbsenteeism(absent); + + busAttendanceClockDateForTwoWeekVos.add(busAttendanceClockDateForTwoWeekVo); + } + return busAttendanceClockDateForTwoWeekVos; + } + + @Override + public void getExportList(AttendanceExportDto dto, HttpServletResponse response) { + + BusProject project = projectService.getById(dto.getProjectId()); + + if (project == null) { + throw new ServiceException("项目不存在"); + } + + List list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class) + .eq(SubConstructionUser::getProjectId, dto.getProjectId()) + .eq(dto.getTeamId() != null, SubConstructionUser::getTeamId, dto.getTeamId()) + .eq(StrUtil.isNotBlank(dto.getTypeOfWork()), SubConstructionUser::getTypeOfWork, dto.getTypeOfWork()) + .like(StringUtils.isNotBlank(dto.getUserName()), SubConstructionUser::getUserName, dto.getUserName()) + ); + + if (list.isEmpty()) { + throw new ServiceException("未查询到相关人员"); + } + + List userIds = list.stream().map(SubConstructionUser::getSysUserId).toList(); + String clockDate = dto.getClockDate(); + + YearMonth yearMonth = YearMonth.parse(clockDate, DateTimeFormatter.ofPattern("yyyy-MM")); + LocalDate start = yearMonth.atDay(1); + LocalDate end = yearMonth.atEndOfMonth(); + + int daysInMonth = yearMonth.lengthOfMonth(); // 动态获取天数 + + List attendanceList = list(Wrappers.lambdaQuery(BusAttendance.class) + .in(BusAttendance::getUserId, userIds) + .between(BusAttendance::getClockDate, start, end) + ); + + Map> teamUserMap = list.stream() + .filter(user -> user.getTeamId() != null) + .collect(Collectors.groupingBy(SubConstructionUser::getTeamId)); + + Workbook workbook = new HSSFWorkbook(); + + for (Map.Entry> entry : teamUserMap.entrySet()) { + Long teamId = entry.getKey(); + List users = entry.getValue(); + SubConstructionUser constructionUser = users.getFirst(); + String teamName = constructionUser.getTeamName(); + Sheet sheet = workbook.createSheet(teamName); + + // ==================== 设置列宽 ==================== + sheet.setColumnWidth(0, 5* 256); // 序号 + sheet.setColumnWidth(1, 10* 256); // 姓名/日期 + sheet.setColumnWidth(2, 30* 256); // 身份证号 + + // 日期列(每天一列) + for (int i = 3; i < 3 + daysInMonth; i++) { + sheet.setColumnWidth(i, 5* 256); // 每天列宽 15 字符 + } + + sheet.setColumnWidth(3 + daysInMonth, 5* 256); // 合计 + sheet.setColumnWidth(3 + daysInMonth + 1, 10* 256); // 是否离场 + sheet.setColumnWidth(3 + daysInMonth + 2, 15* 256); // 签字 + + // ==================== 表头部分 ==================== + Row titleRow = sheet.createRow(0); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellValue("建筑施工企业现场人员考勤表(" + clockDate + "月)"); + titleCell.setCellStyle(createTitleCellStyle(workbook)); + + // 合并标题行,横跨所有列 + int totalColumns = 3 + daysInMonth + 3; // 总列数 + sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, totalColumns - 1)); + + // ==================== 第二行:项目名称和班组类别 ==================== + Row projectRow = sheet.createRow(1); + + // 设置项目名称(左对齐,占据前半部分) + Cell projectNameCell = projectRow.createCell(0); + projectNameCell.setCellValue("项目名称:" + project.getProjectName()); + projectNameCell.setCellStyle(createProjectCellStyle(workbook)); // 可选:设置样式 + + int midColumn = (totalColumns / 2) - 1; + + // 设置班组类别(右对齐,占据后半部分) + int teamCol = midColumn +1; // + Cell teamNameCell = projectRow.createCell(teamCol); + teamNameCell.setCellValue("班组类别:" + teamName); + teamNameCell.setCellStyle(createProjectCellStyle(workbook)); + + // 合并项目名称区域(从第 0 列到中间) + if (midColumn >= 0) { + sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, midColumn)); + } + + // 合并班组类别区域(从 teamCol 开始,到最后一列) + if (teamCol < totalColumns) { + sheet.addMergedRegion(new CellRangeAddress(1, 1, teamCol, totalColumns - 1)); + } + + // ==================== 数据表头 ==================== + Row headerRow = sheet.createRow(2); + writeHeaderRow(headerRow, daysInMonth); + + // ==================== 数据行 ==================== + int rowIndex = 3; + for (SubConstructionUser user : users) { + Row row = sheet.createRow(rowIndex++); + writeDataRow(row, user, attendanceList, start, end, daysInMonth); + } + + // ==================== 表尾部分 ==================== + + sheet.createRow(rowIndex++); + + Row footerRow1 = sheet.createRow(rowIndex++); + int allTotalColumns = 3 + daysInMonth + 3; + int quarter = allTotalColumns / 4; + + int[] colSpans = { + quarter - 3, // 第一列减少3列 + quarter + 2, // 第二列增加2列 + quarter + 2, // 第三列增加2列 + allTotalColumns - (quarter - 3 + quarter + 2 + quarter + 2) // 自动计算最后一列 + }; + + int startCol = 0; + String[] footerLabels = {"制表人:", "班组负责人:", "项目负责人:", "制表日期:"}; + for (int i = 0; i < 4; i++) { + int endCol = startCol + colSpans[i] - 1; + + // 合并单元格 + sheet.addMergedRegion(new CellRangeAddress(rowIndex - 1, rowIndex - 1, startCol, endCol)); + + // 创建单元格并设置内容 + Cell cell = footerRow1.createCell(startCol); + cell.setCellValue(footerLabels[i]); + cell.setCellStyle(createLeftAlignedCellStyle(workbook)); // 左对齐 + + startCol = endCol + 1; + } + + Row footerRow2 = sheet.createRow(rowIndex++); + footerRow2.createCell(0).setCellValue("注:"); + footerRow2.createCell(1).setCellValue("1、本考勤表必须按照每日实际工时进行填写;"); + Row footerRow3 = sheet.createRow(rowIndex++); + footerRow3.createCell(0).setCellValue(""); + footerRow3.createCell(1).setCellValue("2、本考勤表作为工资计发的重要依据。"); + + } + + try (OutputStream outputStream = response.getOutputStream()) { + workbook.write(outputStream); + workbook.close(); + } catch (IOException e) { + log.error("导出失败", e); + throw new ServiceException("导出失败"); + } + } + + private CellStyle createProjectCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontHeightInPoints((short) 10); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + return style; + } + + private CellStyle createTitleCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontHeightInPoints((short) 16); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + return style; + } + + private void writeHeaderRow(Row row, int daysInMonth) { + row.createCell(0).setCellValue("序号"); + row.createCell(1).setCellValue("姓名/日期"); + row.createCell(2).setCellValue("身份证号"); + + for (int i = 1; i <= daysInMonth; i++) { + row.createCell(2 + i).setCellValue(String.valueOf(i)); + } + + row.createCell(2 + daysInMonth + 1).setCellValue("合计"); + row.createCell(2 + daysInMonth + 2).setCellValue("是否离场"); + row.createCell(2 + daysInMonth + 3).setCellValue("签字"); + } + + private void writeDataRow(Row row, SubConstructionUser user, List attendanceList, LocalDate start, LocalDate end, int daysInMonth) { + int index = row.getRowNum(); + row.createCell(0).setCellValue(index); + row.createCell(1).setCellValue(user.getUserName()); + row.createCell(2).setCellValue(idCardEncryptorUtil.decrypt(user.getSfzNumber())); + + for (int i = 1; i <= daysInMonth; i++) { + LocalDate date = start.plusDays(i - 1); + String value = getAttendanceValue(user.getSysUserId(), date, attendanceList); + row.createCell(2 + i).setCellValue(value); + } + + double total = countAttendance(user.getSysUserId(), attendanceList, start, end); + row.createCell(2 + daysInMonth + 1).setCellValue(total); + + String leaveStatus = "0".equals(user.getExitStatus()) ? "未离场" : "已离场"; + row.createCell(2 + daysInMonth + 2).setCellValue(leaveStatus); + + row.createCell(2 + daysInMonth + 3).setCellValue(""); + } + + private String getAttendanceValue(Long userId, LocalDate date, List attendanceList) { + List validRecords = attendanceList.stream() + .filter(a -> a.getUserId().equals(userId) && a.getClockDate().equals(date)) + .filter(a -> !a.getClockStatus().equals("4")) // 排除缺卡记录 + .collect(Collectors.toList()); + + if (validRecords.isEmpty()) { + return "0"; // 无有效打卡 + } + + // 检查是否有有效出勤状态(1,2,3,5) + boolean hasValidStatus = validRecords.stream() + .anyMatch(a -> Arrays.asList("1", "2", "3", "5").contains(a.getClockStatus())); + + if (!hasValidStatus) { + return "0"; // 状态无效,如补卡、其他异常 + } + + // 判断是否为半勤(仅一次有效打卡) + if (validRecords.size() == 1) { + return "0.5"; + } + + // 正常出勤(两次有效打卡) + return "1"; + } + + private double countAttendance(Long userId, List attendanceList, LocalDate start, LocalDate end) { + double total = 0.0; + LocalDate current = start; + + while (!current.isAfter(end)) { + String value = getAttendanceValue(userId, current, attendanceList); + if ("1".equals(value)) { + total += 1.0; + } else if ("0.5".equals(value)) { + total += 0.5; + } + current = current.plusDays(1); + } + + return total; + } + + private CellStyle createLeftAlignedCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.LEFT); // 左对齐 + style.setVerticalAlignment(VerticalAlignment.CENTER); + return style; + } + + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java index c02cc8b1..9f3e53e6 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java @@ -31,17 +31,16 @@ import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; import org.dromara.project.mapper.BusProjectTeamMemberMapper; import org.dromara.project.service.*; import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.SysUserRole; import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserRoleMapper; import org.dromara.system.service.ISysUserService; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; /** @@ -77,6 +76,9 @@ public class BusProjectTeamMemberServiceImpl extends ServiceImpl sysUserRoles = userRoleMapper.selectList(Wrappers.lambdaQuery() + .eq(SysUserRole::getUserId, constructionUser.getSysUserId()) + .eq(SysUserRole::getProjectId, req.getProjectId()) + .in(SysUserRole::getRoleId, Arrays.asList(2L, 3L)) + ); + if (CollUtil.isEmpty(sysUserRoles)) { + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(constructionUser.getSysUserId()); + sysUserRole.setRoleId("0".equals(req.getPostId()) ? 2L : 3L); + sysUserRole.setProjectId(req.getProjectId()); + userRoleMapper.insert(sysUserRole); + } else { + Long roleId = "0".equals(req.getPostId()) ? 2L : 3L; + List list1 = sysUserRoles.stream().map(SysUserRole::getRoleId).toList(); + if (!list1.contains(roleId)){ + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(constructionUser.getSysUserId()); + sysUserRole.setRoleId(roleId); + sysUserRole.setProjectId(req.getProjectId()); + userRoleMapper.insert(sysUserRole); + } + } return projectTeamMember.getId(); } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/ChatServerHandler.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/ChatServerHandler.java index 47075a1b..d9372aa6 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/ChatServerHandler.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/ChatServerHandler.java @@ -37,30 +37,26 @@ import java.util.concurrent.ConcurrentHashMap; public class ChatServerHandler extends SimpleChannelInboundHandler { // 移除 @Autowired 注解 + private static ChatHistoryServiceImpl chatHistoryService; + private static ChatGroupServiceImpl chatGroupService; + private static SysUserServiceImpl sysUserService; + private static SysOssServiceImpl sysOssService; @Autowired - private ChatHistoryServiceImpl chatHistoryService; + public void setChatHistoryService(ChatHistoryServiceImpl service) { + chatHistoryService = service; + } @Autowired - private ChatGroupServiceImpl chatGroupService; + public void setChatGroupService(ChatGroupServiceImpl service){ + chatGroupService = service; + } @Autowired - private SysUserServiceImpl sysUserService; + public void setSysUserService(SysUserServiceImpl service){ + sysUserService = service; + } @Autowired - private SysOssServiceImpl sysOssService; -// @Autowired -// public void setChatHistoryService(ChatHistoryServiceImpl service) { -// chatHistoryService = service; -// } -// @Autowired -// public void setChatGroupService(ChatGroupServiceImpl service){ -// chatGroupService = service; -// } -// @Autowired -// public void setSysUserService(SysUserServiceImpl service){ -// sysUserService = service; -// } -// @Autowired -// public void setSysOssService(SysOssServiceImpl service){ -// sysOssService = service; -// } + public void setSysOssService(SysOssServiceImpl service){ + sysOssService = service; + } // 存储所有连接的客户端Channel private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/controller/ChatGroupController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/controller/ChatGroupController.java index 6b41bbe2..d43ed0b9 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/controller/ChatGroupController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/websocket/controller/ChatGroupController.java @@ -156,6 +156,11 @@ public class ChatGroupController { return R.fail(); } + @GetMapping("/testSys") + public void testSys(Long userId, String message){ + chatServerHandler.sendSystemMessageToUser(userId, message,"1"); + } + /*** * 获取房间聊天记录 传递房间ID 获取发送给该房间的所有聊天记录 */ From 2f57979a411c252169100038fd04a8b61c0c3644 Mon Sep 17 00:00:00 2001 From: dfdg <2710245601@qq.com> Date: Mon, 15 Sep 2025 19:47:20 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=90=88=E8=A7=84=E6=80=A7=E6=89=8B?= =?UTF-8?q?=E7=BB=AD=E4=BF=AE=E6=94=B9=E7=8A=B6=E6=80=81=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/formalities/enums/FormalitiesStatusEnum.java | 3 ++- .../impl/BusFormalitiesAreConsolidatedServiceImpl.java | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/enums/FormalitiesStatusEnum.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/enums/FormalitiesStatusEnum.java index 895422f3..3b69e780 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/enums/FormalitiesStatusEnum.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/enums/FormalitiesStatusEnum.java @@ -7,7 +7,8 @@ public enum FormalitiesStatusEnum { TOSTART("待开始", "0"), PROCESSING("处理中", "1"), - DELETE("已完成", "2"); + DELETE("已完成", "2"), + NOHANDLE("不需要办理", "3"); private final String text; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java index 7f8f85c4..048389d3 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/formalities/service/impl/BusFormalitiesAreConsolidatedServiceImpl.java @@ -252,7 +252,8 @@ public class BusFormalitiesAreConsolidatedServiceImpl extends ServiceImpl