From dd71325ea857403255396fac0a0c518a35ba2051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B7=AF=20=E8=8C=83?= Date: Thu, 31 Mar 2022 09:07:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Ewide.Core/Service/Auth/AuthService.cs | 2 +- .../Ewide.Core/Util/DEntityExtensions.cs | 58 ++++ 20220330_Vote/Ewide.Web.Core/Startup.cs | 2 +- .../Controllers/ManageController.cs | 26 ++ .../Controllers/VoteController.cs | 4 +- .../Ewide.Web.Entry/Ewide.Web.Entry.csproj | 24 ++ .../Views/Manage/Expert.cshtml | 120 ++++++++ .../Ewide.Web.Entry/Views/Manage/Index.cshtml | 260 ++++++++++++++++ .../Ewide.Web.Entry/Views/Manage/Login.cshtml | 269 ++++++++++++++++ .../Views/Shared/_Layout.cshtml | 2 +- .../Ewide.Web.Entry/Views/Vote/Index.cshtml | 289 ++++++++++++++++++ .../ExcelTemplate/2021年度甬江杯投票.xlsx | Bin 0 -> 22407 bytes .../ApiController/ProjectsService.cs | 160 +++++++++- .../Vote.Services/Dto/ProjectsInput.cs | 75 +++++ .../Vote.Services/Tools/ExcelHelper.cs | 212 +++++++++++++ .../Vote.Services/Vote.Services.csproj | 18 ++ 20220330_Vote/Vote.Services/Vote.Services.xml | 134 +++++++- 17 files changed, 1644 insertions(+), 11 deletions(-) create mode 100644 20220330_Vote/Ewide.Core/Util/DEntityExtensions.cs create mode 100644 20220330_Vote/Ewide.Web.Entry/Controllers/ManageController.cs create mode 100644 20220330_Vote/Ewide.Web.Entry/Views/Manage/Expert.cshtml create mode 100644 20220330_Vote/Ewide.Web.Entry/Views/Manage/Index.cshtml create mode 100644 20220330_Vote/Ewide.Web.Entry/Views/Manage/Login.cshtml create mode 100644 20220330_Vote/Ewide.Web.Entry/wwwroot/ExcelTemplate/2021年度甬江杯投票.xlsx create mode 100644 20220330_Vote/Vote.Services/Tools/ExcelHelper.cs diff --git a/20220330_Vote/Ewide.Core/Service/Auth/AuthService.cs b/20220330_Vote/Ewide.Core/Service/Auth/AuthService.cs index 1580edd..c05d8ad 100644 --- a/20220330_Vote/Ewide.Core/Service/Auth/AuthService.cs +++ b/20220330_Vote/Ewide.Core/Service/Auth/AuthService.cs @@ -82,7 +82,7 @@ namespace Ewide.Core.Service /// /// 默认用户名/密码:admin/admin /// - [HttpPost("/login")] + [HttpPost("/gb/yjb/login")] [AllowAnonymous] [Op(LogOpType.GRANT)] public async Task LoginAsync([Required] LoginInput input) diff --git a/20220330_Vote/Ewide.Core/Util/DEntityExtensions.cs b/20220330_Vote/Ewide.Core/Util/DEntityExtensions.cs new file mode 100644 index 0000000..c4dde1e --- /dev/null +++ b/20220330_Vote/Ewide.Core/Util/DEntityExtensions.cs @@ -0,0 +1,58 @@ +using Furion; +using Furion.DatabaseAccessor; +using Furion.DatabaseAccessor.Extensions; +using Furion.LinqBuilder; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Core.Util +{ + public static class DEntityExtensions + { + public async static Task InsertOrUpdate(this TEntity entity) where TEntity : DEntityBase, IPrivateEntity, new() + { + if (entity.Id.IsNullOrEmpty()) + await entity.SetInsertDefaultValue().InsertAsync(); + else + await entity.SetUpdateDefaultValue().UpdateExcludeAsync(new[] { nameof(entity.CreatedTime), nameof(entity.CreatedUserId), nameof(entity.CreatedUserName) }); + return entity; + } + public async static Task InsertOrUpdate(this TEntity entity, bool isInsert) where TEntity : DEntityBase, IPrivateEntity, new() + { + if (isInsert) + await entity.SetInsertDefaultValue().InsertAsync(); + else + await entity.SetUpdateDefaultValue().UpdateAsync(); + return entity; + } + public static TEntity SetInsertDefaultValue(this TEntity entity) where TEntity : DEntityBase + { + if (string.IsNullOrEmpty(entity.Id)) + entity.Id = Guid.NewGuid().ToString(); + if (!entity.CreatedTime.HasValue) + entity.CreatedTime = DateTime.Now; + //if (string.IsNullOrEmpty(entity.CreatedUserId)) + entity.CreatedUserId = GetUserId(); + if (string.IsNullOrEmpty(entity.CreatedUserName)) + entity.CreatedUserName = App.GetService().Name; + return entity; + } + public static TEntity SetUpdateDefaultValue(this TEntity entity) where TEntity : DEntityBase + { + entity.UpdatedTime = DateTime.Now; + entity.UpdatedUserId = GetUserId(); + entity.UpdatedUserName = App.GetService().Name; + return entity; + } + private static string GetUserId() + { + var userid = App.GetService().UserId; + //if (string.IsNullOrWhiteSpace(userid)) + // userid = App.GetService().WorkUSERID; + return userid; + } + } +} diff --git a/20220330_Vote/Ewide.Web.Core/Startup.cs b/20220330_Vote/Ewide.Web.Core/Startup.cs index 872875c..7239c9d 100644 --- a/20220330_Vote/Ewide.Web.Core/Startup.cs +++ b/20220330_Vote/Ewide.Web.Core/Startup.cs @@ -107,7 +107,7 @@ namespace Ewide.Web.Core { endpoints.MapControllerRoute( name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); + pattern: "gb/yjb/{controller=Home}/{action=Index}/{id?}"); }); } } diff --git a/20220330_Vote/Ewide.Web.Entry/Controllers/ManageController.cs b/20220330_Vote/Ewide.Web.Entry/Controllers/ManageController.cs new file mode 100644 index 0000000..14b4505 --- /dev/null +++ b/20220330_Vote/Ewide.Web.Entry/Controllers/ManageController.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ewide.Web.Entry.Controllers +{ + [AllowAnonymous] + public class ManageController : Controller + { + public IActionResult Index() + { + return View(); + } + public IActionResult Login() + { + return View(); + } + public IActionResult Expert() + { + return View(); + } + } +} diff --git a/20220330_Vote/Ewide.Web.Entry/Controllers/VoteController.cs b/20220330_Vote/Ewide.Web.Entry/Controllers/VoteController.cs index 1d3bb32..b4367dd 100644 --- a/20220330_Vote/Ewide.Web.Entry/Controllers/VoteController.cs +++ b/20220330_Vote/Ewide.Web.Entry/Controllers/VoteController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; @@ -6,6 +7,7 @@ using System.Threading.Tasks; namespace Ewide.Web.Entry.Controllers { + [AllowAnonymous] public class VoteController : Controller { public IActionResult Index() diff --git a/20220330_Vote/Ewide.Web.Entry/Ewide.Web.Entry.csproj b/20220330_Vote/Ewide.Web.Entry/Ewide.Web.Entry.csproj index 968bca3..2482c34 100644 --- a/20220330_Vote/Ewide.Web.Entry/Ewide.Web.Entry.csproj +++ b/20220330_Vote/Ewide.Web.Entry/Ewide.Web.Entry.csproj @@ -78,4 +78,28 @@ + + + bin\Debug\net5.0\ICSharpCode.SharpZipLib.dll + + + bin\Debug\net5.0\NPOI.dll + + + bin\Debug\net5.0\NPOI.OOXML.dll + + + bin\Debug\net5.0\NPOI.OpenXml4Net.dll + + + bin\Debug\net5.0\NPOI.OpenXmlFormats.dll + + + + + + PreserveNewest + + + diff --git a/20220330_Vote/Ewide.Web.Entry/Views/Manage/Expert.cshtml b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Expert.cshtml new file mode 100644 index 0000000..5faf79c --- /dev/null +++ b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Expert.cshtml @@ -0,0 +1,120 @@ +@* + For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 +*@ +@{ +} + + + + + + + + + + + + + + +
+

2021年度宁波市“甬江建设杯”选票结果

+ + + + + + + +

+ 刷新数据 + 查看项目投票情况 +

+
+ + + + + \ No newline at end of file diff --git a/20220330_Vote/Ewide.Web.Entry/Views/Manage/Index.cshtml b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Index.cshtml new file mode 100644 index 0000000..87f22f8 --- /dev/null +++ b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Index.cshtml @@ -0,0 +1,260 @@ +@* + For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 +*@ +@{ +} + + + + + + + + + + + + + + +
+

2021年度宁波市“甬江建设杯”选票结果

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ 刷新数据 + 导出Excel + 查看专家投票情况 +

+
+ + + + + \ No newline at end of file diff --git a/20220330_Vote/Ewide.Web.Entry/Views/Manage/Login.cshtml b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Login.cshtml new file mode 100644 index 0000000..50b04de --- /dev/null +++ b/20220330_Vote/Ewide.Web.Entry/Views/Manage/Login.cshtml @@ -0,0 +1,269 @@ +@* + For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 +*@ +@{ +} + + + + + + + + + + + + + + + +
+

后台登录

+ + + + + + + + + + 登录 + @*重置*@ + + +
+ + + + + \ No newline at end of file diff --git a/20220330_Vote/Ewide.Web.Entry/Views/Shared/_Layout.cshtml b/20220330_Vote/Ewide.Web.Entry/Views/Shared/_Layout.cshtml index 84dc8a3..86df639 100644 --- a/20220330_Vote/Ewide.Web.Entry/Views/Shared/_Layout.cshtml +++ b/20220330_Vote/Ewide.Web.Entry/Views/Shared/_Layout.cshtml @@ -3,7 +3,7 @@ - @ViewData["Title"] - Furion + 2021年度宁波市“甬江建设杯”选票 @RenderBody() diff --git a/20220330_Vote/Ewide.Web.Entry/Views/Vote/Index.cshtml b/20220330_Vote/Ewide.Web.Entry/Views/Vote/Index.cshtml index e1dd794..9958614 100644 --- a/20220330_Vote/Ewide.Web.Entry/Views/Vote/Index.cshtml +++ b/20220330_Vote/Ewide.Web.Entry/Views/Vote/Index.cshtml @@ -3,3 +3,292 @@ *@ @{ } + + + + + + + + + + + + + + +
+

2021年度宁波市“甬江建设杯”选票

+ + + + {{project.serial_number}}:{{project.name}} + + + + + + + + {{project.serial_number}}:{{project.name}} + + + + + + + + {{project.serial_number}}:{{project.name}} + + + + + + + + {{project.serial_number}}:{{project.name}} + + + + + + + + {{project.serial_number}}:{{project.name}} + + + + + + + + {{project.serial_number}}:{{project.name}} + + + + + + +

+ +

+

+ 全部同意 + 提交 +

+
+ + + + + \ No newline at end of file diff --git a/20220330_Vote/Ewide.Web.Entry/wwwroot/ExcelTemplate/2021年度甬江杯投票.xlsx b/20220330_Vote/Ewide.Web.Entry/wwwroot/ExcelTemplate/2021年度甬江杯投票.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c66bf71567e6cdbf640eca6a82d4dd50b15ed902 GIT binary patch literal 22407 zcma%h19acn^LE&%QNxCfZ5xekCv9xoYHTNst;V)(HMZ5*dcW!JcDujb|2c0?&uP!x zxiinqGcz~0pDQB{3I+}I`V%0v!Tb96Uq4WQf9P52%Gg+1+0w`W)Q|xJ$e(ItM%}J5 zz(7FuAV5F}zpH6mSy4Ngo25q6iFfg0^*DB%AXr$I)#A%hllcUP%w;yFCwMOSZc#5i z!Is2idjPTUu_J55TEJzc_b%L1H4}~#Z){yZ-{3^7`s%h=zjJ+$PEm6{AXO#EDZ?Ki z2kUOb&1!LkG={H?7f}O}F3}#XRo>EbFO>gT#^*}Iuaf&cUY@2{2|8b=`PBR%TNE>t zu;W*}8CgPbEEDTEFa8CKnrqTfL zJ#K9>0Twblzx&W-a^GEWF;vH|l&whR=qrV2m4!15BL-(U4F&N|x7<)R9rF>iULKqp zU2N&y?!%4+Tk%ttliS^Oy-Si3gc-;fZpfnZOp)yKMpp96yGNjZX5SPJOwJUL z{a8Tu5r5CVuBDCsYx>=zE2O$;kp&$IpYhJq7NpcNl)j32vCBdQeLzUoZ>vQOLYnul zCBWqA7!AB7xyNQTMpE-ek8xccaF!PBEyjmW>rhcVK+NLu0U6JV6&n-YV^02JNLn6l zI&dM^1zFOOW$oe?8yFlk*J%HWEMEi{$e*rIdFLEYk0MiQ@-G-ExBg8mjBfS(8m6X~<3%Y!^sCWXeDZU1jDU@+j@CV6JwX4-%&fDT9Wj6zSO7Cf|6s=6*3Q!Wm7ClsNmE~51pgDiXNdWx z9|3fYe6Sw;`PcHn~RqrSr@9aOohpuK%_K$&0SoPc*xmo_1~0Yhaj*6L+I|ne))=hJ8d%7 z+ezG_Aa80`crA1N)b2z!Pj9XLfzJqbJ}WF`=?(^hx_M;c5oKP~p>}HI2c!BjWKph z+D90rl=nu=n~zyxVo=b5Ar*#}d$JOuZ`-QSwNRePHb3eA2;S+td|TELy%4%owt7B2{Hg0S;+g&NY%~4ka{bEg&gE(HrVf}4s|>!2 zrf%`hgR#+~?J{8G>WAHr2xMn&O}J#tr`4g|i7U5#7HPWua$L#Y&7QsTdF%ku_2+Y( zu&Ij+i$$KaTAF}oCvp4)kG2NHm#d*4ZYVXY=_|Q6cJs}XwkT;JXLN!JWyy+e0n67m zjcI9?j*C;;vEv7Z4LBtu7o27knJmHfa~iF!DV`tJ8Mqpxo1T7L3%fOfOs`gs9v&Vp zAKtmtanTFPW>~NtSUzvNaA4!G)Qy~O1~`GVX$j%-a2^)~ukS%5Jl|>G$~(Tyh0T5p z?&f+~xGJ07IPqQFe-wXlyLj@DZkk=TLReUv+P`EndpexzvckH2aBqW!pr0GZUA?bf zrYfu}eF=g`ewKo#pA;s0p^mtdDjcoV)7& zY?Hl`x-t^rJ2hn9#&O+txq8n<#Q8RV-McoQt8nrK4z6i@r>jHz!u9cjiA-+i>bfrt z!;KxwOt<2;f_+pv328Kkhs{=qHiiA6t&k84H}-jJ+QOa1`2;k^VK|S6$km}vt(7J9 zI@ho{v9wY^C_)hVLvB*8zlPGoWR(wCc z2ewi@wQKKES4t9&K`zjs6R^t*6Nu##2mvty;WZWx;;i9tE1|36z&XUWUDi$mx)Nyq zcxV-{A}=cjiINL9iKJCv$H|>gE3qLNL6N3B85b-(Oc5hv4=R8jhLRhqGBIxER8J<9 zEuo!&`dz#>&A#Gu`(8gr2kFO-(@6PmVCuk$dK4-EVS)TlVMd)saNK88pcpf73e>mg zL5x1K{yu!-O~@1-?B%F5`(jFz==29GLX~TY>kIzGL&{`VuEFo=_dfoyR2godPoO3u z%iJ7-#b`Aiq6HpXs!`#jH&Ws>Fe1OdcHKY?4vS-#v&-fDnKPaOH6pYTg~r*n)0bnf z5t-3xJR$8S)(Kzqs@h3!sKjYwEAwoPxbbxhWBx7|QJRR7linb}RG<9SDR(2aAS^Cp z0YIK^q~r#0;kL13&DvgKrx}dFy(cr~D#ktW?Y2Kt{jPhO09Qjom?pY&gxPI83*f^o zOZ6;Dw(dNrPMEtsiMqLzpL*-Uz2p7fv zSC}sY{h~t42yeN zpzJqH@>TI^VYg49nLCZ<6<-$w*MTD5MUX*{Fn`!HXJ)Jh&nr5jRpi}(zihv1e~15x zuInxnI!T%_%5s65=dTcdn&7(|L}B2`JHGg@_%3wGwf-GnISC&Y~2lz zozlD7$(Nlff|(+AQN@Q$yV$GorsNuwdqOHSewc$KTW~OXAD*3OHvUx$g+9YbN#7I~ zQ@-NX>YIG|+t?kJU#;)0*Grb_BoHEFfbcl=o1nda5EysVsaY? z1)u;JxB{SHsJL}%UBmuU_m$+}GIz7#?hOK5r+}XvpZ>w|X2ry*X{IU$)PA3m{3+Z| zI@bO|&10}}mFcnfKW03JyAS`@jA=S9!)q#6e#89jR;0k%W0+L%N&gK%u690R?NRV2 z6p!vz^C2Er!`~o2tUM;xjYUL8AO3BH^izY*PG7UT$CudQzomeDbYG6Wp6&k; z9+}|D308BLb@i6|+M~>CdH;pt{vZCLEGPab*kAe2aN7<}!VS5;LzJWcCo4sOI8*{> z`!2vwtbQZb?f60$PYd_oF#~jkx&K8T>c*8fe9O<0gLnGXyM9jYTcH0RW^tjIMkBy; z3)(1OQ!L&}Gz$N_jc@-zjC9wz7=w9;wmL!i!mZ}zm~+FiSZ7X|2`Jt_D6D*?(CueM z=6U>GsOh-kXZQauR1eDkqyV7%zZC`;J8rIxOYoO}SFXFI2j$|fu*k$i1=v60yaE&{ zz=T!nKN*ksqV^OaXYl7cBAjy*8IY$6(-ZAg`ny(=DI+Juv zJfaKld^SMw6;%9Hs7oqAeSNMluNH1IdjIHLw_{rZH!#xKKP>Qt{hF=4Vw`~a_tWnG zNKZ5W!>%wlBj<0)yNWPsHHc6w1Sokm=`UoU4)1cdtfZai{10Iy)|OskCrUAe@q4=L*KpsDGXkHLsOs zX$vS|8QotkSAkj<;kIV}I+#q3e$AQh8&^^A&97zd-!#EZnh(o3>Po z)Nd=zW?IUM63K%JBPq(QX7RcA`WIi*K2@Wf_uMr1(HtpDtNO08hsQG=_OdcM$v?We z-iPux=t!2i8-43p+syP?XAf87bwbr5Ixh?+O(W-OQfRxuHI>MG_to~eSA=|VFlMG^ zBQ?5FDczjKBKBZOS|WcAYA{(Zn>D3%wAwq<6g_vUy~m$+XdA zQLFe#Lx?iW(s7qnhPkit-$Gt!YV0(kfuZGkI9UxJZ9!RzE3P7+TTX>H8cit|D`RK6 zx^6vr%G_j;Vj$?k)#BfmzmQv=`^EVq1QkBGegznWq)r%(S`*#&RxxaZbS#+}=~;HE z0NKyA*kgHOH!kr!LipPBL6TwQx@f7ma16VsoAO=OAxlpgt4;_jZ)v^{cVxe z?D8!5jzg2PC%W~P%X;nx&rsNi!>WhAdG&{U;0!tvjo+IE;fvRGHm z3%Fww^Cv0!v~_vr`OiyrgWow#Harjzgwp?cVWa=!!lr4dTld$6Eutjb^8Fz!Kh7Jf zND#iM2-6a`W>kFDQo^#B=X*FF{}ku_HwH8ZTdC_Q!kk^s$46h&TVIZy(A_ad6Q1_( zJeHOvdb8J^9bM*lJX>&IE^v7~>Tn{cXOAzsuB}{fe)P4$C!F1+zdYtkTjpPsCFE<@ zhZl5SY`>D@oGZo|Bv`f}na|sq1RrqxpT+_081cC;z9}e2VoE3)Ibt{VPEF;dx+J{XwbfamSu~9r8gHb6;?= zZ(5K0vNx~mPOqqxa^eyWPasTg=bfryk`vNqa<8nn8B21?jJH!hPfp(9Qs;KAXI?T< z9TTVBejLl4)TVQn3}IoJilEMGE>CRT=_!t&*2?Qywy8yxMq7Fo?1hCZn_^ksmEN6N z41^;*uJ&ZP*bnpkyfpXNSN9`!0XX(SA!HKOArpupS|f)lQ-Pb=WVXKt<>= z98Ht&D9ZaVU6FEE9wae&M~@t%6NPHpBoH?S1oJ3?jI$f1Lkuw`2C1$8+Z*$kV#M^#Y-my zFg1zOTv(^_Lihw>TFm4}>D|WGQ%lN_@BOLFq1^E$#r?+xFkuNNJ13ZzIevg(o6Cpi zY)3aQO6?e_o%<3m?BPbCO4sk}D40_-)=ILyOE5*%$TZS8_aoN0j=IGT<=)E+k@bUF z2JGwJ{tB*4ijnY`36=0fxYp^+q8UoAVPu(XLr6VKS>;eLN8VEICvc6-H5*B#lwm+jxPX{gfYGE{&UgeiWqqG($%L_L#H{6hUxIph z0wV_f6J7lBYrrpnfZG58AB->xDKhZ>o{Qg?hJgM%(91tIq?+~OY(Ch(@f~>ek@lO90R}by*-$Rxwa(AM`z?u z2-;?)GFA=56oBeq0z@QElHBoY;ZJO@@{2J!ZAWd9q(5!_T|dPmxy9@M-l3da1$wuf z+VyMYZzsyh;>yW?FZ^=yOHOW$wrBD;F@<&^lEY*?W6NxB$zH1zqxbhJeJ!aLn2&>B z+EB7y7CS*Odh@W>OKlLC_V%N}@wY2}7q zc(1u#jh|i3za0VO;2bh@n&@)Gf+*CCp(7~J)U$d$00tKKOknm+SaT!*EoX%OTg%O$ z9`SlOqS5|ZLDnc82##R`bmI)_j#vm}<`Z4_?Tv6aF^?l%#+Rfd7s7&p!PF z@Sk!`s=pc=`A6l%jGM>&Z-CKD%K#Jd6|cBM#(2|z;)}&p4i7Bg#DXagz@HhK_Eq=>>c=~b*8>QnjHhw-sOsdxO!kcpYsLJYc9%)VD ze<%MRv6TNi7HG$rJ(Jhs|F3+Z{GUWp?3?_j6AFin|8Vk3q|$#A>G#QZ9Z;4&uhFdY zcg+E2r&1~L>$oj0$tf=R{EPeF`lw{i+wG+Ebt$gi)UHP3uZgA5*fXOPD{Y(b#`RhE z(0=A!N*6D4nNIFcHs|*AC>&DDvuTATgNv~Jh%0`zjn!VindDuA<1DTG>(S-}`dcu?CG+0=4DAyC6O3$qvXJt{oxY=X z-fR5-K&E`rmiNi(?}guH)1rv7de<*oe{m32TB{8K-2%ff^E%N1kbhMtV3Y_oF8sv& zM`Hf&OIVJ`Rn3&b*MZRtoJ{ds`!i3>7+r3qe_)=$v4!JV*-`xV^W;FpOr>1v?BF@G z_t>tdzXO zo(EaZ>D(doXdM|+*?&za-6Vy{;&ge&5&0a_la9R|YfDL_V4K9W9QfeA;ClRsY_z+$dVj;(p)W0hv~X9wH)pU>YPMh#JX^q0XX>2K}H;&|ALp>9SVt z3lF5Mt!8|nnh5Xmp5-#(SLH?qASWYTT@`s>;7Ki8L?J?x*q^IL&dXnp$&Q##5$xYm zm^5p96*L592n7}RflVv4_1rc>QS~!??Im5oi`>A#Y$;PfoYP1o>O_t1y-v_|GJClR z?ud_Z%XYjY*sHrryJ%&9+#fk;%99bQ2P9 z)TuGchlyWAZGhm57y(!zun%tM310WQ1jU{8mqLqn^emRt8EIR_*vpgeP>0UyE0-?Ci6m65s zy>I=INn_mU{jpTpShdN=nM(2>L6^esujW%>kg_M;*OvQD+;?9Xk5bi=w^LupZd&^N z@z>+U+~C|l3bCk6I_jT%!%sM^Q-9;>ZSRqOK9W$!CZa6RYSsqlxtP}WBb_E2blFZ6 zO>N~H@!@u5vSabQUE_5dzH>O5R4Y>E1Km^byaBW7*2_fGgH7Y4eF`_@l_%<>z-$(r zT@#YN!^MbAWr_v!)ac9k^X9&tI}1PVc-0fV#-~q0G>ZxAk3-LGcA7*jCsWSS%Gv&y zvL}5s`4?Bs%b%XYyZau|#U|TUb|^G>UVeVo{reS(%^XS6;u|2KTD<@BV$bmNV*gds za*-L?{{-R)@FliP-@RKjn6*cza?uNx^t-!8F>@+p9F?TpMs1r%Kn+mv&_KVmv>`z6# zm&;EPJWHvK>le2<)3NPu`>a#BCFNh3hkB1=*rzwM4rdTk+*z;=pggc~sw!|5S{Quc z%#|n;ijQPi`s~uykF5r>s=mgLzm`{aN&QipkfltOXN z8mQx7)Y=Sv3pe7h*K5H;RlAIrJkeRzJYvxT`10x-q^0`pBbS@UkJa{Wu9T(xJoCJ= z9Xmu3Nr$wl{c6^$O&wQGc~+R%PlhH7oDuSl2v-XEH;y~dZs?T{O`4#^1vKvT1yAfx zWS$hoiqQUKcTKYS6V9o7rq6|k+@_ne%j}v50}92pE>|%aXU;K#}o1OFvOONGyU*lX5;=r zcklw;i93R9NKnhoQ^p<#Y|JSmxo6}B3o4J%5Oj=n&!ocTNo2nHox$>zUt1eyqdbTu zw931dK;_wbgz9frBll`;2^V$BR>pOW_avmVVqe=65vLO#n)^>G(dxq&ZAU=A?_JIM zGHW1cM21HKqfc~nnl{=rsA%>=fO^4uy!+I#*BRXWnJIbJM9dTCOiglowtv>7w4j$m zzFu=<6!}de1JkV64kOI77mg+{H6*o&@M-;8c<81NaCgu5D`2jT4WBh1JFo~Ci+fgT zbY6`kHSP>yji2t;tUKH>`oKX0Lza2q_Yl$0z|e9CoHS0K!(VsnpUmGq^GDRzf2jX} z-LdJ@M!Hddnf~D(yY%D%rRijXfcj5wA51ptKLc57GEiRzhQRp1Od@iYVm%XwfKCwv z9{EQ_i5hw1g9tVTOGAWlMq5}s0eWuR&Pa{DG%$r?QqhfluP@4Ou0t|G(}vTI3P)LB z6lI^B8|QLOg!5?O4NbrHZ^G&g5l*v}HxU7R;iWyB!H_07#kWr5Q3Pk@0hpX=P;8B; z5fu0ZQKcK3e7fP?T}l?GPK;Z7YMiBj`QI2E0rAB44xXd2V-qSW+w`m+-v{H>Q}sT; z=+T=92*KZtmH>>l0gR&kZFC)FA}Lc?#$bz+v7e}!7ttGEv!~A&4yVoq{MxO`g_Ehj z#z`gOFH{`>1G}cpKKVl4)SYG^f?&aRD7f(Kx1o;fB!ow|Z^8|Qyi5K548kh*JzA$W z2s&#TI(Q>$_#Z)Z$?9l820X2{pEZxCH;t(Gc3KO9F#%G>Iv4`8UjBf|nuhwjwi-aY z1)%+nbiBq&1CcKb;4r*$gP-;2@l801;P2j$0p3`dweO#NT_|M zu43PTOGDW}QOgKqh$x?}lM+#X=}NOy3O5u8`VB53z`z@$`e>5hrBP6_I(-1Ec>Oh2 ze1^C-rIC2OSBOz4f-!Sz-4eG3jw z@@8VS3H--|5Yt=K4s$XkDoL*mF0^T{<8R?tr|Ih17 zTkQ9Vwt#b!8}pA>X1~;aD*t@EbgU|Ai7ANQN^piNPVQyVqi>Fj=Pv7XBnZn$zQX z@0jHyx5AxXnLwv!f5153o22aJR2tHu>U3<_1Lg&Nuf!;15+6x-jTg$niUA$W1lr7J zwH~HIOY0uv^YDKmN7eqgS+hMV)qh|4FMni!_(534b#yI z3z?<${yt{4?H1wbdTU4-o`<4u2>&_Zgxlr$B7d8=Kchi_hTHS;aH@|6$Nljt)=Nkr3v&zM_yW?7!QYyQ1^l zP_5Jzd%fcTogyQsT~qBXAV)Ssb85gZ%90o4Do(UvzBW5LYTd`WZZf@1zPf!i%f=vz z3@~DS*Qt@LIzQ;JD6k?ENpn`upzw$mmNTa-4ymue6WqRyV+SuJ#(&l04UqaU!g4$g z`AAPO^%9YsELK+ZO(NhNqz635^fTMBz=+)L?Z+Yk`dL2u}v&)ijwh99Jw^XXz-q zLYWwg=uYaP>MN+#d6ltqY)U=}>(73Ej+oM$Tp$&#b51MYm+S0jAI4^v^&8w4OgL!D zWn8aLKkw==5DAM1Y|-g|D>DeyNHCC!AEy-JQki}jhKkw>$RqqxW^C$HY4J@;LyyxsrzYV?PW-}%>Xi`gqW2{F6*|krVR7%=Q3J0FS zE%L49qBPy1nuc9Hd&E`2##(YNu2tA8>l0Hbg#xI`=2eWH`ujwOFuN*HTZN#UG!Hu9 ztAMBj+=$HP(i4Y?hjv%Y41ya(WqgyNO>e;cQrROR3u`Ohnj0l58$*_>*jApGF}8o( z&GibqWQo+V$M#vrjR85@Ym5)=>sA&tL{q9hKGIbayHh}%fENxh>d(``^?k4}@ZlyP zUw7zK0DA&bHeOiRiBnIR%AwHu{60mqj}ppS&B8v|Ajxc!{crtMP?iv!jhju|%oTd*>OHu7(@b%h~wDY}sNr?&!Mj0dhdV5F+MwbpZ0+H3e z?HrGzL4G<6yu54flj^TZ;DQ0txLJPtqkrP#Vmlngv{ehljm zg+X{bZ&2$Q>*FT|$;O8%z&VvvVYtG&XBqx+U^`+FmrTH$r<$T(VyWJP5mq+3RPiRsXp(c?WhA z*57vj-RO@ zGKj~Iyzqq;6w;6#A&M%-itt&}2VcDr-Nn&XclHE^WRck^Nn?Hqz14il%--7*^=vqN z^$J1=h!KQlisDIWOqWQgug&@F2$-s772~b9`?sv)NYhwX?E$U)6Zrlfd{f`2CP^{D z62$_n1-1Ou>u}D`s$m+*wOpc%XdFm-HINs>q~$)jcY)ek&P>U%qu&r%D6USEWUzGd z(>32RmoSk`jdoCz8oY5`4D&hso=m*;y^vCBMg$)72iWwS1n~XAv4r6%*lB=nGwf^NDDh=@)_bdm-*m7Z6=N{)}l&AL;EK3z3g-4t{Cz_d<<;kC6CU=bkyj#`J{NmaB+-dX7%OK>x_?F zp#ihiMFu%V2}QV7#Xa~#gx;xQlyTf&oQ3iix2MFJFT5y{F(FDmoW5~KlL|e(y)OYx zbiCAV6hD$7WKwmP+;8DKj91Lcq|@}vTs^KHcr+{%-Nlu?*=8;tDb86wK84qKfX1#z zMO-uP=vjo87ijnlhE2c7JX?I_(qf=!Qlqw9LA5Zxu~-&(Jv8pITslKRjS9ro@H$qU`r9e#W!$srEiZ#q>KvCDX>ejU83PX$)-H9+=_T zdWb|L@_lEgQ7m_*y>VhI!{8*TSk*|hb}Tc6^71zqfvw40nIdY^xRR2OVv1Fw2nCy} zVq4=^f#AfXD{b`_RY_r@h_;pb)U#IyN?fj*3H-RRMDg!(LvSj;P`79h^URN<>3_*h zWF%mk2;D@tmmQ%cI)z?3matjdfH1?;MW zSaB5gGapid%!E;;T=UKxO4L&MP0LE5U`Y~+oG7cx-fH$d0ljE<)yl74 z>`|gJ7voV&#(ET2QwM=268Qv0w7KC0z2De-SrIW{p#Iz%SLzqCGXF#bfNS z%m0HVf}KOZLl!pc)tlHG;U>BYxaGJw;#nhXEIZ4Fac=X}RA4acT0!B@8;>?$K5Dp_ zu0gCw@jA{WWvqOYi2|qeVQ2IPe^@VvMgM++b6wlwE$+As1^GVv%bDAkcLsSNgc|w8 z3cea%`&f;~$IZ^prJVUq7-Pxcv|}B9K75}sV14QH*yzmBLlF|#Kn7|D(>U^DU|VHv zK!tbvGg!g9!U7<--+oyB<_as)y#Hjda$omuU=|Pj+)Sez!lppzQH<-U0YyF9pQzkX zC82yfY6j#DP`|8RGqN-EcPrbknxmh9+C9K6lxc6O9Y#3u@X1rk)_m9|2HS1Zf$-TQ zV^Q?|XOlZ}b2?xNB}VGi!?%0#&Mr`zh!}+<3*vBnH#`uRc+8(y1|8N33O|8$v*8if z5?H%(!>WR82sVVj9R(Ak-~FCwQz2_k)H&!j0_phH$Vfg~sWPxC!H}{VTEsx2Gr&vJ zmwYo)u%(EKj!K$Tygy#f=Z&MOM3R04#KWL-zZk+gUiZ>xFjCGE-u|7KXrgLb$!}k! zWBX&Hn|7T~fF{kk^=phUJz61jDsINsRhA4RaYJdf3}NRBOjEJ^0J^%8}uozhw#Oo zRy~pwROw$gaU2+gq!jz)N=z8AbJ#FX9-n@0^hGa0KV9Nv@;*xdLc;b=#=X%Qhir4vZm$9h<1nv z=AZYrtw83KF7)^ibxNucA$qgv1UG{I13q|c1YIP;?gSYmv7na{X$L3KmrLQG!t1#jF< zO`Acg{AHQ3x|qe@NE2Vy*dh6ytOCyX=RM^%PWKlsJ$UrkOoKfN>P@Cp1=q+Y(N08W z_o>esgL_k(B21OaLdXHjlF)r&2ulSx^DX!X6*SV_-?T(~#9Uwqd$h~yB7)fNPL`)2 z#`@Z}pR*&H18d`OJn!;%Kd+qetc09SF6(DSFHog>*w{Sw?00P@oU}2_7fE2&Xc~(E zK^6G`9Vs3m;RK4kt2_+_OU_l?G1T|QrX*|MQ4}mZYkP5UInmS-$^(9wmcMt62HmJM$eprE#wuwSdx`((PzkH5l4dpVye!Fyp4`-9v0k&e~I?ZJAO)y9F8 z;v=;}ozE#L!Pi35Q)ljFdXlV`*_K!?5edLP2608zXka!b ze+u-T+Ny1!KIMZ7avQ9Uo@0jBzD+|$1*M^ptCqaac1;&#EYEBb=6f@ST~vhivb}xw zQA>~*)C^f!;k~Du>*KC)_Cp))atp)rsjZf>6l^*Bw}RxklXFTiE-E2SC3ckwYZ${J zW00e=_73`&FL2}XYrX5h?1IZ@Z9l>+UufhOql7V!KH{D+(z;xRCO~A&Q4CHyx;&uK zq;an+>Ou3#kjb2p@=s(Mh-Sgxo{mQ)ZIaTFyR{R5n}~>!Z?YiaERYLHSgY|!lMqeZwOtNMO4I8OjJ z$+_Jg{JX#q6kWwuZg-RsV5ka->+4ZWuQyW+Y|%o5b=GLekeiBF^)i z$QkAmCKJkJmo7$0vTxs3RY23x`vHuCqVsMBQD=)VkynD58(g>Q%vkXF#Hbs_7m1Ej z`;)*|k*)&Dgd##<`1DG2CBgUzE3FH0{N(wbg8K~N$grrz2T}~t zP(*a!izb6KO2Yy&74`SBD)lah?TZh%dgnD2^W>=G*0$%%if$6jAq&|(p+a4xtq+y2 zJZxl|j6Ev-n2)+Vp*XkMXXQANtqb#R;3)AMc}w=WK)-%SQX4ysx7YGE>S`_B zcmF7E+u-t|fFRZ4X@ms>H+xk_~I=4r2T5^?b>fKwjq$k88#{d}KYUM?K3yezJNhd81s@0-Yl9g%`4KeMUud zNa06M861O*qIRjSsdl@wQtaXjZ;;Ll^ba(8_>tL$>95WNY{159<6U|J^IgQ0mi$!6 zikYfuLTtRii>-stAfu^|fTgeZLk6j}hstqYLI_b6AyPh#c`gnPuRO7K- zq^?$+q+Y|+cRgr&b^blBrgCbj(Wa*)nW*ZHfmWn!5m$?|GDS$62NI4NHRMu!rDWZu ztcu|@;MtVmAv6(6ksS$A7WOrBW)Xf zJ$XADV++GS?w)Gu@|eP?9;-!9@Z{&woTML)SfvJuYqrg5Q}Pwe9adGb~6KHC40MDpV2X6V9*IvI$btcUBM8Ov!Rna+K4 zakbxiH6tB?!|q`x?b1u!YYAV^jg4Vd-*+Opgp2vIe%=15^`+O@wtYPb1G|mq-b!c5 z-E}S9Vys=6pzURuD#CEkyJ0hJ5fnZz566>@b+6&3{mE$hV!vDWhSlTlp?fQPg3K-T zQG5KtX_Cuj^`iYa&E?X{%E@T2cP)FO;taU2C5U8Gz7E2_%$<47iJtp9g5(E>O*fO9 z?&qy|L$j^#)BUI8iIrW!Q_YnlCJbfGWQdEKxs0ZyYGF3% zVM`b}NjBHX@;vHqFB-s)GX_D2${r6brMgV0CfRP&ZFjtWF+Ln%{_;w z%_*5as14&mHijW+JT6}yON1$aPVy!^bD{qX>Tdnh0U!@SRO4bY?x4Nx<(d@L;rG5=wtbD1qpvKo-gpdZ#l4My{CbG0^xKCOU8?HmFQn#Bd zz*Aaj6mmRVbziu!@Og@DGUp8Fx!k9Pi}K}=5%iO&5rcjqDQTFc{)YD`@GBR?V4yvZjtt=h#MBDkBI~6kHDwr(6OOHP0jZUU`aD zfst@|Pb!v_o#d}9wry0h-+Go^HXM`NWo2Wd%f`nZ$S9dExM2Jy#+jZEM~l-SiOIHA zTi7+V6TIOZ1nazpRQk@@9R;p;M~$*!b#qI`Q#VLoIaBP|YgmACJ`Z^4*olr%X)J>! zPeGL#KbM}-Vn>jTS`m6iJfSI&w6IT^jsU;DkQ^^Qb#tuck+s{G?Jt!%I{;oujR}dwoX%LXEFXJl9&=>IO(=t zRNT`JCmX1**jt*R!s{J=_6b86^Q!Ot?Sy>v#6jI5g%%Q z>T`#4{>9UEgL6B@N9ht^cQDlt_*EH<($c(`s-OxVf{+!-2Ud&)vj&Esavqq+WVK37 zN3hL_vzfnURkTNBL%yj=dN4Lt`&grOu)-LZD3Zb? zbsE$xv}63OKRW1B>Nkz`NcqiM}*Fy$K4M4Vm{`r zO{B=kXgq=e6DTm%+(DDI)aPxhrKW6R*L-iM#LRCXuT5X98ezExmW!HhC#OKzk%=>G zbksC87kk$4iA5z)eM{s!rp(PC(*$d-vtpGJXR7dRG18lORylVhWhogCTMu#yAESRs zNO2#u)+`Rlhq%0dhp%gXACF54I8irX<5oLN84fDu615G!f^=Y_1YI3(rK|12U7#WB zlrN}m3VGNM0d)cth&NcgOG9s}hO`{}?cNvDi%yuXZF9uW)SquTH6WqO2HpeL;vy}Q zOkQzdXR13N?6Xsph=AZHZ7p)+dmVL04E7p%nb;DRrfoYnfQWs$l$E4uC%1C98a*`Z zMko>?e6HosK2ij^6&)I*dtq<_`Cd=!n3^w`3>!%+!>!KAd)5tde-34NxNGu)ZCgKpCguSEloIjb-9ZU7;h8Ramg1xu*q{-7}wT;WFDrA-;8@}(EneBVm zH$3^|nI=abvnWS-5yJ%^O6+A6u9|@e#~jo1!3w7!f4}v-2?Q8o@RUJjaSg@RAG?{w z0rz4sD!A`s0^(IG=HHXVsxIa_)XP`bNfMaJcvCKX=$9^J!;V|D&EHx+6+)7@F8p?X z&ZwX10v-~QfG4Ip-+Z}Y+Vu$tfgp}O<^C}m@{24n2ibLw4+V5Xr{D&@IH+>JLAXm} zPT$bpZe(R>Pe+>ks?!^@e$!Y@Ds-!~SsZ1@_i%0%#cj!GUl%{?t`1KLe*xQVnd6sJ z3LSl{@cf{G4YRtuzVZgXT4in)>Ts+NjHb@WRD~v6Z8D8$J)pN+4E@=6*oUuHVSMy} zvRu3bL06sJ)$qC^i)QvxMdTj#_@rWr?p{D@%aNDD7 z(F73@B?E>Rp&?M_+Kc7%i19-ZzH+(YD0k!{P#zL9NQR>Y)tcF9hC}YYynJrYD!4>> zKYNHkhcQWXBr%4YBRMf49rA>DfqGP}owuZleHUeQ^-W@KST*9Zk%!nRzb3?cUTk&d z_eo`L>dQkJIOpBK#Qj+QUV73u2tnx9ofVhM3<5q!`3s98it(4bU<3mXdI3_6Q5DuU z`0|xDaxgj}tr4LRv4-@@BW&XbKMWwA(3Lo&Fcp?L2o~LJa7=1j(>7L`7c??znY~tp z9v6hA(6ZKCnt*lfvPCl<-#WWH#kJ>VLU7UbiR~H4`L-|!PcaXmvb>Rtk5#$B3GS2vBW(uR`9W3JZk23X^cbBSRmhnmgz2d@H1uDI&5TN|h zxySjUH}uI6`C29oz?kVo?aCx(-{Wtp$D_6N+YoQT-laN$m=9eu=LNj9N2^tNb?Tp( z7zCG&^e2qt3Pm@D>mo0J58;mb;a>zjad5B;KFUq{9x@aL+^p4zXP26u zNDf5aFP6PLlFV)U=lB>PcQnL;NZK8&$t@hM$plONFb(3iyJ&genpl2#QT)M7C7{}x zEDBaJ>sxURf=&yATIu(I$lw+7^ZU2~apH#9X6$%cWCQ*Kcw0jTDJ!pArQVymeVU{k zc&|3v0uF-S>1RtsIM`XDgLGYpAq(eWto8V6QR&Tjmw12VY!S<ikgI2G8zwaO0ANzi;>$qfmGa>> zLR}YvY-*iL%pfsBE}?+wg8-=vQOLmHFbFpCz1VXv7F8=p^f!$WHpqab3uU+R`|||y zJuhRl{BEkzQCh}xtfJ(>>f+7TnXjoQ0PMB7u$bV!9~=Y1ySmwl{FefRM-0<;F>v}i zg42*+kCe1r#1*C}s>i+JsZ;jO)9_ook@ZXmbx{0hkB?f;o}OTWgtcI>A8Gq(fG$I{ zf>G%d++Oh6KDWr!Fj8~XF2SMGEyEEHi{3sXK!FfjRSq+!;&OF8mZnJrKPHaxhLj@* zEck$KdY$R!8<%G~N-YwP3ee;4bHBxa;dad#zU;&YeWR9LE= z)#f{dh5&~+SI5o01P?cSWiC;0@Q0sPhxNwpF!}(lE)sYqhja-|tFKrb)KgCX`(Bd^ zyIvVq&gdzeOn`_FA zWgjFu;h|dWI|0ro64DNjmou}I9IHTOZqSOWD^}e(jq{5_(&@}KD@sGWxIx6 z=5o>H>Kr#Zbo1I`vDEAoea4^Ql zI=eo4tBeDDMk|Bdw|$9ieRF(FI$62$xyST1%#rbhiM2Hhn9HZicEVau1K0#dzo zFT=+QE7RH)`NEOBA!QfhTNhgH^WFC~(3ykn%?Fok0#c> z3A$LpSEVoqk8dELDw3sHUoB+<5RwMvV$mv!T4M_bUcZZ16;R&?)C8a6lOsdGt)EW^^fyYo3m zZ?+s717Q=rdK;Fy^2(}Q{Ak|H0wL$CIQ(-|1CMSEaQZ{l-^ml$+^`-I0ccVW!xMbt z5qI3DyE9GDAAr9OB6LXB@%M6rZ)y(hW-y$qr9@7a2FI=bf&N74dSbBh zuy>}1I{7Pm*RN4N8=-)=*f-|LP-m9h>DFz90Nco+WFV;l>chKh04Xax3$+UjN!DK@ zit*ern`^+HI0t@N%W^AanUppXU{|+)2xKXjA6p;lbuRR{YrA*DxsL%T)1gqE2iR8t zUt>4i_PXgs+m-Mzl3M(rj7S_Tz=$XxdGs*Gsb|XA@OaiyMXdsrW0wzwDPa+Y2*Tp& zwk$zIsM^zE$s7K4%q8-ZW6n3+|& zJ-jqJ$v(P~4@w-QIkYSylFvuI{b14P4o<;aoE3@^&3?Xoytj7(*BsYlUfHRm8ZMeM zvnC>sZ+)NWtD$J6O`q$}ok&yJ&tTdX+R9a5)F_p;(`*{2mgzgum5EZZrD z-;)*WJ^3vvB7cw>Jgn00CxTNlZfACw)46fND$@57@AXI%OV6CWGomYa#W^#1Tt^`I z3rb9HXPP2^L!k2cn06j~p4Od2eI-4}RE*6F(d74Skfh|#v$772KQ}zM`Z5W7QtFWa z*){Xqj zE^Hwz+>hkbls_Mnvyc~R2M$2-raHUXf9N-lOy8M@zrfjF>1(MAig}XHYINV+BwICB zq&bp1NKMFIZ|1H_K-xLjP_i=K+RKw<*&^Y%VHqTZQk4C3*5mTl3k3{ z_V+jDd}_JETD(IB0gB25vD6wjjaT=nhDdlaezX5R+dF6m?++S`_bbwJ>KesMpBxM< zavJ$k8duvW@s_B)hP$@<3O^UTGP>X{M8)%MW8A%dEszGTq+cbJ*IXwb#Q+|w6Og7~kK*T>CG!^zo8`OhN z+`e9k{v`N0OQQx`N*8^g^fiv^hn6K4!!5F3DjvNZ`ist+b{aI+?fh~Hn%)9^uhgc6 zGZ31Ejn1k6|JZ{LuS@^yAO86aq3I8~;VS$#SF*pB^c)X(gU}Bm93OSbtjwjL=)5e|~Ax dii_}Xt*k%IWT?lqUO0FtUlSNg%)>@h-9LeK0ZRY? literal 0 HcmV?d00001 diff --git a/20220330_Vote/Vote.Services/ApiController/ProjectsService.cs b/20220330_Vote/Vote.Services/ApiController/ProjectsService.cs index c037927..66f75dd 100644 --- a/20220330_Vote/Vote.Services/ApiController/ProjectsService.cs +++ b/20220330_Vote/Vote.Services/ApiController/ProjectsService.cs @@ -1,9 +1,13 @@ -using Furion.DatabaseAccessor; +using Ewide.Core.Util; +using Furion.DatabaseAccessor; using Furion.DynamicApiController; +using Furion.FriendlyException; using Mapster; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -15,12 +19,17 @@ namespace Vote.Services.ApiController /// 项目 /// [ApiDescriptionSettings("Vote", Order = 0)] + [Route("/gb/yjb/api/projects")] public class ProjectsService : IDynamicApiController { private readonly IRepository rep_Projects; - public ProjectsService(IRepository _rep_Projects) + private readonly IRepository rep_Experts; + private readonly IRepository rep_VoteRecords; + public ProjectsService(IRepository _rep_Projects, IRepository _rep_Experts, IRepository _rep_VoteRecords) { rep_Projects = _rep_Projects; + rep_Experts = _rep_Experts; + rep_VoteRecords = _rep_VoteRecords; } /// /// 列表 @@ -28,14 +37,153 @@ namespace Vote.Services.ApiController /// [HttpPost] [Microsoft.AspNetCore.Authorization.AllowAnonymous] - public async Task List() + public async Task List(ProjectsInput args) { var data = await rep_Projects.DetachedEntities.Where(p => !p.IsDeleted) - //.ProjectToType() + .Where(args.type != null, a => (int)a.type == args.type) + .ProjectToType() .OrderBy(a => a.serial_number) - .ToPagedListAsync(); - + .ToListAsync(); return data; } + + /// + /// 检验提交码 + /// + /// + [HttpPost] + [Microsoft.AspNetCore.Authorization.AllowAnonymous] + public async Task CheckSubmitCode(CheckSubmitCodeInput args) + { + var data = await rep_Experts.DetachedEntities.Where(p => !p.IsDeleted) + .Where(a => a.login_code == args.code) + .FirstOrDefaultAsync(); + return data != null; + } + + + /// + /// 提交 + /// + /// + [HttpPost] + [UnitOfWork] + [Microsoft.AspNetCore.Authorization.AllowAnonymous] + public async Task SubmitSubmitVote(SubmitInput args) + { + var data = await rep_Experts.DetachedEntities.Where(p => !p.IsDeleted) + .Where(a => a.login_code == args.code) + .FirstOrDefaultAsync(); + _ = (data == null) ? throw Oops.Oh("提交码错误") : 1; + //var list = args.projects.Adapt>(); + //删除这个专家上次提交的结果 + //或者提示不能再次提交 + _ = (await rep_VoteRecords.DetachedEntities.Where(a => !a.IsDeleted && a.expert_login_code == args.code).CountAsync() > 0) ? throw Oops.Oh("已提交,无需再次提交") : 1; + var now = DateTime.Now; + args.projects.ForEach(async a => + { + var model = new Entities.VoteRecords + { + expert_login_code = args.code, + project_id = a.id, + is_agree = a.vote, + vote_time = now + }; + await model.InsertOrUpdate(); + }); + return true; + } + private async Task> GetVoteData() + { + var query = from a in rep_Projects.DetachedEntities + join b in rep_VoteRecords.DetachedEntities + on a.Id equals b.project_id into grouping + from p in grouping.DefaultIfEmpty() + group new { a, p } by new { a.Id, a.name, a.serial_number, a.type } into pp + select new ProjectsList2Output + { + serial_number = pp.Key.serial_number, + id = pp.Key.Id, + name = pp.Key.name, + yes_count = pp.Where(a => a.p.is_agree).Count(), + no_count = pp.Where(a => !a.p.is_agree).Count(), + type = pp.Key.type + }; + return await query.OrderBy(a => a.serial_number).ToListAsync(); + } + /// + /// 列表 + /// + /// + [HttpPost] + public async Task List2() + { + + //var data = rep_Projects.DetachedEntities.Where(p => !p.IsDeleted) + // //.Where(args.type != null, a => (int)a.type == args.type) + // .Join(rep_VoteRecords.DetachedEntities, a => a.Id, a => a.project_id, (a, b) => + // new + // { + // //a.Id, + // //type = (int)a.type, + // //serial_number = a.serial_number, + // //name = a.name, + // //no_count = b.Where(bb => !bb.is_agree).Count(), + // //yes_count = b.Where(bb => bb.is_agree).Count(), + // }).ToList(); + ////.ProjectToType() + ////.OrderBy(a => a.serial_number) + ////.ToListAsync(); + var data = await GetVoteData(); + var data0 = data.Where(a => a.type == Entities.EnumProjectType.FangJian).ToList(); + var data1 = data.Where(a => a.type == Entities.EnumProjectType.ShiZheng).ToList(); + var data2 = data.Where(a => a.type == Entities.EnumProjectType.GuiDaoGongCheng).ToList(); + var data3 = data.Where(a => a.type == Entities.EnumProjectType.DianLiGongCheng).ToList(); + var data4 = data.Where(a => a.type == Entities.EnumProjectType.JiaoTongGongCheng).ToList(); + var data5 = data.Where(a => a.type == Entities.EnumProjectType.ShuiLiGongCheng).ToList(); + return new + { + data0, + data1, + data2, + data3, + data4, + data5 + }; + } + /// + /// + /// + /// + public async Task Download() + { + var data = await GetVoteData(); + var filepath = Tools.ExcelHelper.WriteTemplate(data, 4, "C"); + return new FileStreamResult(new FileStream(filepath, FileMode.Open), "application/octet-stream") { FileDownloadName = filepath }; + } + /// + /// + /// + /// + public async Task ExpertVote() + { + var list = await rep_Experts.DetachedEntities.GroupJoin(rep_VoteRecords.DetachedEntities, a => a.login_code, a => a.expert_login_code, (a, b) => new { a, b }) + .SelectMany(a => a.b.DefaultIfEmpty(), (a, b) => new { a.a.Id, a.a.login_code, is_vote = b != null }) + .Distinct().ToListAsync(); + return list; + //var query = from a in rep_Experts.DetachedEntities + // join b in rep_VoteRecords.DetachedEntities on a.login_code equals b.expert_login_code into temp + // from tt in temp.DefaultIfEmpty() + // select new + // { + // a.Id, + // a.login_code, + // is_vote = tt == null + // }; + //return await query.ToListAsync(); + + + } + } } diff --git a/20220330_Vote/Vote.Services/Dto/ProjectsInput.cs b/20220330_Vote/Vote.Services/Dto/ProjectsInput.cs index eaf48b9..f271277 100644 --- a/20220330_Vote/Vote.Services/Dto/ProjectsInput.cs +++ b/20220330_Vote/Vote.Services/Dto/ProjectsInput.cs @@ -1,6 +1,7 @@ using Ewide.Core.Util; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,9 +11,17 @@ namespace Vote.Services.Dto { public class ProjectsInput { + /// + /// 项目类型 + /// + public int? type { get; set; } } public class ProjectsOutput { + /// + /// + /// + public string id { get; set; } /// /// 项目序号 /// @@ -35,5 +44,71 @@ namespace Vote.Services.Dto return type.GetEnumDescription(); } } + /// + /// + /// + public bool vote { get; set; } = false; + } + public class CheckSubmitCodeInput + { + /// + /// 项目类型 + /// + [Required] + public string code { get; set; } + } + public class SubmitInput + { + /// + /// 项目类型 + /// + [Required] + public string code { get; set; } + [Required] + public List projects { get; set; } + } + + public class ProjectsList2Output + { + /// + /// + /// + public string id { get; set; } + /// + /// 项目序号 + /// + public int serial_number { get; set; } + /// + /// 工程名称 + /// + public string name { get; set; } + + public int no_count { get; set; } + public int yes_count { get; set; } + + /// + /// + /// + public bool is_agree + { + get + { + return yes_count >= 12; + } + } + /// + /// 项目类型 + /// + public EnumProjectType type { get; set; } + /// + /// 项目类型 + /// + public string type_title + { + get + { + return type.GetEnumDescription(); + } + } } } diff --git a/20220330_Vote/Vote.Services/Tools/ExcelHelper.cs b/20220330_Vote/Vote.Services/Tools/ExcelHelper.cs new file mode 100644 index 0000000..340b3e3 --- /dev/null +++ b/20220330_Vote/Vote.Services/Tools/ExcelHelper.cs @@ -0,0 +1,212 @@ +using Furion; +using Furion.FriendlyException; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Vote.Services.Dto; + +namespace Vote.Services.Tools +{ + /// + /// + /// + public static class ExcelHelper + { + static ExcelHelper() + { + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); + } + /// + /// 判断是否为兼容模式 + /// + /// + /// + public static bool GetIsCompatible(string filePath) + { + return filePath.EndsWith(".xls", StringComparison.OrdinalIgnoreCase); + } + /// + /// 创建工作薄 + /// + /// + /// + public static IWorkbook CreateWorkbook(bool isCompatible) + { + if (isCompatible) + { + return new HSSFWorkbook(); + } + else + { + return new XSSFWorkbook(); + } + } + + /// + /// 创建工作薄(依据文件流) + /// + /// + /// + /// + public static IWorkbook CreateWorkbook(bool isCompatible, dynamic stream) + { + if (isCompatible) + { + return new HSSFWorkbook(stream); + } + else + { + return new XSSFWorkbook(stream); + } + } + + + + /// + /// 列名字母转索引 + /// + /// + /// + public static int ToExcelColumnIndex(this string columnName) + { + if (!Regex.IsMatch(columnName.ToUpper(), @"[A-Z]+")) { throw new Exception("invalid parameter"); } + int index = 0; + char[] chars = columnName.ToUpper().ToCharArray(); + for (int i = 0; i < chars.Length; i++) + { + index += ((int)chars[i] - (int)'A' + 1) * (int)Math.Pow(26, chars.Length - i - 1); + } + return index - 1; + } + /// + /// 列索引转字母 + /// + /// + /// + public static string ToExcelColumnName(this int index) + { + if (index < 0) { throw new Exception("invalid parameter"); } + List chars = new List(); + do + { + if (chars.Count > 0) index--; + chars.Insert(0, ((char)(index % 26 + (int)'A')).ToString()); + index = (int)((index - index % 26) / 26); + } while (index > 0); + return String.Join(string.Empty, chars.ToArray()); + } + + + private static List GetDataByType(List list, Entities.EnumProjectType type) + { + return list.Where(a => a.type == type).ToList(); + } + + /// + /// + /// + /// + public static string WriteTemplate(List list, int start_row, string start_column) + { + try + { + string template_name = "2021年度甬江杯投票.xlsx"; + string excelFilePath = $"{App.WebHostEnvironment.WebRootPath}\\ExcelTemplate\\{template_name}"; + string outputPath = string.Empty; + if (!string.IsNullOrEmpty(excelFilePath)) + { + using (FileStream excelFileStream = System.IO.File.OpenRead(excelFilePath)) + { + bool isCompatible = ExcelHelper.GetIsCompatible(excelFilePath); + IWorkbook workbook = ExcelHelper.CreateWorkbook(isCompatible, excelFileStream); + ISheet sheet = null; + sheet = workbook.GetSheetAt(1); + Dictionary dic_sheet_config = new Dictionary(); + var data = GetDataByType(list, Entities.EnumProjectType.FangJian); + //从第几行开始 , 比如 行号是4 , 就写3 + var startRowIndex = start_row - 1; + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var length0 = data.Count; + data = GetDataByType(list, Entities.EnumProjectType.ShiZheng); + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = length0 + 1 + startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var length1 = data.Count; + data = GetDataByType(list, Entities.EnumProjectType.GuiDaoGongCheng); + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = length0 + 1 + length1 + 1 + startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var length2 = data.Count; + data = GetDataByType(list, Entities.EnumProjectType.DianLiGongCheng); + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = length0 + 1 + length1 + 1 + length2 + 1 + startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var length3 = data.Count; + data = GetDataByType(list, Entities.EnumProjectType.JiaoTongGongCheng); + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = length0 + 1 + length1 + 1 + length2 + 1 + length3 + 1 + startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var length4 = data.Count; + data = GetDataByType(list, Entities.EnumProjectType.ShuiLiGongCheng); + for (int i = 0; i < data.Count; i++) + { + var c_rowindex = length0 + 1 + length1 + 1 + length2 + 1 + length3 + 1 + length4 + 1 + startRowIndex + i; + int cell_start_index = start_column.ToExcelColumnIndex(); + sheet.GetRow(c_rowindex).GetCell(cell_start_index).SetCellValue(data[i].no_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 1).SetCellValue(data[i].yes_count); + sheet.GetRow(c_rowindex).GetCell(cell_start_index + 2).SetCellValue(data[i].is_agree ? "通过" : "不通过"); + } + var file = new FileInfo(excelFilePath); + var savePath = file.DirectoryName + "\\OutPut\\"; + if (!Directory.Exists(savePath)) + Directory.CreateDirectory(savePath); + outputPath = savePath + DateTime.Now.ToString("yyyyMMddHHmmss") + "-" + template_name; + using (var filess = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + workbook.Write(filess); + } + } + } + return outputPath; + } + catch (System.IO.IOException ioex) + { + throw Oops.Oh("文件被占用,请检查文件模板"); + } + } + } +} diff --git a/20220330_Vote/Vote.Services/Vote.Services.csproj b/20220330_Vote/Vote.Services/Vote.Services.csproj index 863ec06..1d441aa 100644 --- a/20220330_Vote/Vote.Services/Vote.Services.csproj +++ b/20220330_Vote/Vote.Services/Vote.Services.csproj @@ -12,4 +12,22 @@ + + + ..\Ewide.Web.Entry\bin\Debug\net5.0\ICSharpCode.SharpZipLib.dll + + + ..\Ewide.Web.Entry\bin\Debug\net5.0\NPOI.dll + + + ..\Ewide.Web.Entry\bin\Debug\net5.0\NPOI.OOXML.dll + + + ..\Ewide.Web.Entry\bin\Debug\net5.0\NPOI.OpenXml4Net.dll + + + ..\Ewide.Web.Entry\bin\Debug\net5.0\NPOI.OpenXmlFormats.dll + + + diff --git a/20220330_Vote/Vote.Services/Vote.Services.xml b/20220330_Vote/Vote.Services/Vote.Services.xml index 401b9b8..bf93e6b 100644 --- a/20220330_Vote/Vote.Services/Vote.Services.xml +++ b/20220330_Vote/Vote.Services/Vote.Services.xml @@ -9,12 +9,52 @@ 项目 - + 列表 + + + 检验提交码 + + + + + + 提交 + + + + + + 列表 + + + + + + + + + + + + + + + + + + 项目类型 + + + + + + + 项目序号 @@ -35,6 +75,51 @@ 项目类型 + + + + + + + + 项目类型 + + + + + 项目类型 + + + + + + + + + + 项目序号 + + + + + 工程名称 + + + + + + + + + + 项目类型 + + + + + 项目类型 + + 专家表 @@ -130,5 +215,52 @@ 投票时间 + + + + + + + + 判断是否为兼容模式 + + + + + + + 创建工作薄 + + + + + + + 创建工作薄(依据文件流) + + + + + + + + 列名字母转索引 + + + + + + + 列索引转字母 + + + + + + + + + +