PersonnelModuleController.cs 183 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283
  1. using Aspose.Cells;
  2. using Aspose.Words;
  3. using FluentValidation;
  4. using Microsoft.AspNetCore.SignalR;
  5. using OASystem.API.OAMethodLib;
  6. using OASystem.API.OAMethodLib.DeepSeekAPI;
  7. using OASystem.API.OAMethodLib.Hub.HubClients;
  8. using OASystem.API.OAMethodLib.Hub.Hubs;
  9. using OASystem.API.OAMethodLib.QiYeWeChatAPI;
  10. using OASystem.API.OAMethodLib.QiYeWeChatAPI.AppNotice;
  11. using OASystem.Domain.Dtos.Groups;
  12. using OASystem.Domain.Dtos.PersonnelModule;
  13. using OASystem.Domain.Dtos.Statistics;
  14. using OASystem.Domain.Entities.Groups;
  15. using OASystem.Domain.Entities.PersonnelModule;
  16. using OASystem.Domain.ViewModels.PersonnelModule;
  17. using OASystem.Domain.ViewModels.QiYeWeChat;
  18. using OASystem.Domain.ViewModels.Statistics;
  19. using OASystem.Infrastructure.Repositories.Groups;
  20. using OASystem.Infrastructure.Repositories.PersonnelModule;
  21. using System.Data;
  22. using System.Diagnostics;
  23. using System.Globalization;
  24. using static OASystem.API.OAMethodLib.JWTHelper;
  25. using Markdig;
  26. using Dm.util;
  27. namespace OASystem.API.Controllers
  28. {
  29. /// <summary>
  30. /// 人事模块
  31. /// </summary>
  32. [Route("api/[controller]/[action]")]
  33. public class PersonnelModuleController : ControllerBase
  34. {
  35. private Result _result;
  36. private readonly IMapper _mapper;
  37. //private readonly decimal _chengDuMinimumWage = 2100.00M;
  38. private readonly IQiYeWeChatApiService _qiYeWeChatApiService;
  39. private readonly WageSheetRepository _wageSheetRep;
  40. private readonly UsersRepository _usersRep;
  41. private readonly TaskAllocationRepository _taskAllocationRep;
  42. private readonly SqlSugarClient _sqlSugar;
  43. private readonly IHubContext<ChatHub, IChatClient> _hubContext;
  44. private readonly GoodsRepository _goodsRep;
  45. private readonly DecreasePaymentsRepository _otherPaymentRep;
  46. private readonly FeeAuditRepository _feeAuditRep;
  47. private readonly IDeepSeekService _deepSeekService;
  48. private readonly string url;
  49. private readonly string path;
  50. /// <summary>
  51. /// 初始化
  52. /// </summary>
  53. /// <param name="qiYeWeChatApiService"></param>
  54. /// <param name="wageSheetRep"></param>
  55. /// <param name="usersRep"></param>
  56. /// <param name="mapper"></param>
  57. /// <param name="taskAllocationRep"></param>
  58. /// <param name="hubContext"></param>
  59. /// <param name="goodsRep"></param>
  60. /// <param name="sqlSugar"></param>
  61. /// <param name="otherPaymentRep"></param>
  62. /// <param name="feeAuditRep"></param>
  63. /// <param name="deepSeekService"></param>
  64. public PersonnelModuleController(
  65. IHubContext<ChatHub, IChatClient> hubContext,
  66. IMapper mapper,
  67. IQiYeWeChatApiService qiYeWeChatApiService,
  68. WageSheetRepository wageSheetRep,
  69. UsersRepository usersRep,
  70. TaskAllocationRepository taskAllocationRep,
  71. GoodsRepository goodsRep,
  72. SqlSugarClient sqlSugar,
  73. DecreasePaymentsRepository otherPaymentRep,
  74. FeeAuditRepository feeAuditRep,
  75. IDeepSeekService deepSeekService
  76. )
  77. {
  78. _mapper = mapper;
  79. _usersRep = usersRep;
  80. _qiYeWeChatApiService = qiYeWeChatApiService;
  81. _wageSheetRep = wageSheetRep;
  82. _result = new Result();
  83. _sqlSugar = sqlSugar;
  84. url = AppSettingsHelper.Get("ExcelBaseUrl");
  85. path = AppSettingsHelper.Get("ExcelBasePath");
  86. if (!System.IO.Directory.Exists(path))
  87. {
  88. System.IO.Directory.CreateDirectory(path);//不存在就创建文件夹
  89. }
  90. this._taskAllocationRep = taskAllocationRep;
  91. _hubContext = hubContext;
  92. _goodsRep = goodsRep;
  93. _otherPaymentRep = otherPaymentRep;
  94. _feeAuditRep = feeAuditRep;
  95. _deepSeekService = deepSeekService;
  96. }
  97. #region 工资表单
  98. /// <summary>
  99. /// 工资 月列表
  100. /// </summary>
  101. /// <returns></returns>
  102. [HttpPost]
  103. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  104. public async Task<IActionResult> GetWageSheetMonth()
  105. {
  106. string sql = string.Format("Select * From Pm_WageIssueWorkingDay Where IsDel = 0 Order By YearMonth Desc");
  107. var data = await _wageSheetRep._sqlSugar.SqlQueryable<WageSheetMonthView>(sql).ToListAsync();
  108. return Ok(JsonView(true, "查询成功!", data));
  109. }
  110. /// <summary>
  111. /// 工资 工作日信息
  112. /// 查询
  113. /// </summary>
  114. /// <returns></returns>
  115. [HttpPost]
  116. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  117. public async Task<IActionResult> GetWageSheetMonthWorkdays(string startDt, string endDt)
  118. {
  119. //参数处理
  120. var dtFormat = "yyyy-MM-dd";
  121. var startDtIsValid = DateTime.TryParseExact(startDt, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out _);
  122. var endDtIsValid = DateTime.TryParseExact(endDt, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out _);
  123. if (!startDtIsValid) return Ok(JsonView(false, "开始日期格式错误!正确时间格式:yyyy-MM-dd "));
  124. if (!endDtIsValid) return Ok(JsonView(false, "结束格式错误!正确时间格式:yyyy-MM-dd "));
  125. string sql = string.Format(@"Select * From Sys_Calendar Where Isdel = 0 And Dt between '{0}' And '{1}'", startDt, endDt);
  126. var data = await _sqlSugar.SqlQueryable<CalendarInfoView>(sql).ToListAsync();
  127. return Ok(JsonView(true, "查询成功!", data));
  128. }
  129. /// <summary>
  130. /// 工资 工作日信息
  131. /// 编辑
  132. /// </summary>
  133. /// <returns></returns>
  134. [HttpPost]
  135. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  136. public async Task<IActionResult> GetWageSheetMonthWorkdaysAddOrEdit(WageSheetMonthWorkdaysAddOrEditDto dto)
  137. {
  138. //参数处理
  139. string yearFormat = "yyyy-MM";
  140. string dtFormat = "yyyy-MM-dd";
  141. bool yearDtIsValid = DateTime.TryParseExact(dto.YearMonth, yearFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime yearDt);
  142. bool startDtIsValid = DateTime.TryParseExact(dto.StartDate, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime startDt1);
  143. bool endDtIsValid = DateTime.TryParseExact(dto.EndDate, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime endDt1);
  144. if (!yearDtIsValid) return Ok(JsonView(false, "年月日期格式错误!正确时间格式:yyyy-MM "));
  145. if (!startDtIsValid) return Ok(JsonView(false, "开始日期格式错误!正确时间格式:yyyy-MM-dd "));
  146. if (!endDtIsValid) return Ok(JsonView(false, "结束格式错误!正确时间格式:yyyy-MM-dd "));
  147. #region 处理数据
  148. Pm_WageIssueWorkingDay pm_WageIssueWorkingDay1 = new();
  149. pm_WageIssueWorkingDay1 = _mapper.Map<Pm_WageIssueWorkingDay>(dto);
  150. List<Sys_Calendar> sys_Calendars = new();
  151. sys_Calendars = _mapper.Map<List<Sys_Calendar>>(dto.CalendarInfos);
  152. if (sys_Calendars.Count > 0)
  153. {
  154. sys_Calendars = sys_Calendars.OrderBy(it => it.Dt).ToList();
  155. }
  156. pm_WageIssueWorkingDay1.Workdays = sys_Calendars.Where(it => it.IsWorkDay == true).ToList().Count;
  157. foreach (var item in sys_Calendars)
  158. {
  159. item.Remark = pm_WageIssueWorkingDay1.Remark;
  160. item.CreateUserId = pm_WageIssueWorkingDay1.CreateUserId;
  161. item.CreateTime = pm_WageIssueWorkingDay1.CreateTime;
  162. }
  163. #endregion
  164. var _sqlSugar = _wageSheetRep._sqlSugar;
  165. _sqlSugar.BeginTran();
  166. try
  167. {
  168. List<Sys_Calendar> sys_Calendars_add = new();
  169. List<Sys_Calendar> sys_Calendars_update = new();
  170. sys_Calendars_add = sys_Calendars.Where(it => it.Id == 0).OrderBy(it => it.Dt).ToList();
  171. sys_Calendars_update = sys_Calendars.Where(it => it.Id != 0).OrderBy(it => it.Dt).ToList();
  172. //int add1 = 0;
  173. //int upd = 0;
  174. if (sys_Calendars_add.Count > 0)
  175. {
  176. var calendarsAdd = await _sqlSugar.Insertable(sys_Calendars_add).ExecuteReturnIdentityAsync();
  177. if (calendarsAdd < 0)
  178. {
  179. _sqlSugar.RollbackTran();
  180. return Ok(JsonView(false, "工作日/节假日/休息日添加失败!"));
  181. }
  182. }
  183. if (sys_Calendars_update.Count > 0)
  184. {
  185. var calendarsUpdate = await _sqlSugar.Updateable<Sys_Calendar>(sys_Calendars)
  186. .UpdateColumns(it => new { it.Dt, it.IsWorkDay, it.IsHoliDay, it.HoliName })
  187. .WhereColumns(it => it.Id)
  188. .ExecuteCommandAsync();
  189. if (calendarsUpdate < 0)
  190. {
  191. _sqlSugar.RollbackTran();
  192. return Ok(JsonView(false, "工作日/节假日/休息日编辑失败!"));
  193. }
  194. }
  195. var calendarsDatas = await _sqlSugar.Queryable<Sys_Calendar>()
  196. .Where(it => Convert.ToDateTime(it.Dt) >= Convert.ToDateTime(dto.StartDate) && Convert.ToDateTime(it.Dt) <= Convert.ToDateTime(dto.EndDate)).ToListAsync();
  197. if (calendarsDatas.Count < 0)
  198. {
  199. _sqlSugar.RollbackTran();
  200. return Ok(JsonView(false, "日期包暂无工作日/节假日/休息日的信息!"));
  201. }
  202. //月份表是否存在
  203. Pm_WageIssueWorkingDay pm_WageIssueWorkingDay = new()
  204. {
  205. YearMonth = dto.YearMonth,
  206. StartDate = dto.StartDate,
  207. EndDate = dto.EndDate,
  208. Workdays = calendarsDatas.Where(it => it.IsWorkDay == true).ToList().Count
  209. };
  210. string sql = string.Format("Select * From Pm_WageIssueWorkingDay Where Isdel = 0 And YearMonth='{0}'", dto.YearMonth);
  211. var workdsys = await _sqlSugar.SqlQueryable<Pm_WageIssueWorkingDay>(sql).FirstAsync();
  212. pm_WageIssueWorkingDay.CreateUserId = dto.UserId;
  213. pm_WageIssueWorkingDay.IsDel = 0;
  214. if (workdsys == null) //添加
  215. {
  216. int addId = await _sqlSugar.Insertable(pm_WageIssueWorkingDay).ExecuteReturnIdentityAsync();
  217. if (addId < 0)
  218. {
  219. _sqlSugar.RollbackTran();
  220. return Ok(JsonView(false, "工作日设置添加失败!"));
  221. }
  222. }
  223. else //更新
  224. {
  225. int updCount = await _sqlSugar.Updateable(pm_WageIssueWorkingDay)
  226. .IgnoreColumns(z => new { z.CreateUserId, z.CreateTime, z.DeleteUserId, z.DeleteTime, z.IsDel })
  227. .WhereColumns(it => it.YearMonth)
  228. .ExecuteCommandAsync();
  229. if (updCount < 0)
  230. {
  231. _sqlSugar.RollbackTran();
  232. return Ok(JsonView(false, "工作日设置编辑失败!"));
  233. }
  234. }
  235. _sqlSugar.CommitTran();
  236. return Ok(JsonView(true, "操作成功!"));
  237. }
  238. catch (Exception ex)
  239. {
  240. _sqlSugar.RollbackTran();
  241. return Ok(JsonView(false, ex.Message));
  242. }
  243. }
  244. /// <summary>
  245. /// 工资表单 基础数据源
  246. /// </summary>
  247. /// <returns></returns>
  248. [HttpPost]
  249. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  250. public async Task<IActionResult> GetWageSheetBasicsDataSource()
  251. {
  252. string companySql = string.Format("Select * From Sys_Company Where IsDel = 0");
  253. var compnayData = await _wageSheetRep._sqlSugar.SqlQueryable<CompanyNameView>(companySql).ToListAsync();
  254. string depSql = string.Format("Select * From Sys_Department Where IsDel = 0");
  255. var depData = await _wageSheetRep._sqlSugar.SqlQueryable<Domain.ViewModels.System.DepartmentView>(depSql).ToListAsync();
  256. //获取OA系统内所有用户
  257. var nameData = await _usersRep.GetUserNameList(1);
  258. if (nameData.Code != 0)
  259. {
  260. return Ok(JsonView(false, nameData.Msg));
  261. }
  262. var data = new
  263. {
  264. compnayData,
  265. depData,
  266. userNames = nameData.Data
  267. };
  268. return Ok(JsonView(true, "查询成功!", data));
  269. }
  270. /// <summary>
  271. /// 获取工资发放月份
  272. /// </summary>
  273. /// <param name="dto"></param>
  274. /// <returns></returns>
  275. [HttpPost]
  276. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  277. public async Task<IActionResult> GetWageYaerMonths(WageYearDto dto)
  278. {
  279. string sql = string.Format(@"Select * From Pm_WageIssueWorkingDay
  280. Where Isdel = 0 And YearMonth Like '%{0}%'
  281. Order By YearMonth Asc", dto.Year);
  282. var data = await _wageSheetRep._sqlSugar.SqlQueryable<WageYearMonthView>(sql).ToListAsync();
  283. return Ok(JsonView(true, "操作成功!", data));
  284. }
  285. /// <summary>
  286. /// 获取工资表单
  287. /// </summary>
  288. /// <param name="dto"></param>
  289. /// <returns></returns>
  290. [HttpPost]
  291. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  292. public async Task<IActionResult> GetWageSheetList(WageSheetListDto dto)
  293. {
  294. if (string.IsNullOrEmpty(dto.YearMonth)) return Ok(JsonView(false, "请选择日期格式"));
  295. //验证日期格式
  296. if (!DateTime.TryParse(dto.YearMonth, out DateTime yearMonthDt))
  297. {
  298. return Ok(JsonView(false, "无效的日期格式"));
  299. }
  300. //参数处理
  301. //string ymFormat = "yyyy-MM";
  302. //bool yearMonthDttIsValid = DateTime.TryParseExact(dto.YearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime yearMonthDt);
  303. //if (!yearMonthDttIsValid)
  304. //{
  305. // _result.Msg = "年月格式错误!正确时间格式:yyyy-MM ";
  306. // return Ok(JsonView(false, _result.Msg));
  307. //}
  308. //获取月工资数据
  309. string yearMonth = yearMonthDt.ToString("yyyy-MM");
  310. if (dto.PortType == 1)
  311. {
  312. _result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(yearMonth);
  313. if (_result.Code != 0)
  314. {
  315. return Ok(JsonView(false, _result.Msg));
  316. }
  317. }
  318. else if (dto.PortType == 2)
  319. { }
  320. else if (dto.PortType == 3)
  321. { }
  322. else
  323. {
  324. return Ok(JsonView(false, "请选择正确的端口参数"));
  325. }
  326. return Ok(JsonView(true, _result.Msg, _result.Data));
  327. }
  328. /// <summary>
  329. /// 获取工资 详情
  330. /// </summary>
  331. /// <param name="dto"></param>
  332. /// <returns></returns>
  333. [HttpPost]
  334. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  335. public async Task<IActionResult> GetWageSheetById(WageSheetInfoDto dto)
  336. {
  337. if (dto.PortType == 1)
  338. {
  339. _result = await _wageSheetRep.Get_WageSheet_InfoByIdAsync(dto.Id);
  340. if (_result.Code != 0)
  341. {
  342. return Ok(JsonView(false, _result.Msg));
  343. }
  344. }
  345. else if (dto.PortType == 2)
  346. { }
  347. else if (dto.PortType == 3)
  348. { }
  349. else
  350. {
  351. return Ok(JsonView(false, "请选择正确的端口参数"));
  352. }
  353. return Ok(JsonView(true, _result.Msg, _result.Data));
  354. }
  355. /// <summary>
  356. /// 人事模块 工资表单 删除
  357. /// </summary>
  358. /// <param name="dto"></param>
  359. /// <returns></returns>
  360. [HttpPost]
  361. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  362. public async Task<IActionResult> PostWageSheetDel(WageDelDto dto)
  363. {
  364. try
  365. {
  366. _result = await _wageSheetRep.Post_WageSheet_DelAsync(dto);
  367. if (_result.Code != 0)
  368. {
  369. return Ok(JsonView(false, _result.Msg));
  370. }
  371. }
  372. catch (Exception ex)
  373. {
  374. return Ok(JsonView(false, ex.Message));
  375. }
  376. return Ok(JsonView(true, _result.Msg, _result.Data));
  377. }
  378. /// <summary>
  379. /// 人事模块 工资表单 添加 Or 修改
  380. /// </summary>
  381. /// <param name="dto"></param>
  382. /// <returns></returns>
  383. [HttpPost]
  384. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  385. public async Task<IActionResult> PostWageSheetAddOrEdit(WageAddOrEditDto dto)
  386. {
  387. try
  388. {
  389. Pm_WageSheet pm_WageSheet = new();
  390. pm_WageSheet = _mapper.Map<Pm_WageSheet>(dto);
  391. pm_WageSheet.LastUpdateUserId = dto.CreateUserId;
  392. #region 计算工资
  393. //月工资
  394. decimal salary = pm_WageSheet.Basic + pm_WageSheet.Floats + pm_WageSheet.PostAllowance + pm_WageSheet.InformationSecurityFee + pm_WageSheet.OtherSubsidies;
  395. //扣款合计
  396. decimal totalDeduction = pm_WageSheet.SickLeave + pm_WageSheet.SomethingFalse + pm_WageSheet.LateTo + pm_WageSheet.LeaveEarly + pm_WageSheet.Absenteeism + pm_WageSheet.NotPunch +
  397. pm_WageSheet.ReservedFunds + pm_WageSheet.WithholdingInsurance + pm_WageSheet.OtherDeductions + pm_WageSheet.OtherDeductions;
  398. //实发合计 不含个税
  399. if (pm_WageSheet.RegularDays >= pm_WageSheet.WorkDays)
  400. {
  401. pm_WageSheet.RegularDays = pm_WageSheet.WorkDays;
  402. salary = salary + pm_WageSheet.Mealsupplement + pm_WageSheet.OtherHandle;
  403. }
  404. else
  405. {
  406. if (dto.UserId == 21) //21==张海麟
  407. {
  408. salary = salary + pm_WageSheet.Mealsupplement + pm_WageSheet.OtherHandle;
  409. }
  410. else
  411. {
  412. salary = PayrollComputation.ConvertToDecimal(salary / pm_WageSheet.WorkDays * pm_WageSheet.RegularDays + pm_WageSheet.Mealsupplement + pm_WageSheet.OtherHandle);
  413. }
  414. }
  415. decimal actualTotal = salary - totalDeduction;
  416. pm_WageSheet.Should = salary;
  417. pm_WageSheet.TotalDeductions = totalDeduction;
  418. pm_WageSheet.TotalRealHair = actualTotal - pm_WageSheet.WithholdingTax;
  419. pm_WageSheet.AfterTax = actualTotal - pm_WageSheet.WithholdingTax;
  420. #endregion
  421. _result = await _wageSheetRep.Post_WageSheet_AddOrEditAsync(dto, pm_WageSheet);
  422. if (_result.Code != 0)
  423. {
  424. return Ok(JsonView(false, _result.Msg));
  425. }
  426. }
  427. catch (Exception ex)
  428. {
  429. return Ok(JsonView(false, ex.Message));
  430. }
  431. return Ok(JsonView(true, _result.Msg, _result.Data));
  432. }
  433. /// <summary>
  434. /// 计算工资
  435. /// </summary>
  436. /// <returns></returns>
  437. [HttpPost]
  438. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  439. public async Task<IActionResult> SalaryCalculatorAsync(SalaryCalculatorDto dto)
  440. {
  441. Result result = new();
  442. Stopwatch sw = new();
  443. sw.Start();
  444. //参数处理
  445. string ymFormat = "yyyy-MM";
  446. string dtFormat = "yyyy-MM-dd";
  447. bool yearMonthDtIsValid = DateTime.TryParseExact(dto.yearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime yearMonthDt);
  448. bool startDtIsValid = DateTime.TryParseExact(dto.startDt, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime startDt);
  449. bool endDtIsValid = DateTime.TryParseExact(dto.endDt, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime endDt);
  450. if (!yearMonthDtIsValid) return Ok(JsonView(false, "年月格式错误!正确时间格式:yyyy-MM "));
  451. if (!startDtIsValid) return Ok(JsonView(false, "开始日期格式错误!正确时间格式:yyyy-MM-dd "));
  452. if (!endDtIsValid) return Ok(JsonView(false, "结束格式错误!正确时间格式:yyyy-MM-dd "));
  453. string thisYearMonth = dto.yearMonth;
  454. string preYearMonth = yearMonthDt.AddMonths(-1).ToString("yyyy-MM");
  455. //计算本月工资起止时间 比如是2月的1号-28号,那就是2月1号的零点到3月1号的零点
  456. DateTime thisStartDt = startDt;
  457. DateTime thisEndDt = endDt; //
  458. //本月工资是否有数据 有数据则不计算
  459. result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(thisYearMonth);
  460. if (result.Code == 0)
  461. {
  462. return Ok(JsonView(false, thisYearMonth + " 工资数据已存在,若无人员工资请手动添加!"));
  463. }
  464. //获取上个月工资信息
  465. List<Pm_WageSheet> preWageSheetItems = await _wageSheetRep._sqlSugar.Queryable<Pm_WageSheet>().Where(it => it.IsDel == 0 && it.YearMonth == preYearMonth).ToListAsync();
  466. preWageSheetItems = preWageSheetItems.OrderBy(it => it.UserId).ToList();
  467. if (preWageSheetItems.Count <= 0)
  468. {
  469. return Ok(JsonView(false, thisYearMonth + " 上月工资数据不存在,请手动添加!"));
  470. }
  471. //处理上个月同月同人 多条数据
  472. List<Pm_WageSheet> preWageSheetItems1 = new();
  473. //preWageSheetItems1 = preWageSheetItems.GroupBy(it => new { it.YearMonth, it.UserId })
  474. // .Select(it => it.FirstOrDefault(item => item.Basic != 0))
  475. // .ToList();
  476. preWageSheetItems1 = preWageSheetItems
  477. .GroupBy(it => new { it.YearMonth, it.UserId })
  478. .Select(it => it.FirstOrDefault(item => item.Basic != 0))
  479. .Where(it => it != null)
  480. .ToList()!;
  481. //获取OA系统内所有用户
  482. List<UserNameView> userNames = _usersRep._sqlSugar.SqlQueryable<UserNameView>("Select Id,CnName From Sys_Users").ToList();
  483. List<Pm_WageSheet> wageSheets = new();
  484. _result = await PayrollComputation.SalaryCalculatorAsync(preWageSheetItems1, userNames, dto.UserId, thisYearMonth, thisStartDt, thisEndDt);
  485. #region 批量添加
  486. if (_result.Code != 0)
  487. {
  488. return Ok(JsonView(false, _result.Msg));
  489. }
  490. wageSheets = _result.Data;
  491. var add = await _wageSheetRep._sqlSugar.Insertable(wageSheets).ExecuteCommandAsync();
  492. if (add <= 0)
  493. {
  494. return Ok(JsonView(false, "操作失败!"));
  495. }
  496. #endregion
  497. #region 处理返回数据
  498. //List <WageSheetItemInfoView> wageSheetItems = new List<WageSheetItemInfoView>();
  499. //wageSheetItems = _mapper.Map<List<WageSheetItemInfoView>>(wageSheets);
  500. //wageSheetItems = wageSheetItems.Select(it =>
  501. // {
  502. // UserNameView? uName1 = new UserNameView();
  503. // UserNameView? uName2 = new UserNameView();
  504. // uName1 = userNames.Where(it1 => it.UserId == it1.Id).FirstOrDefault();
  505. // if (uName1 != null) it.Name = uName1.CnName;
  506. // uName2 = userNames.Where(it1 => it.LastUpdateUserId == it1.Id).FirstOrDefault();
  507. // if (uName2 != null) it.LastUpdateUserName = uName2.CnName;
  508. // return it; }
  509. // ).ToList();
  510. #endregion
  511. sw.Stop();
  512. return Ok(JsonView(true, "操作成功! 耗时:" + (sw.ElapsedMilliseconds / 1000) + "s"));
  513. }
  514. /// <summary>
  515. /// 计算工资 By YearMonth And UserId
  516. /// </summary>
  517. /// <returns></returns>
  518. [HttpPost]
  519. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  520. public async Task<IActionResult> SalaryCalculatorSingleAsync(SalaryCalculatorSingleDto dto)
  521. {
  522. Result result = new();
  523. Stopwatch sw = new();
  524. sw.Start();
  525. //参数处理
  526. string ymFormat = "yyyy-MM";
  527. string ymdFormat = "yyyy-MM-dd";
  528. bool yearMonthDtIsValid = DateTime.TryParseExact(dto.YearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime yearMonthDt);
  529. bool startDtIsValid = DateTime.TryParseExact(dto.StartDate, ymdFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime startDt);
  530. bool endDtIsValid = DateTime.TryParseExact(dto.EndDate, ymdFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime endDt);
  531. if (!yearMonthDtIsValid) return Ok(JsonView(false, "年月格式错误!正确时间格式:yyyy-MM "));
  532. if (!startDtIsValid) return Ok(JsonView(false, "开始时间格式错误!正确时间格式:yyyy-MM-dd "));
  533. if (!yearMonthDtIsValid) return Ok(JsonView(false, "结束时间格式错误!正确时间格式:yyyy-MM-dd "));
  534. List<Pm_WageSheet> wageSheets = new();
  535. Pm_WageSheet wageSheet = _mapper.Map<Pm_WageSheet>(dto);
  536. Pm_WageSheet wageSheet1 = await _wageSheetRep._sqlSugar.Queryable<Pm_WageSheet>().Where(it => it.UserId == dto.UserId && it.YearMonth == dto.YearMonth && it.StartDate == dto.StartDate && it.EndDate == dto.EndDate).FirstAsync();
  537. if (wageSheet1 != null)
  538. {
  539. wageSheet.Id = wageSheet1.Id;
  540. }
  541. wageSheets.Add(wageSheet);
  542. //获取OA系统内所有用户
  543. List<UserNameView> userNames = _usersRep._sqlSugar.SqlQueryable<UserNameView>("Select Id,CnName From Sys_Users").ToList();
  544. _result = await PayrollComputation.SalaryCalculatorAsync(wageSheets, userNames, dto.UserId, dto.YearMonth, startDt, endDt);
  545. if (_result.Code != 0)
  546. {
  547. return Ok(JsonView(false, _result.Msg));
  548. }
  549. List<Pm_WageSheet> wageSheets1 = new();
  550. wageSheets1 = _result.Data;
  551. #region 处理返回数据
  552. List<WageSheetInfoView> wageSheetItems = new();
  553. wageSheetItems = _mapper.Map<List<WageSheetInfoView>>(wageSheets1);
  554. wageSheetItems = wageSheetItems.Select(it =>
  555. {
  556. UserNameView? uName1 = new();
  557. UserNameView? uName2 = new();
  558. uName1 = userNames.Where(it1 => it.UserId == it1.Id).FirstOrDefault();
  559. if (uName1 != null) it.Name = uName1.CnName;
  560. uName2 = userNames.Where(it1 => it.LastUpdateUserId == it1.Id).FirstOrDefault();
  561. if (uName2 != null) it.LastUpdateUserName = uName2.CnName;
  562. return it;
  563. }
  564. ).ToList();
  565. #endregion
  566. sw.Stop();
  567. return Ok(JsonView(true, "操作成功!耗时:" + (sw.ElapsedMilliseconds / 1000) + "s", wageSheetItems[0]));
  568. }
  569. /// <summary>
  570. /// 导出工资单
  571. /// </summary>
  572. /// <returns></returns>
  573. [HttpPost]
  574. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  575. public async Task<IActionResult> ExportWageCard(string yearMonth)
  576. {
  577. Stopwatch sw = new();
  578. sw.Start();
  579. //参数处理
  580. string ymFormat = "yyyy-MM";
  581. bool yearMonthDtIsValid = DateTime.TryParseExact(yearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out _);
  582. if (!yearMonthDtIsValid) return Ok(JsonView(false, "年月格式错误!正确时间格式:yyyy-MM "));
  583. //公司部门
  584. string sql = string.Format(@"Select row_number() over(order by pm_ws.Id) as Row_Number,
  585. sc.Id as CompanyId,sc.CompanyName,sd.Id as DepId,sd.DepName,
  586. sys_u1.CnName Name,sys_u2.CnName LastUpdateUserName,pm_ws.*
  587. From Pm_WageSheet pm_ws
  588. Left Join Sys_Users sys_u1 On pm_ws.UserId = sys_u1.Id
  589. Left Join Sys_Users sys_u2 On pm_ws.LastUpdateUserId = sys_u2.Id
  590. Left Join Sys_Company sc On sys_u1.companyId = sc.Id
  591. Left Join Sys_Department sd On sys_u1.DepId = sd.Id
  592. Where pm_ws.IsDel = 0 And pm_ws.YearMonth = '{0}'", yearMonth);
  593. var wageSheetList = await _wageSheetRep._sqlSugar.SqlQueryable<ExportWageSheetItemView>(sql).ToListAsync();
  594. if (wageSheetList.Count <= 0)
  595. {
  596. return Ok(JsonView(false, yearMonth + "暂无工资数据!"));
  597. }
  598. decimal SumPrice = 0.00M;
  599. foreach (var item in wageSheetList)
  600. {
  601. SumPrice += item.AfterTax;
  602. }
  603. WorkbookDesigner designer = new()
  604. {
  605. Workbook = new Workbook(AppSettingsHelper.Get("ExcelBasePath") + "Template/工资详细清单.xlsx")
  606. };
  607. designer.Workbook.Worksheets[0].Name = yearMonth + " 工资单";
  608. designer.SetDataSource("WageSheet", wageSheetList);
  609. designer.SetDataSource("YearMonth", yearMonth);
  610. designer.SetDataSource("StartEndDt", wageSheetList[0].StartDate + " - " + wageSheetList[0].EndDate);
  611. designer.SetDataSource("WorkDays", wageSheetList[0].WorkDays);
  612. designer.SetDataSource("SumPrice", SumPrice);
  613. designer.SetDataSource("WageSheetTitle", "工资单");//
  614. designer.Process();
  615. string fileName = "WageCard/" + yearMonth + "_工资单_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx";
  616. string path = AppSettingsHelper.Get("ExcelBasePath");
  617. designer.Workbook.Save(path + fileName);
  618. string excelPath = AppSettingsHelper.Get("ExcelFtpPath") + fileName;
  619. string url = AppSettingsHelper.Get("ExcelBaseUrl");
  620. string fileUrl = url + excelPath;
  621. sw.Stop();
  622. return Ok(JsonView(true, "操作成功!耗时:" + (sw.ElapsedMilliseconds / 1000) + "s", new { FileUrl = fileUrl }));
  623. }
  624. /// <summary>
  625. /// 下载个税模板
  626. /// </summary>
  627. /// <returns></returns>
  628. [HttpPost]
  629. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  630. public async Task<IActionResult> WageSheetTaxTemplate()
  631. {
  632. //string serverUrl = AppSettingsHelper.Get("WageSheetExcelBaseUrl");
  633. var userData = await _usersRep.GetUserNameList(1);
  634. if (userData.Code == 0)
  635. {
  636. var userNames = userData.Data;
  637. List<string> names = new()
  638. {
  639. "管理员",
  640. "国交共享号",
  641. "人事审核号",
  642. "国交主管号"
  643. };
  644. List<TaxTemlateViuw> taxs = new();
  645. List<UserNameView> users = JsonConvert.DeserializeObject<List<UserNameView>>(JsonConvert.SerializeObject(userNames));
  646. foreach (UserNameView item in users)
  647. {
  648. string uName = item.CnName;
  649. if (!names.Contains(uName))
  650. {
  651. taxs.Add(new TaxTemlateViuw { UserName = item.CnName });
  652. }
  653. }
  654. if (taxs.Count > 0)
  655. {
  656. WorkbookDesigner designer = new()
  657. {
  658. Workbook = new Workbook(AppSettingsHelper.Get("ExcelBasePath") + "Template/个税导入模板.xlsx")
  659. };
  660. designer.Workbook.Worksheets[0].Name = "个税模板";
  661. designer.SetDataSource("TaxTemp", taxs);
  662. designer.Process();
  663. string fileName = "WageSheetTaxFile/个税模板" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx";
  664. string path = AppSettingsHelper.Get("ExcelBasePath");
  665. designer.Workbook.Save(path + fileName);
  666. string excelPath = AppSettingsHelper.Get("ExcelFtpPath") + fileName;
  667. string url = AppSettingsHelper.Get("ExcelBaseUrl");
  668. string fileUrl = url + excelPath;
  669. return Ok(JsonView(true, "操作成功!", new { FileUrl = fileUrl }));
  670. }
  671. }
  672. return Ok(JsonView(false, "操作失败!"));
  673. }
  674. /// <summary>
  675. /// 上传个税
  676. /// </summary>
  677. /// <returns></returns>
  678. [HttpPost]
  679. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  680. public async Task<IActionResult> UploadTax(IFormFile file)
  681. {
  682. try
  683. {
  684. var yearMonth = Request.Headers["YearMonth"].ToString();
  685. //string yearMonth = "2023-10";
  686. string ymFormat = "yyyy-MM";
  687. bool yearMonthDtIsValid = DateTime.TryParseExact(yearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime yearMonthDt);
  688. if (!yearMonthDtIsValid) return Ok(JsonView(false, "年月格式错误!正确时间格式:yyyy-MM "));
  689. if (file != null)
  690. {
  691. var fileDir = AppSettingsHelper.Get("WageSheetExcelFptPath");
  692. //文件名称
  693. string projectFileName = file.FileName;
  694. //上传的文件的路径
  695. string filePath = "";
  696. if (!Directory.Exists(fileDir))
  697. {
  698. Directory.CreateDirectory(fileDir);
  699. }
  700. //上传的文件的路径
  701. filePath = fileDir + $@"\{projectFileName}";
  702. if (System.IO.File.Exists(filePath))
  703. {
  704. //删除文件
  705. System.IO.File.Delete(filePath);
  706. }
  707. using (FileStream fs = System.IO.File.Create(filePath))
  708. {
  709. file.CopyTo(fs);
  710. fs.Flush();
  711. }
  712. if (System.IO.File.Exists(filePath))
  713. {
  714. Workbook book = new(filePath);
  715. DataSet dataSet = new();
  716. if (book.Worksheets.Count > 0)
  717. {
  718. var sheet = book.Worksheets[0];
  719. if (sheet != null)
  720. {
  721. // sheets 中的数据必须存在
  722. if (sheet.Cells.MaxDataRow != -1 && sheet.Cells.MaxDataColumn != -1)
  723. {
  724. // 方法 ExportDataTable 的参数说明
  725. // 要导出的第一个单元格的行号。
  726. // 要导出的第一个单元格的列号。
  727. // 要导入的行数。
  728. // 要导入的列数。
  729. // 指示第一行的数据是否导出到DataTable的列名。
  730. DataTable dataTable = sheet.Cells.ExportDataTable(0, 0, sheet.Cells.MaxDataRow + 1, sheet.Cells.MaxDataColumn + 1, true);
  731. dataSet.Tables.Add(dataTable);
  732. DataTable taxData = dataSet.Tables[0];
  733. //公司部门
  734. string sql = string.Format(@"Select row_number() over(order by pm_ws.Id) as Row_Number,
  735. sc.Id as CompanyId,sc.CompanyName,sd.Id as DepId,sd.DepName,
  736. sys_u1.CnName Name,sys_u2.CnName LastUpdateUserName,pm_ws.*
  737. From Pm_WageSheet pm_ws
  738. Left Join Sys_Users sys_u1 On pm_ws.UserId = sys_u1.Id
  739. Left Join Sys_Users sys_u2 On pm_ws.LastUpdateUserId = sys_u2.Id
  740. Left Join Sys_Company sc On sys_u1.companyId = sc.Id
  741. Left Join Sys_Department sd On sys_u1.DepId = sd.Id
  742. Where pm_ws.IsDel = 0 And pm_ws.YearMonth = '{0}'
  743. Order By UserId Asc ", yearMonth);
  744. var wageSheetList = await _wageSheetRep._sqlSugar.SqlQueryable<WageSheetInfoView>(sql).ToListAsync();
  745. if (wageSheetList.Count <= 0)
  746. {
  747. return Ok(JsonView(false, yearMonth + "工资数据不存在,请先添加工资数据!"));
  748. }
  749. for (int i = 0; i < taxData.Rows.Count; i++)
  750. {
  751. string name = taxData.Rows[i][0].ToString().Trim();
  752. List<WageSheetInfoView> wageSheets = new();
  753. wageSheets = wageSheetList.Where(it => it.Name.Equals(name)).ToList();
  754. if (wageSheets.Count > 0)
  755. {
  756. wageSheetList.Where(it => it.Name.Equals(name))
  757. .Select(it =>
  758. {
  759. //修改 绩效不等于0.00M的数据
  760. //decimal oldTax = it.WithholdingTax;
  761. var newTax = Convert.ToDecimal(taxData.Rows[i][1].ToString());
  762. it.WithholdingTax = newTax;
  763. it.TotalRealHair = it.Should - it.TotalDeductions - newTax;
  764. return it;
  765. })
  766. .ToList();
  767. }
  768. }
  769. List<Pm_WageSheet> wageSheets1 = new();
  770. wageSheets1 = _mapper.Map<List<Pm_WageSheet>>(wageSheetList);
  771. var updateStatus = _wageSheetRep._sqlSugar
  772. .Updateable(wageSheets1)
  773. .UpdateColumns(it => new { it.WithholdingTax, it.TotalRealHair })
  774. .ExecuteCommand();
  775. if (updateStatus < 0)
  776. {
  777. return Ok(JsonView(false, "操作失败!"));
  778. }
  779. if (System.IO.File.Exists(filePath))
  780. {
  781. //删除文件
  782. System.IO.File.Delete(filePath);
  783. }
  784. return Ok(JsonView(true, "操作成功!"));
  785. }
  786. }
  787. else
  788. {
  789. return Ok(JsonView(false, "工作薄没有数据!"));
  790. }
  791. }
  792. }
  793. return Ok(JsonView(true, "上传成功!", projectFileName));
  794. }
  795. else
  796. {
  797. return Ok(JsonView(false, "上传失败!"));
  798. }
  799. }
  800. catch (Exception ex)
  801. {
  802. return Ok(JsonView(false, "程序错误!"));
  803. throw;
  804. }
  805. //return Ok(JsonView(true, "操作成功!"));
  806. }
  807. /// <summary>
  808. /// 打卡记录测试
  809. /// </summary>
  810. /// <returns></returns>
  811. [HttpPost]
  812. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  813. public async Task<IActionResult> Test(string startDt, string endDt, int code)
  814. {
  815. UserIdListView userIdListView = await _qiYeWeChatApiService.GetUserIdListAsync();
  816. if (userIdListView.errcode != 0)
  817. {
  818. _result.Msg = "【企业微信】【打卡】【获取员工ID】【Msg】" + userIdListView.errmsg;
  819. return Ok(JsonView(false, _result.Msg));
  820. }
  821. List<string> qyWhchatIdList = new();
  822. //qyWhchatIdList = userIdListView.dept_user.Select(it => it.userid).ToList();
  823. qyWhchatIdList = userIdListView.dept_user.Select(it => it.userid!).ToList();
  824. var data = await _qiYeWeChatApiService.GetCheckinDataAsync(qyWhchatIdList, code, Convert.ToDateTime(startDt), Convert.ToDateTime(endDt));
  825. return Ok(JsonView(true, "操作成功!", data.checkindata));
  826. }
  827. /// <summary>
  828. /// 审批详情
  829. /// </summary>
  830. /// <returns></returns>
  831. [HttpPost]
  832. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  833. public async Task<IActionResult> PostApprovalDetailAsync(string spNo)
  834. {
  835. if (string.IsNullOrEmpty(spNo))
  836. {
  837. return Ok(JsonView(false, "审批单号不能为空!!"));
  838. }
  839. var data = await _qiYeWeChatApiService.GetApprovalDetailAsync(spNo);
  840. return Ok(JsonView(true, "操作成功!", data));
  841. }
  842. #endregion
  843. #region 任务单
  844. /// <summary>
  845. /// 任务分配
  846. /// 基础数据源
  847. /// </summary>
  848. /// <returns></returns>
  849. [HttpPost]
  850. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  851. public async Task<IActionResult> PostTaskAllocationInit(TaskAllocationInitDto dto)
  852. {
  853. #region 参数验证
  854. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  855. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  856. #region 页面操作权限验证
  857. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  858. if (pageFunAuthView.CheckAuth == 0) return Ok(JsonView(false, "您没有查看权限!"));
  859. #endregion
  860. #endregion
  861. var _view = await _taskAllocationRep._Init(dto.PortType, dto.UserId);
  862. if (_view.Code == 0)
  863. {
  864. return Ok(JsonView(true, "查询成功!", _view.Data));
  865. }
  866. return Ok(JsonView(false, _view.Msg));
  867. }
  868. /// <summary>
  869. /// 任务分配
  870. /// page
  871. /// </summary>
  872. /// <returns></returns>
  873. [HttpPost]
  874. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  875. public async Task<IActionResult> PostTaskAllocationPage(TaskAllocationPageDto dto)
  876. {
  877. #region 参数验证
  878. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  879. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  880. PageFunAuthViewBase pageFunAuthView = new();
  881. #region 页面操作权限验证
  882. pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  883. if (pageFunAuthView.CheckAuth == 0) return Ok(JsonView(false, "您没有查看权限!"));
  884. #endregion
  885. #endregion
  886. var groupNames = dto.GroupNames;
  887. var groupArr = Array.Empty<string>();
  888. if (!string.IsNullOrEmpty(groupNames))
  889. {
  890. groupArr = groupNames.Split(',').Select(part => part.Trim()).ToArray();
  891. }
  892. string whereSql = "", currUserName = "";
  893. #region 分页参数处理
  894. //类型处理
  895. if (dto.Type == 0) whereSql = "";
  896. else if (dto.Type == 1) //1 由我指派
  897. {
  898. //whereSql = string.Format(@" And ta.CreateUserId = {0} Or (Select COUNT(1) As PeopleNumber From Pm_TaskRelevanceUser Where IsDel = 0 And ta.Id = TAId And UserId = {0}) > 0", dto.UserId);
  899. }
  900. else if (dto.Type == 2)// 2 指派给我
  901. {
  902. //whereSql = string.Format(@" And (Select COUNT(1) As PeopleNumber From Pm_TaskRelevanceUser Where IsDel = 0 And ta.Id = TAId And UserId = {0}) > 0", dto.UserId);
  903. }
  904. //状态 -1 全部 0 未开始 1 进行中 2 待审核 3 未完成 4 已完成
  905. if (dto.Status == -1) //全部
  906. {
  907. whereSql += "";
  908. }
  909. else
  910. {
  911. whereSql += string.Format(@" And ta.Status = {0} ", dto.Status);
  912. }
  913. //任务名称
  914. if (!string.IsNullOrEmpty(dto.TaskName))
  915. {
  916. whereSql += string.Format(@" And ta.TaskName Like '%{0}%' ", dto.TaskName);
  917. }
  918. #endregion
  919. var currUserInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.Id == dto.UserId);
  920. if (currUserInfo != null) currUserName = currUserInfo.CnName;
  921. string pageSql = string.Format(@"Select
  922. ROW_NUMBER() OVER(
  923. ORDER BY
  924. CreateTime Desc
  925. ) AS RowNumber,
  926. *
  927. From
  928. (
  929. Select
  930. ta.Id,
  931. ta.TaskName,
  932. ta.TaskContent,
  933. ta.TaskPriority,
  934. d.DepName,
  935. di.TeamName,
  936. ta.Status,
  937. ta.PredictBeginTime,
  938. ta.PredictEndTime,
  939. u.CnName As CreateUserName,
  940. ta.CreateTime,
  941. (
  942. SELECT
  943. STUFF(
  944. (
  945. Select
  946. ',' + u.CnName
  947. From
  948. Pm_TaskRelevanceUser tra
  949. Left Join Sys_Users u On tra.UserId = u.Id
  950. Where
  951. tra.Isdel = 0
  952. And tra.TAId = ta.Id FOR XML PATH('')
  953. ),
  954. 1,
  955. 1,
  956. ''
  957. )
  958. ) As Participant,
  959. (
  960. SELECT
  961. STUFF(
  962. (
  963. Select
  964. ',' + u.CnName
  965. From
  966. Pm_TaskRelevanceUser tra
  967. Left Join Sys_Users u On tra.UserId = u.Id
  968. Where
  969. tra.Isdel = 0
  970. And tra.TAId = ta.Id
  971. And tra.TaskStatus = 4 FOR XML PATH('')
  972. ),
  973. 1,
  974. 1,
  975. ''
  976. )
  977. ) As Consummator
  978. From
  979. Pm_TaskAllocation ta
  980. Left Join Sys_Department d On ta.DepId = d.Id
  981. Left Join Grp_DelegationInfo di On ta.DiId = di.Id
  982. Left Join Sys_Users u On ta.CreateUserId = u.Id
  983. Where
  984. ta.IsDel = 0 {0}
  985. ) As temp
  986. WHERE
  987. [CreateUserName] like '%{1}%'
  988. OR [Participant] like '%{2}%' ", whereSql, currUserName, currUserName);
  989. RefAsync<int> total = 0;
  990. var _view = await _sqlSugar.SqlQueryable<TaskListView>(pageSql)
  991. .WhereIF(groupArr.Any(), x => groupArr.Contains(x.TeamName))
  992. .ToPageListAsync(dto.PageIndex, dto.PageSize, total);//ToPageAsync
  993. List<int> taskIds = taskIds = _view.Select(it => it.Id).ToList();
  994. string taskerSql = string.Format(@"Select tau.TAId,tau.Id,tau.UserId,u.CnName As UserName,tau.BeginTime,tau.OverTime,tau.TaskStatus,
  995. tau.Cause,tau.Score,tau.Remark As ScoreRemark,tau.CreateUserId As TaskCreateUserId
  996. From Pm_TaskRelevanceUser tau
  997. Left Join Sys_Users u On tau.UserId = u.Id
  998. Where tau.IsDel = 0");
  999. var taskerData = _sqlSugar.SqlQueryable<TaskerDetailsView>(taskerSql).Where(it => taskIds.Contains(it.TAId)).ToList();
  1000. foreach (var item in _view)
  1001. {
  1002. //任务接收者显示自己任务状态
  1003. if (!item.CreateUserName.Equals(currUserName))
  1004. {
  1005. var subTaskInfo = taskerData.FirstOrDefault(x => item.Id == x.TAId && x.UserId == dto.UserId);
  1006. if (subTaskInfo != null) item.Status = subTaskInfo.TaskStatus;
  1007. }
  1008. else
  1009. {
  1010. item.TaskerDetails = taskerData.Where(it => it.TAId == item.Id).ToArray();
  1011. }
  1012. ////处理任务总状态 And 任务人状态
  1013. //var taskerStatusData = taskerData.Where(it => it.TAId == item.Id && it.TaskCreateUserId != dto.UserId && it.UserId == dto.UserId).FirstOrDefault();
  1014. //if (taskerStatusData != null)
  1015. //{
  1016. // item.Status = taskerStatusData.TaskStatus;
  1017. //}
  1018. }
  1019. return Ok(JsonView(true, "查询成功!", _view, total));
  1020. }
  1021. /// <summary>
  1022. /// 任务分配
  1023. /// 详情
  1024. /// </summary>
  1025. /// <returns></returns>
  1026. [HttpPost]
  1027. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1028. public async Task<IActionResult> PostTaskAllocationDetails(TaskAllocationDetailsDto dto)
  1029. {
  1030. #region 参数验证
  1031. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1032. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1033. #region 页面操作权限验证
  1034. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1035. if (pageFunAuthView.CheckAuth == 0) return Ok(JsonView(false, "您没有查看权限!"));
  1036. #endregion
  1037. #endregion
  1038. var _view = await _taskAllocationRep._Details(dto.PortType, dto.Id);
  1039. if (_view.Code == 0)
  1040. {
  1041. return Ok(JsonView(true, "查询成功!", _view.Data));
  1042. }
  1043. return Ok(JsonView(false, _view.Msg));
  1044. }
  1045. /// <summary>
  1046. /// 任务分配
  1047. /// Add Or Edit
  1048. /// </summary>
  1049. /// <returns></returns>
  1050. [HttpPost]
  1051. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1052. public async Task<IActionResult> PostTaskAllocationAddOrEdit(TaskAllocationAddOrEditDto dto)
  1053. {
  1054. #region 参数验证
  1055. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1056. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1057. PageFunAuthViewBase pageFunAuthView = new();
  1058. #region 页面操作权限验证
  1059. pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1060. if (dto.Id == 0)
  1061. {
  1062. if (pageFunAuthView.AddAuth == 0) return Ok(JsonView(false, "您没有添加权限!"));
  1063. }
  1064. else if (dto.Id > 0)
  1065. {
  1066. if (pageFunAuthView.EditAuth == 0) return Ok(JsonView(false, "您没有编辑权限!"));
  1067. }
  1068. #endregion
  1069. #endregion
  1070. var _view = await _taskAllocationRep._AddOrEdit(dto);
  1071. if (_view.Code == 0)
  1072. {
  1073. if (dto.Id == 0) //添加提示任务单创建
  1074. {
  1075. string title = $"[{dto.TaskName}] 任务新建成功!";
  1076. string content = $"[{dto.TaskName}] 任务新建成功,请前往任务页面查看详情!";
  1077. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, dto.UserIds);
  1078. var userIds = dto.UserIds.Select(x => x.ToString()).ToList();
  1079. await AppNoticeLibrary.SendUserMsg_Task_ToUser(userIds, dto.DiId, title, dto.UserId);
  1080. }
  1081. return Ok(JsonView(true, "操作成功!"));
  1082. }
  1083. return Ok(JsonView(false, _view.Msg));
  1084. }
  1085. /// <summary>
  1086. /// 任务分配
  1087. /// 状态任务归属人详情
  1088. /// </summary>
  1089. /// <returns></returns>
  1090. [HttpPost]
  1091. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1092. public async Task<IActionResult> PostTaskAllocationTaskerDetails(TaskerDetailsDto dto)
  1093. {
  1094. var _view = await _taskAllocationRep._TaskerDetails(dto.Id);
  1095. if (_view.Code == 0)
  1096. {
  1097. return Ok(JsonView(true, "操作成功!", _view.Data));
  1098. }
  1099. return Ok(JsonView(false, _view.Msg));
  1100. }
  1101. /// <summary>
  1102. /// 任务分配
  1103. /// 状态任务归属人设置开始状态
  1104. /// </summary>
  1105. /// <returns></returns>
  1106. [HttpPost]
  1107. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1108. public async Task<IActionResult> PostTaskAllocationSetStartStatus(TaskerStatusDto dto)
  1109. {
  1110. var _view = await _taskAllocationRep._TaskerSetStartStatus(dto.UserId, dto.Id);
  1111. if (_view.Code == 0)
  1112. {
  1113. //发送消息
  1114. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == dto.Id).First();
  1115. if (taskData != null)
  1116. {
  1117. var taskUserIds = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.TAId == dto.Id).Select(it => it.UserId).ToList();
  1118. if (taskUserIds.Count > 0)
  1119. {
  1120. taskUserIds.Remove(dto.UserId);
  1121. }
  1122. var UserName = _taskAllocationRep._sqlSugar.Queryable<Sys_Users>().Where(it => it.Id == dto.UserId).Select(it => it.CnName).First();
  1123. string title_createUser = $"[{taskData.TaskName}] 进度更新!";
  1124. string conten_createUser = $"[{UserName}] 已开始任务,请注意该工作人员任务进度!";
  1125. //创建人发送消息
  1126. List<int> createUserIds = new() { taskData.CreateUserId };
  1127. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title_createUser, conten_createUser, createUserIds);
  1128. await AppNoticeLibrary.SendUserMsg_Task_ToUser(createUserIds.Select(x => x.ToString()).ToList(), taskData.DiId, conten_createUser, taskData.CreateUserId);
  1129. //其他人发送消息
  1130. string title = $"[{taskData.TaskName}] 进度更新!";
  1131. string content = $"[{UserName}] 已开始任务.若需查看,请前往任务页面查看详情!";
  1132. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, taskUserIds);
  1133. await AppNoticeLibrary.SendUserMsg_Task_ToUser(taskUserIds.Select(x => x.ToString()).ToList(), taskData.DiId, content, dto.UserId);
  1134. }
  1135. return Ok(JsonView(true, "操作成功!"));
  1136. }
  1137. return Ok(JsonView(false, _view.Msg));
  1138. }
  1139. /// <summary>
  1140. /// 任务分配
  1141. /// 状态 任务归属人 设置完成状态
  1142. /// </summary>
  1143. /// <returns></returns>
  1144. [HttpPost]
  1145. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1146. public async Task<IActionResult> PostTaskAllocationSetOverStatus(TaskerStatusDto dto)
  1147. {
  1148. var _view = await _taskAllocationRep._TaskerSetOverStatus(dto.UserId, dto.Id);
  1149. if (_view.Code == 0)
  1150. {
  1151. //发送消息
  1152. var taskData = _sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == dto.Id).First();
  1153. if (taskData != null)
  1154. {
  1155. var taskUserIds = _sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.TAId == dto.Id).Select(it => it.UserId).Distinct().ToList();
  1156. var UserName = _sqlSugar.Queryable<Sys_Users>().Where(it => it.Id == dto.UserId).Select(it => it.CnName).First();
  1157. string title_createUser = $"[{taskData.TaskName}] 进度更新!";
  1158. string conten_createUser = $"[{UserName}] 已完成任务,请前往任务页面进行审核操作!";
  1159. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title_createUser, conten_createUser, new List<int>() { taskData.CreateUserId }); //创建人发送消息
  1160. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskData.CreateUserId.ToString() }, taskData.DiId, conten_createUser, dto.UserId);
  1161. string title = $"[{taskData.TaskName}] 进度更新!";
  1162. string content = $"[{UserName}] 已完成任务,请注意在规定时间内完成任务.若需查看,请前往任务页面查看详情!";
  1163. string yw_content = $"[{UserName}] 已完成任务,请注意在规定时间内完成任务!";
  1164. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, taskUserIds); //其他人发送消息
  1165. await AppNoticeLibrary.SendUserMsg_Task_ToUser(taskUserIds.Select(x => x.ToString()).ToList(), taskData.DiId, yw_content, dto.UserId);
  1166. string content1 = $"任务已完成,等待任务发布人审核!若需查看,请前往任务页面查看详情!";
  1167. string yw_content1 = $"任务已完成,等待任务发布人审核!";
  1168. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content1, new List<int>() { dto.UserId }); //设置任务人 发送消息
  1169. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { dto.UserId.ToString() }, taskData.DiId, yw_content1, dto.UserId);
  1170. }
  1171. return Ok(JsonView(true, "操作成功!"));
  1172. }
  1173. return Ok(JsonView(false, _view.Msg));
  1174. }
  1175. /// <summary>
  1176. /// 任务分配
  1177. /// 状态 任务归属人 设置知晓状态
  1178. /// </summary>
  1179. /// <returns></returns>
  1180. [HttpPost]
  1181. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1182. public async Task<IActionResult> PostTaskAllocationSetHaveStatus(TaskAllocationStatusDto dto)
  1183. {
  1184. var _view = await _taskAllocationRep._TaskSetHaveStatus(dto.SubId);
  1185. if (_view.Code == 0)
  1186. {
  1187. //发送消息
  1188. var taskUserData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.Id == dto.SubId).First();
  1189. if (taskUserData != null)
  1190. {
  1191. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == taskUserData.TAId).First();
  1192. if (taskData != null)
  1193. {
  1194. var UserName = _taskAllocationRep._sqlSugar.Queryable<Sys_Users>().Where(it => it.Id == taskData.CreateUserId).Select(it => it.CnName).First();
  1195. string title = $"[{taskData.TaskName}] 进度更新!";
  1196. string conten_createUser = $"[{UserName}] 已知晓任务.若需查看,请前往任务页面查看详情!";
  1197. string qw_conten_createUser = $"[{UserName}] 已知晓任务!";
  1198. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, conten_createUser, new List<int>() { taskData.CreateUserId }); //创建人发送消息
  1199. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskData.CreateUserId.ToString() }, taskData.DiId, qw_conten_createUser, taskData.CreateUserId);
  1200. string content = $"请注意任务完成时间!若需查看,请前往任务页面查看详情!";
  1201. string yw_content = $"请注意任务完成时间!";
  1202. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, new List<int>() { taskUserData.UserId }); //设置任务人 发送消息
  1203. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskUserData.UserId.ToString() }, taskData.DiId, yw_content, taskUserData.UserId);
  1204. }
  1205. }
  1206. return Ok(JsonView(true, "操作成功!"));
  1207. }
  1208. return Ok(JsonView(false, _view.Msg));
  1209. }
  1210. /// <summary>
  1211. /// 任务分配
  1212. /// 任务发布者 单人设置审批状态
  1213. /// </summary>
  1214. /// <returns></returns>
  1215. [HttpPost]
  1216. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1217. public async Task<IActionResult> PostTaskAllocationSetAuditStatus(TaskAllocationStatusDto dto)
  1218. {
  1219. var _view = await _taskAllocationRep._TaskSetAuditStatus(dto.SubId);
  1220. if (_view.Code == 0)
  1221. {
  1222. //发送消息
  1223. var taskUserData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.Id == dto.SubId).First();
  1224. if (taskUserData != null)
  1225. {
  1226. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == taskUserData.TAId).First();
  1227. if (taskData != null)
  1228. {
  1229. string title = $"[{taskData.TaskName}] 进度更新!";
  1230. string content = $"任务已完成!若需查看,请前往任务页面查看详情!";
  1231. string yw_content = $"任务已完成!";
  1232. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, new List<int>() { taskUserData.UserId }); //设置任务人 发送消息
  1233. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskUserData.UserId.ToString() }, taskData.DiId, yw_content, taskUserData.UserId);
  1234. }
  1235. }
  1236. return Ok(JsonView(true, "操作成功!"));
  1237. }
  1238. return Ok(JsonView(false, _view.Msg));
  1239. }
  1240. /// <summary>
  1241. /// 任务分配
  1242. /// 任务发布者 单人设置未完成状态
  1243. /// </summary>
  1244. /// <returns></returns>
  1245. [HttpPost]
  1246. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1247. public async Task<IActionResult> PostTaskAllocationSetUnFinishedStatus(TaskAllocationSetUnFinishedStatusDto dto)
  1248. {
  1249. var _view = await _taskAllocationRep._TaskSetUnFinishedStatus(dto.SubId, dto.Cause);
  1250. if (_view.Code == 0)
  1251. {
  1252. //发送消息
  1253. var taskUserData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.Id == dto.SubId).First();
  1254. if (taskUserData != null)
  1255. {
  1256. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == taskUserData.TAId).First();
  1257. if (taskData != null)
  1258. {
  1259. string title = $"[{taskData.TaskName}] 进度更新!";
  1260. string content = $"任务未完成!若需查看,请前往任务页面查看详情!";
  1261. string yw_content = $"任务未完成!";
  1262. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, new List<int>() { taskUserData.UserId }); //设置任务人 发送消息
  1263. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskUserData.UserId.ToString() }, taskData.DiId, yw_content, taskUserData.UserId);
  1264. }
  1265. }
  1266. return Ok(JsonView(true, "操作成功!"));
  1267. }
  1268. return Ok(JsonView(false, _view.Msg));
  1269. }
  1270. ///// <summary>
  1271. ///// 任务分配
  1272. ///// 确认任务是否可操作完成
  1273. ///// </summary>
  1274. ///// <returns></returns>
  1275. //[HttpPost]
  1276. //[ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1277. //public async Task<IActionResult> PostTaskAllocationIsConfirmCompletion(TaskAllocationScoreDto dto)
  1278. //{
  1279. // try
  1280. // {
  1281. // #region 参数验证
  1282. // if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1283. // if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1284. // PageFunAuthViewBase pageFunAuthView = new PageFunAuthViewBase();
  1285. // #region 页面操作权限验证
  1286. // pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1287. // if (pageFunAuthView.EditAuth == 0) return Ok(JsonView(false, "您没有编辑权限!"));
  1288. // #endregion
  1289. // #endregion
  1290. // var _view = await _taskAllocationRep._TaskConfirmCompletion(dto.PortType, dto.Id);
  1291. // if (_view.Code == 0)
  1292. // {
  1293. // return Ok(JsonView(true, "操作成功!"));
  1294. // }
  1295. // return Ok(JsonView(false, _view.Msg));
  1296. // }
  1297. // catch (Exception ex)
  1298. // {
  1299. // return Ok(JsonView(false, ex.Message));
  1300. // }
  1301. //}
  1302. ///// <summary>
  1303. ///// 任务分配
  1304. ///// 任务确认完成
  1305. ///// </summary>
  1306. ///// <returns></returns>
  1307. //[HttpPost]
  1308. //[ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1309. //public async Task<IActionResult> PostTaskAllocationConfirmCompletion(TaskAllocationConfirmCompletionDto dto)
  1310. //{
  1311. // try
  1312. // {
  1313. // #region 参数验证
  1314. // if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1315. // if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1316. // PageFunAuthViewBase pageFunAuthView = new PageFunAuthViewBase();
  1317. // #region 页面操作权限验证
  1318. // pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1319. // if (pageFunAuthView.EditAuth == 0) return Ok(JsonView(false, "您没有编辑权限!"));
  1320. // #endregion
  1321. // #endregion
  1322. // var _view = await _taskAllocationRep._TaskConfirmCompletion(dto.PortType,dto.Id);
  1323. // if (_view.Code == 0)
  1324. // {
  1325. // return Ok(JsonView(true, "操作成功!"));
  1326. // }
  1327. // return Ok(JsonView(false, _view.Msg));
  1328. // }
  1329. // catch (Exception ex)
  1330. // {
  1331. // return Ok(JsonView(false, ex.Message));
  1332. // }
  1333. //}
  1334. /// <summary>
  1335. /// 任务分配
  1336. /// 任务发布者 任务评分
  1337. /// </summary>
  1338. /// <returns></returns>
  1339. [HttpPost]
  1340. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1341. public async Task<IActionResult> PostTaskAllocationScore(TaskAllocationScoreDto dto)
  1342. {
  1343. #region 参数验证
  1344. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1345. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1346. #region 页面操作权限验证
  1347. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1348. if (pageFunAuthView.EditAuth == 0) return Ok(JsonView(false, "您没有编辑权限!"));
  1349. #endregion
  1350. #endregion
  1351. var _view = await _taskAllocationRep._TaskScore(dto);
  1352. if (_view.Code == 0)
  1353. {
  1354. //发送消息
  1355. var taskUserData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.Id == dto.SubId).First();
  1356. if (taskUserData != null)
  1357. {
  1358. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == taskUserData.TAId).First();
  1359. if (taskData != null)
  1360. {
  1361. string title = $"[{taskData.TaskName}] 进度更新!";
  1362. string content = $"任务评分已完成!若需查看,请前往任务页面查看详情!";
  1363. string yw_content = $"任务评分已完成!";
  1364. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, new List<int>() { taskUserData.UserId }); //设置任务人 发送消息
  1365. await AppNoticeLibrary.SendUserMsg_Task_ToUser(new List<string>() { taskUserData.UserId.ToString() }, taskData.DiId, yw_content, taskUserData.UserId);
  1366. }
  1367. }
  1368. return Ok(JsonView(true, "操作成功!"));
  1369. }
  1370. return Ok(JsonView(false, _view.Msg));
  1371. }
  1372. /// <summary>
  1373. /// 任务分配
  1374. /// 任务发布者 任务终止
  1375. /// </summary>
  1376. /// <returns></returns>
  1377. [HttpPost]
  1378. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1379. public async Task<IActionResult> PostTaskAllocationTermination(TaskAllocationConfirmCompletionDto dto)
  1380. {
  1381. #region 参数验证
  1382. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1383. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1384. #region 页面操作权限验证
  1385. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1386. if (pageFunAuthView.EditAuth == 0) return Ok(JsonView(false, "您没有编辑权限!"));
  1387. #endregion
  1388. #endregion
  1389. var _view = await _taskAllocationRep._TaskTermination(dto.Id);
  1390. if (_view.Code == 0)
  1391. {
  1392. //发送消息
  1393. var taskData = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskAllocation>().Where(it => it.Id == dto.Id).First();
  1394. if (taskData != null)
  1395. {
  1396. var taskUserIds = _taskAllocationRep._sqlSugar.Queryable<Pm_TaskRelevanceUser>().Where(it => it.Id == dto.Id).Select(it => it.UserId).ToList();
  1397. taskUserIds.Add(taskData.CreateUserId);
  1398. string title = $"[{taskData.TaskName}] 进度更新!";
  1399. string content = $"任务已终止!若需查看,请前往任务页面查看详情!";
  1400. string yw_content = $"[{taskData.TaskName}]任务已终止!";
  1401. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.TaskProgressUpdate, title, content, taskUserIds); //设置任务人 发送消息
  1402. await AppNoticeLibrary.SendUserMsg_Task_ToUser(taskUserIds.Select(x => x.ToString()).ToList(), taskData.DiId, yw_content, taskData.CreateUserId);
  1403. }
  1404. return Ok(JsonView(true, "操作成功!"));
  1405. }
  1406. return Ok(JsonView(false, _view.Msg));
  1407. }
  1408. /// <summary>
  1409. /// 任务分配
  1410. /// 任务发布者 任务删除
  1411. /// </summary>
  1412. /// <returns></returns>
  1413. [HttpPost]
  1414. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1415. public async Task<IActionResult> PostTaskAllocationDel(TaskAllocationConfirmCompletionDto dto)
  1416. {
  1417. #region 参数验证
  1418. if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
  1419. if (dto.PageId < 1) dto.PageId = 172; //任务指派Id
  1420. #region 页面操作权限验证
  1421. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
  1422. if (pageFunAuthView.DeleteAuth == 0) return Ok(JsonView(false, "您没有删除权限!"));
  1423. #endregion
  1424. #endregion
  1425. var _view = await _taskAllocationRep._TaskDel(dto.Id);
  1426. if (_view.Code == 0)
  1427. {
  1428. return Ok(JsonView(true, "操作成功!"));
  1429. }
  1430. return Ok(JsonView(false, _view.Msg));
  1431. }
  1432. #endregion
  1433. #region 团组状态通知
  1434. // ///// <summary>
  1435. // ///// 测试
  1436. // ///// </summary>
  1437. // ///// <param name="dto"></param>
  1438. // ///// <returns></returns>
  1439. // [HttpPost]
  1440. // [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1441. // public async Task<IActionResult> Test_QIYEWX(PostTourClientListDownloadFile dto)
  1442. // {
  1443. // // //List<string> templist = new List<string>() { 234.ToString() };
  1444. // // //await AppNoticeLibrary.SendUserMsg_GroupStatus_AuditFee(14090, templist, QiyeWeChatEnum.TestChat);
  1445. // // //await AppNoticeLibrary.SendUserMsg_GroupShare_ToJob(dto.DiId); ;
  1446. // // //DeleReminderMessage.PostMessageByWebhook();
  1447. // // //GroupStatus_UserSimplelistView list = await _qiYeWeChatApiService.GroupStatus_GetUserList();
  1448. // // //创建群聊
  1449. // // //List<string> userList1 = new List<string>() { "Feint", "amy.zhu@pan-american-intl.com", "judy.zeng@pan-american-intl.com", "FuHongJin" };
  1450. // // //List<string> userList2 = new List<string>() { "Feint", "ZhaoYaQi", "LiaoWenYa" };
  1451. // List<string> userList3 = new List<string>() { "rongfeng.yuan", "zhaiyang" };
  1452. // // //GroupStatus_CreateChatView rst1 = await _qiYeWeChatApiService.GroupStatus_CreateChat("团组通知", "Feint", userList1, "CaiWuChat01");
  1453. // // //GroupStatus_CreateChatView rst2 = await _qiYeWeChatApiService.GroupStatus_CreateChat("OA通知-国交部", "Feint", userList2, "GuoJiaoLeader01");
  1454. // GroupStatus_CreateChatView rst3 = await _qiYeWeChatApiService.GroupStatus_CreateChat("OA通知-机票预算", "rongfeng.yuan", userList3, "AirCostChat01");
  1455. // // //推送消息(模板)
  1456. // // //List<string> userList = new List<string>() { "Feint", "huaju.liu", "johnny.yang@pan-american-intl.com" };
  1457. // // //List<string> userList = new List<string>() { "Feint", "johnny.yang@pan-american-intl.com" };
  1458. // // GroupStatus_CreateChatView rst1 = await _qiYeWeChatApiService.GroupStatus_CreateChat("团组费用提示", "Feint", userList, "GuoJiaoChat01");
  1459. // // //团组出发
  1460. // // //AppNoticeLibrary.SendUserMsg_GroupStatus_Create(2358, userList);
  1461. // // //费用审核
  1462. // // //AppNoticeLibrary.SendChatMsg_GroupStatus_ApplyFee(dto.DiId, QiyeWeChatEnum.TestChat);
  1463. // // //费用审核结果通知(通过情况下发送财务群)
  1464. // // //List<string> userList = new List<string>() { "234" };
  1465. // // //AppNoticeLibrary.SendUserMsg_GroupStatus_AuditFee(dto.DiId, userList, QiyeWeChatEnum.CaiWuChat02);
  1466. // // //4、财务付款时:(1)对应版块人员【单独发,状态为已付款才发】
  1467. // // //AppNoticeLibrary.SendUserMsg_GroupStatus_PayResult(dto.DiId, userList);
  1468. // // //团组提醒财务群
  1469. // // //DateTime dtNow = DateTime.Now;
  1470. // // //List<Grp_DelegationInfo> listSource = _usersRep.Query<Grp_DelegationInfo>(s => s.IsDel == 0 && s.VisitStartDate >= dtNow).Take(3).ToList();
  1471. // // //List<Grp_DelegationInfo> listAdd7day = _usersRep.Query<Grp_DelegationInfo>(s => s.IsDel == 0 && s.VisitStartDate >= dtNow).Take(3).ToList();
  1472. // // //List<Grp_DelegationInfo> listAdd3day = new List<Grp_DelegationInfo>() { };
  1473. // //机票预算群通知
  1474. // await AppNoticeLibrary.SendChatMsg_AirCostChat(dto.DiId, QiyeWeChatEnum.AirCostChat01);
  1475. // // //日付申请提醒财务群
  1476. // // //AppNoticeLibrary.DailyPayReminders_Create_ToCaiwuChat(dto.DiId, QiyeWeChatEnum.CaiWuChat02);
  1477. // // //日付申请结果推送用户、成功通知财务群
  1478. // // //AppNoticeLibrary.DailyPayReminder_Audit_ToUser(dto.DiId, userList, QiyeWeChatEnum.TestChat);
  1479. // // //AppNoticeLibrary.DailyPayReminder_Pay_ToUser(dto.DiId, userList);
  1480. // // //string q = "";
  1481. // // DeleReminderMessage.PostMessageByWebhook_CRMStatistics();
  1482. // return Ok(JsonView(true, "操作成功!"));
  1483. // }
  1484. #endregion
  1485. #region 物资进销存
  1486. /// <summary>
  1487. /// 物资进销存
  1488. /// 基础数据类型
  1489. /// </summary>
  1490. /// <returns></returns>
  1491. [HttpGet]
  1492. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1493. public async Task<IActionResult> GoodsInitDataSource()
  1494. {
  1495. return Ok(await _goodsRep.InitDataSource());
  1496. }
  1497. /// <summary>
  1498. /// 物资进销存
  1499. /// 基础数据类型 --> 团组名称列表 分页
  1500. /// </summary>
  1501. /// <returns></returns>
  1502. [HttpPost]
  1503. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1504. public async Task<IActionResult> GoodsGroupNameInit(QueryGroupListOffsetDto dto)
  1505. {
  1506. var watch = new Stopwatch();
  1507. watch.Start();
  1508. var countyDatas = await _sqlSugar
  1509. .Queryable<Grp_DelegationInfo>()
  1510. .Where((di) => di.IsDel == 0 && !string.IsNullOrWhiteSpace(di.TeamName))
  1511. .OrderBy((di) => new { id = SqlFunc.Desc(di.Id) })
  1512. .Select((di) => new { id = di.Id, name = di.TeamName })
  1513. .ToListAsync();
  1514. countyDatas.Insert(0, new { id = 0, name = "其他物资(公司内部物资)" });
  1515. countyDatas.Insert(0, new { id = -1, name = "拜访客户所使用的物资" });
  1516. countyDatas.Insert(0, new { id = -2, name = "库存调整" });
  1517. countyDatas.Insert(0, new { id = -3, name = "全部团组" });
  1518. var total = countyDatas.Count;
  1519. countyDatas = countyDatas.WhereIF(!string.IsNullOrEmpty(dto.Search), x => x.name.Contains(dto.Search)).ToList();
  1520. countyDatas = countyDatas
  1521. .Skip((dto.PageIndex - 1) * dto.PageSize)
  1522. .Take(dto.PageSize)
  1523. .ToList();
  1524. watch.Stop();
  1525. return Ok(JsonView(true, $"{MsgTips.Succeed},耗时 {watch.ElapsedMilliseconds} ms", countyDatas, total));
  1526. }
  1527. /// <summary>
  1528. /// 物资进销存
  1529. /// 物品 列表
  1530. /// </summary>
  1531. /// <returns></returns>
  1532. [HttpPost]
  1533. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1534. public async Task<IActionResult> GoodsList(GoodsListDto dto)
  1535. {
  1536. if (dto.PortType < 1 || dto.PortType > 3) return Ok(JsonView(false, MsgTips.Port));
  1537. if (dto.PageIndex < 1 || dto.PageSize < 1) return Ok(JsonView(false, MsgTips.PageIndex));
  1538. return Ok(await _goodsRep.GoodsList(dto));
  1539. }
  1540. /// <summary>
  1541. /// 物资进销存
  1542. /// 物品 详情
  1543. /// </summary>
  1544. /// <returns></returns>
  1545. [HttpGet()]
  1546. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1547. public async Task<IActionResult> GoodsInfo(int portType, int id)
  1548. {
  1549. if (portType < 1 || portType > 3) return Ok(JsonView(false, MsgTips.Port));
  1550. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  1551. return Ok(await _goodsRep.GoodsInfo(portType, id));
  1552. }
  1553. /// <summary>
  1554. /// 物资进销存
  1555. /// 物品 OP(Add OR Edit)
  1556. /// </summary>
  1557. /// <returns></returns>
  1558. [HttpPost]
  1559. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1560. public async Task<IActionResult> GoodsOP(GoodsOpDto dto)
  1561. {
  1562. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1563. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1564. var validator = new GoodsOPDTOValidator();
  1565. var validatorRes = await validator.ValidateAsync(dto);
  1566. if (!validatorRes.IsValid)
  1567. {
  1568. var sb = new StringBuilder();
  1569. foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
  1570. return Ok(JsonView(false, sb.ToString()));
  1571. }
  1572. return Ok(await _goodsRep.GoodsOp(dto, currUserInfo.UserId));
  1573. }
  1574. /// <summary>
  1575. /// 物资进销存
  1576. /// 物品 Del
  1577. /// </summary>
  1578. /// <returns></returns>
  1579. [HttpDelete("{id}")]
  1580. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1581. public async Task<IActionResult> GoodsDel(int id)
  1582. {
  1583. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  1584. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1585. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1586. return Ok(await _goodsRep.GoodsDel(id, currUserInfo.UserId));
  1587. }
  1588. /// <summary>
  1589. /// 物资进销存(审核,需传token)
  1590. /// 入库 列表
  1591. /// </summary>
  1592. /// <returns></returns>
  1593. [HttpPost]
  1594. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1595. public async Task<IActionResult> GoodsStorageList(GoodsStorageListDto dto)
  1596. {
  1597. //var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1598. //if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1599. if (dto.PortType < 1 || dto.PortType > 3) return Ok(JsonView(false, MsgTips.Port));
  1600. if (dto.PageIndex < 1 || dto.PageSize < 1) return Ok(JsonView(false, MsgTips.PageIndex));
  1601. return Ok(await _goodsRep.GoodsStorageList(dto));
  1602. //return Ok(await _goodsRep.GoodsStorageList(dto, 0));
  1603. }
  1604. /// <summary>
  1605. /// 物资进销存
  1606. /// 入库 详情
  1607. /// </summary>
  1608. /// <returns></returns>
  1609. [HttpGet("{id}")]
  1610. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1611. public async Task<IActionResult> GoodsStorageInfo([FromQuery] int portType, int id)
  1612. {
  1613. if (portType < 1 || portType > 3) return Ok(JsonView(false, MsgTips.Port));
  1614. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  1615. return Ok(await _goodsRep.GoodsStorageInfo(portType, id));
  1616. }
  1617. /// <summary>
  1618. /// 物资进销存
  1619. /// 入库 OP(Add OR Edit)
  1620. /// </summary>
  1621. /// <returns></returns>
  1622. [HttpPost]
  1623. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1624. public async Task<IActionResult> GoodsStorageOp(GoodsStorageOpDto dto)
  1625. {
  1626. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1627. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1628. var validator = new GoodsStorageOpDtoValidator();
  1629. var validatorRes = await validator.ValidateAsync(dto);
  1630. if (!validatorRes.IsValid)
  1631. {
  1632. var sb = new StringBuilder();
  1633. foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
  1634. return Ok(JsonView(false, sb.ToString()));
  1635. }
  1636. return Ok(await _goodsRep.GoodsStorageOp(dto, currUserInfo.UserId));
  1637. }
  1638. /// <summary>
  1639. /// 物资进销存
  1640. /// 入库确认状态变更
  1641. /// </summary>
  1642. /// <returns></returns>
  1643. [HttpPost]
  1644. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1645. public async Task<IActionResult> GoodsStorageConfirmStatusChange(GoodsStorageConfirmDto dto)
  1646. {
  1647. if (dto.Id < 1) return Ok(JsonView(false, MsgTips.Id));
  1648. if (!Enum.IsDefined(typeof(GoodsAuditDepEnum), (int)dto.AuditDep))
  1649. {
  1650. return Ok(JsonView(false, $"审核部门类型超出可用范围!"));
  1651. }
  1652. if (!Enum.IsDefined(typeof(GoodsConfirmEnum), (int)dto.ConfirmStatus))
  1653. {
  1654. return Ok(JsonView(false, $"入库审核状态超出可用范围!"));
  1655. }
  1656. if (dto.ConfirmStatus == GoodsConfirmEnum.WaitConfirm || dto.ConfirmStatus == GoodsConfirmEnum.PartConfirmed)
  1657. {
  1658. return Ok(JsonView(false, $"入库审核状态(待确认、部分确认)不可用!"));
  1659. }
  1660. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1661. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1662. return Ok(await _goodsRep.GoodsStorageConfirmStatusChange(dto, currUserInfo.UserId));
  1663. }
  1664. /// <summary>
  1665. /// 物资进销存
  1666. /// 入库 Del
  1667. /// </summary>
  1668. /// <returns></returns>
  1669. [HttpDelete("{id}")]
  1670. //[Authorize]
  1671. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1672. public async Task<IActionResult> GoodsStorageDel(int id)
  1673. {
  1674. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1675. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1676. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  1677. return Ok(await _goodsRep.GoodsStorageDel(id, currUserInfo.UserId));
  1678. }
  1679. /// <summary>
  1680. /// 物资进销存
  1681. /// 入库 excelDownload
  1682. /// </summary>
  1683. /// <returns></returns>
  1684. [HttpPost]
  1685. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1686. public async Task<IActionResult> GoodsStorageExcelDownload()
  1687. {
  1688. //token验证
  1689. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1690. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1691. //文件下载权限验证
  1692. int userId = currUserInfo.UserId,
  1693. pageId = 191;
  1694. #region 页面操作权限验证
  1695. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(userId, pageId);
  1696. if (pageFunAuthView.FilesDownloadAuth == 0) return Ok(JsonView(false, "您未分配文件下载权限!"));
  1697. #endregion
  1698. return Ok(await _goodsRep.GoodsStorageExcelDownload());
  1699. }
  1700. /// <summary>
  1701. /// 物资进销存
  1702. /// 领用记录 List
  1703. /// </summary>
  1704. /// <returns></returns>
  1705. [HttpPost]
  1706. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1707. public async Task<IActionResult> GoodsReceiveList(GoodsReceiveListDTO dto)
  1708. {
  1709. //token验证
  1710. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1711. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1712. if (dto.PortType < 1 || dto.PortType > 3) return Ok(JsonView(false, MsgTips.Port));
  1713. if (dto.PageIndex < 1 || dto.PageSize < 1) return Ok(JsonView(false, MsgTips.PageIndex));
  1714. //文件下载权限验证
  1715. int userId = currUserInfo.UserId,
  1716. pageId = 191;
  1717. if (dto.IsExcelDownload)
  1718. {
  1719. if (userId < 1) return Ok(JsonView(false, "excel导出时,需传入正确的当前操作人UserId!"));
  1720. ;
  1721. #region 页面操作权限验证
  1722. PageFunAuthViewBase pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(userId, pageId);
  1723. if (pageFunAuthView.FilesDownloadAuth == 0) return Ok(JsonView(false, "您未分配文件下载权限!"));
  1724. #endregion
  1725. }
  1726. dto.CurrUserId = currUserInfo.UserId;
  1727. return Ok(await _goodsRep.GoodsReceiveList(dto));
  1728. }
  1729. /// <summary>
  1730. /// 物资进销存
  1731. /// 领用 审核 List
  1732. /// </summary>
  1733. /// <returns></returns>
  1734. [HttpPost]
  1735. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1736. public async Task<IActionResult> GoodsReceiveAuditList(GoodsReceiveAuditListDTO dto)
  1737. {
  1738. //token验证
  1739. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1740. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1741. if (dto.PortType < 1 || dto.PortType > 3) return Ok(JsonView(false, MsgTips.Port));
  1742. if (dto.PageIndex < 1 || dto.PageSize < 1) return Ok(JsonView(false, MsgTips.PageIndex));
  1743. dto.CurrUserId = currUserInfo.UserId;
  1744. return Ok(await _goodsRep.GoodsReceiveAuditList(dto));
  1745. }
  1746. /// <summary>
  1747. /// 物资进销存
  1748. /// 领用详情
  1749. /// </summary>
  1750. /// <returns></returns>
  1751. [HttpGet("{id}")]
  1752. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1753. public async Task<IActionResult> GoodsReceiveInfo([FromQuery] int portType, int id)
  1754. {
  1755. if (portType < 1 || portType > 3) return Ok(JsonView(false, MsgTips.Port));
  1756. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  1757. return Ok(await _goodsRep.GoodsReceiveInfo(portType, id));
  1758. }
  1759. /// <summary>
  1760. /// 物资进销存
  1761. /// 领用 OP
  1762. /// </summary>
  1763. /// <returns></returns>
  1764. [HttpPost]
  1765. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1766. public async Task<IActionResult> GoodsReceiveOP(GoodsReceiveOpDto dto)
  1767. {
  1768. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1769. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1770. var validator = new GoodsReceiveOpDtoValidator();
  1771. var validatorRes = await validator.ValidateAsync(dto);
  1772. if (!validatorRes.IsValid)
  1773. {
  1774. var sb = new StringBuilder();
  1775. foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
  1776. return Ok(JsonView(false, sb.ToString()));
  1777. }
  1778. //Return Ok(await _goodsRep.GoodsReceiveOp(dto, currUserInfo.UserId));
  1779. //TODO:调试完成后 单个领用使用批量领用方法
  1780. var receiveDetails = new GoodsReceiveDetailsView[] {
  1781. new () {
  1782. Id = 0,
  1783. GoodsId = dto.GoodsId,
  1784. Quantity = dto.Quantity,
  1785. Remark = dto.Remark
  1786. }
  1787. };
  1788. var newDto = new GoodsReceiveBatchOpDto()
  1789. {
  1790. Id = dto.Id,
  1791. GroupId = dto.GroupId,
  1792. ReceiveDetails = receiveDetails,
  1793. Reason = dto.Reason,
  1794. Remark = dto.Remark,
  1795. IsReplace = dto.IsReplace,
  1796. CurrUserId = currUserInfo.UserId,
  1797. };
  1798. var res = await _goodsRep.GoodsReceiveBatchOpAsync(newDto);
  1799. //企业微信消息通知
  1800. if (res.Code == StatusCodes.Status200OK && dto.Id < 1)
  1801. {
  1802. var signProperty = res.Data?.GetType().GetProperty("sign");
  1803. int sign = signProperty != null && signProperty.GetValue(res.Data, null) is int value ? value : 0;
  1804. //物资领用通知
  1805. await AppNoticeLibrary.SendUserMsg_CompanyShare_ToHR(sign, dto.GroupId, currUserInfo.UserId);
  1806. }
  1807. return Ok(res);
  1808. }
  1809. /// <summary>
  1810. /// 物资进销存
  1811. /// 领用 审核
  1812. /// </summary>
  1813. /// <param name="dto"></param>
  1814. /// <returns></returns>
  1815. [HttpPost]
  1816. [ApiExplorerSettings(IgnoreApi = true)]
  1817. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1818. public async Task<IActionResult> GoodsReceiveAudit(GoodsReceiveAuditDTO dto)
  1819. {
  1820. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1821. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1822. var validator = new GoodsReceiveAuditDTOValidator();
  1823. var validatorRes = await validator.ValidateAsync(dto);
  1824. if (!validatorRes.IsValid)
  1825. {
  1826. var sb = new StringBuilder();
  1827. foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
  1828. return Ok(JsonView(false, sb.ToString()));
  1829. }
  1830. int[] idArray = dto.Label
  1831. .Split(',')
  1832. .Select(x =>
  1833. {
  1834. if (int.TryParse(x, out var id)) return id;
  1835. return id;
  1836. })
  1837. .ToArray();
  1838. var view = await _goodsRep.GoodsReceiveAudit(idArray, currUserInfo.UserId, dto.AuditEnum);
  1839. //var view = new JsonView() { Code = StatusCodes.Status200OK};
  1840. //TODO:出库成功 并且是团组相关物资 向团组其他款项添加信息
  1841. #region 出库成功 && 不需要归还的物资(IsReplace == false) && 团组相关物资 向团组其他款项添加信息
  1842. if (view.Code != StatusCodes.Status200OK) return Ok(view);
  1843. if (idArray.Length < 1) return Ok(view);
  1844. int receiveId = idArray[0];
  1845. var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveId);
  1846. if (receiveInfo == null) return Ok(view);
  1847. if (receiveInfo.IsReplace)
  1848. {
  1849. view.Msg += $"\r\n 需要归还的物资不向团组其他款项添加信息!";
  1850. return Ok(view);
  1851. }
  1852. var auditEnums = new List<GoodsAuditEnum>() { GoodsAuditEnum.OutConfirmed, GoodsAuditEnum.OutRejected };
  1853. if (!auditEnums.Contains(receiveInfo.AuditStatus)) return Ok(view);
  1854. var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveInfo.GroupId);
  1855. if (groupInfo == null) return Ok(view);
  1856. var basicData = await _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && x.STid == 91).ToListAsync();
  1857. var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveInfo.GoodsId);
  1858. if (goodsInfo == null) return Ok(view);
  1859. var basicInfo = basicData.FirstOrDefault(x => x.Name.Equals(goodsInfo.Name));
  1860. if (basicInfo == null) return Ok(view);
  1861. string priceName = basicInfo.Name;
  1862. _ = decimal.TryParse(basicInfo.Remark, out decimal price);
  1863. decimal total = price * receiveInfo.Quantity;
  1864. var requestData = new DecreasePaymentsOpDto()
  1865. {
  1866. Status = 1,
  1867. DiId = groupInfo.Id,
  1868. PriceName = priceName,
  1869. Price = price,
  1870. Quantity = receiveInfo.Quantity,
  1871. FeeTotal = total,
  1872. Currency = 836,
  1873. FilePath = "",
  1874. OrbitalPrivateTransfer = 0,
  1875. OTAOrderNo = "-",
  1876. OtherBankName = "-",
  1877. OtherSideName = "-",
  1878. OtherSideNo = "-",
  1879. PayDId = 105,
  1880. SupplierAddress = "-",
  1881. SupplierArea = 1,
  1882. SupplierContact = "-",
  1883. SupplierContactNumber = "-",
  1884. SupplierEmail = "-",
  1885. SupplierName = "-",
  1886. SupplierSocialAccount = "-",
  1887. SupplierTypeId = 0,
  1888. CreateUserId = receiveInfo.CreateUserId,
  1889. Remark = $"物资领用模块添加!!"
  1890. };
  1891. //其他费用
  1892. #region 调用方法
  1893. JsonView groupData = await _otherPaymentRep.OpDecreasePayments(requestData);
  1894. if (groupData.Code != 200)
  1895. {
  1896. view.Msg += groupData.Msg;
  1897. return Ok(view);
  1898. }
  1899. #region 应用推送
  1900. int diId = requestData.DiId, status = requestData.Status;
  1901. int otherId = Convert.ToInt32(groupData.Data.GetType().GetProperty("dataId").GetValue(groupData.Data, null) ?? 0);
  1902. int ccpId = Convert.ToInt32(groupData.Data.GetType().GetProperty("ccpId").GetValue(groupData.Data, null) ?? 0);
  1903. int sign = Convert.ToInt32(groupData.Data.GetType().GetProperty("sign").GetValue(groupData.Data, null) ?? 0);
  1904. //自动审核
  1905. var autoAdit = await _feeAuditRep.FeeAutomaticAudit(3, diId, otherId);
  1906. await AppNoticeLibrary.SendChatMsg_GroupStatus_ApplyFee(ccpId, sign, QiyeWeChatEnum.GuoJiaoLeaderChat);
  1907. //2024-10-21 新增LZ UID
  1908. var userIds = new List<int>() { 208 };
  1909. //var userIds = new List<int>() { 21 };
  1910. string title = $"系统通知";
  1911. string content = "";
  1912. var ccpInfo = await _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.Id == ccpId).FirstAsync();
  1913. if (status == 1) content = $"[新增-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{ccpInfo.PayMoney * ccpInfo.DayRate:#0.00} CNY;";
  1914. else if (status == 2) content = $"[更新-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{ccpInfo.PayMoney * ccpInfo.DayRate:#0.00} CNY;";
  1915. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.GroupBusinessOperations, title, content, userIds, diId);
  1916. //await APNsTools.iOS_PushNotifications1("051", $"其他款项费用审核", "", content);
  1917. #endregion
  1918. #endregion
  1919. #endregion
  1920. return Ok(view);
  1921. }
  1922. /// <summary>
  1923. /// 物资进销存
  1924. /// 领用 List(含批量)
  1925. /// </summary>
  1926. /// <returns></returns>
  1927. [HttpPost]
  1928. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1929. public async Task<IActionResult> GoodsReceiveBatchList(GoodsReceiveBatchListDto dto)
  1930. {
  1931. var currUserId = dto.CurrUserId;
  1932. var userInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.IsDel == 0 && x.Id == currUserId);
  1933. if (userInfo == null)
  1934. {
  1935. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1936. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1937. dto.CurrUserId = currUserInfo.UserId;
  1938. }
  1939. return Ok(await _goodsRep.GoodsReceiveBatchListAsync(dto));
  1940. }
  1941. /// <summary>
  1942. /// 物资进销存
  1943. /// 领用 OP 批量领用
  1944. /// </summary>
  1945. /// <returns></returns>
  1946. [HttpPost]
  1947. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1948. public async Task<IActionResult> GoodsReceiveBatchOp(GoodsReceiveBatchOpDto dto)
  1949. {
  1950. var currUserId = dto.CurrUserId;
  1951. var userInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.IsDel == 0 && x.Id == currUserId);
  1952. if (userInfo == null)
  1953. {
  1954. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  1955. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  1956. dto.CurrUserId = currUserInfo.UserId;
  1957. }
  1958. //参数验证
  1959. if (!dto.ReceiveDetails.Any()) Ok(JsonView(false, "请传入领用明细!"));
  1960. int index = 1;
  1961. foreach (var item in dto.ReceiveDetails)
  1962. {
  1963. //物品验证
  1964. if (item.GoodsId < 1) return Ok(JsonView(false, $"第{index}项物品无效!"));
  1965. //数量验证
  1966. if (item.Quantity <= 0.00M) return Ok(JsonView(false, $"第{index}项物品的数量无效!"));
  1967. index++;
  1968. }
  1969. var res = await _goodsRep.GoodsReceiveBatchOpAsync(dto);
  1970. //企业微信消息通知
  1971. if (res.Code == StatusCodes.Status200OK && dto.Id < 1)
  1972. {
  1973. var signProperty = res.Data?.GetType().GetProperty("sign");
  1974. int sign = signProperty != null && signProperty.GetValue(res.Data, null) is int value ? value : 0;
  1975. //物资领用通知
  1976. await AppNoticeLibrary.SendUserMsg_CompanyShare_ToHR(sign, dto.GroupId, dto.CurrUserId);
  1977. }
  1978. return Ok(res);
  1979. }
  1980. /// <summary>
  1981. /// 物资进销存
  1982. /// 领用 详情(含批量)
  1983. /// </summary>
  1984. /// <param name="id">id</param>
  1985. /// <returns></returns>
  1986. [HttpGet("{id}")]
  1987. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  1988. public async Task<IActionResult> GoodsReceiveBatchInfo(int id)
  1989. {
  1990. return Ok(await _goodsRep.GoodsReceiveBatchInfoAsync(id));
  1991. }
  1992. /// <summary>
  1993. /// 物资进销存
  1994. /// 领用 审核 (含批量)
  1995. /// </summary>
  1996. /// <param name="dto"></param>
  1997. /// <returns></returns>
  1998. [HttpPost]
  1999. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  2000. public async Task<IActionResult> GoodsReceiveAuditNew(GoodsReceiveAuditDTO dto)
  2001. {
  2002. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  2003. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  2004. var validator = new GoodsReceiveAuditDTOValidator();
  2005. var validatorRes = await validator.ValidateAsync(dto);
  2006. if (!validatorRes.IsValid)
  2007. {
  2008. var sb = new StringBuilder();
  2009. foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
  2010. return Ok(JsonView(false, sb.ToString()));
  2011. }
  2012. int[] idArray = dto.Label
  2013. .Split(',')
  2014. .Select(x =>
  2015. {
  2016. if (int.TryParse(x, out var id)) return id;
  2017. return id;
  2018. })
  2019. .ToArray();
  2020. if (idArray.Length < 1) return Ok(JsonView(false, "请传入有效的领用ID"));
  2021. int receiveId = idArray[0];
  2022. var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveId);
  2023. if (receiveInfo == null) return Ok(JsonView(false, "请传入有效的领用ID"));
  2024. var view = new JsonView();
  2025. if (dto.AuditEnum == GoodsAuditEnum.Approved) //审核通过
  2026. {
  2027. view = await _goodsRep.GoodsReceiveApproveAsync(receiveId, currUserInfo.UserId);
  2028. }
  2029. else if (dto.AuditEnum == GoodsAuditEnum.UnApproved) //审核拒绝
  2030. {
  2031. view = await _goodsRep.GoodsReceiveRejectAsync(receiveId, currUserInfo.UserId);
  2032. }
  2033. if (view.Code != StatusCodes.Status200OK) return Ok(view);
  2034. receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveId);
  2035. var auditEnums = new List<GoodsAuditEnum>() { GoodsAuditEnum.OutConfirmed, GoodsAuditEnum.OutRejected };
  2036. if (receiveInfo.AuditStatus == GoodsAuditEnum.OutConfirming)
  2037. {
  2038. //物资领用通知
  2039. await AppNoticeLibrary.SendUserMsg_CompanyShare_ToHR(receiveId, receiveInfo.GroupId, receiveInfo.CreateUserId);
  2040. }
  2041. #region 出库成功 && 不需要归还的物资(IsReplace == false) && 团组相关物资 向团组其他款项添加信息
  2042. //if (!auditEnums.Contains(receiveInfo.AuditStatus)) return Ok(view);
  2043. if (receiveInfo.IsReplace)
  2044. {
  2045. view.Msg += $"\r\n 需要归还的物资不向团组其他款项添加信息!";
  2046. return Ok(view);
  2047. }
  2048. var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveInfo.GroupId);
  2049. if (groupInfo == null) return Ok(view);
  2050. var basicData = await _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && x.STid == 91).ToListAsync();
  2051. var receiveDetails = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
  2052. .Where(x => x.IsDel == 0 && x.GoodsReceiveId == receiveInfo.Id)
  2053. .ToListAsync();
  2054. if (!receiveDetails.Any()) return Ok(view);
  2055. var goodsIds = receiveDetails.Select(y => y.GoodsId).ToList();
  2056. var goodsInfos = await _sqlSugar.Queryable<Pm_GoodsInfo>()
  2057. .Where(x => x.IsDel == 0 && goodsIds.Contains(x.Id))
  2058. .ToListAsync();
  2059. if (!goodsInfos.Any()) return Ok(view);
  2060. string priceName = string.Join("、", goodsInfos.Select(x => x.Name).ToList());
  2061. //物品价格 按照物品批次单价计算
  2062. var goodsPriceDetails = new StringBuilder();
  2063. decimal price = 0.00M; //物品累计价格
  2064. var goodsStorages = await _sqlSugar.Queryable<Pm_GoodsStorage>().Where(x => x.IsDel == 0 && goodsIds.Contains(x.GoodsId)).ToListAsync();
  2065. foreach (var item in receiveDetails)
  2066. {
  2067. List<GoodsReceiveLinkStorageView> storageFlows = new();
  2068. if (!string.IsNullOrEmpty(item.GoodsStorageInfo))
  2069. {
  2070. storageFlows = JsonConvert.DeserializeObject<List<GoodsReceiveLinkStorageView>>(item.GoodsStorageInfo);
  2071. }
  2072. if (storageFlows.Any())
  2073. {
  2074. storageFlows.ForEach(storage =>
  2075. {
  2076. price += goodsStorages.FirstOrDefault(x => x.Id == storage.StorageId)?.UnitPrice ?? 0m * storage.Quantity;
  2077. });
  2078. }
  2079. }
  2080. decimal quantity = 1m;
  2081. var total = price * quantity;
  2082. string remark = $"物资领用模块添加!需核对领用物品价格!!!";
  2083. if (!string.IsNullOrEmpty(receiveInfo.Remark)) remark = $"{receiveInfo.Remark}\n物资领用模块添加!需核对领用物品价格!!!";
  2084. var requestData = new DecreasePaymentsOpDto()
  2085. {
  2086. Status = 1,
  2087. DiId = groupInfo.Id,
  2088. PriceName = priceName,
  2089. Price = price,
  2090. Quantity = quantity,
  2091. FeeTotal = total,
  2092. Currency = 836,
  2093. FilePath = "",
  2094. OrbitalPrivateTransfer = 0,
  2095. OTAOrderNo = "-",
  2096. OtherBankName = "-",
  2097. OtherSideName = "-",
  2098. OtherSideNo = "-",
  2099. PayDId = 105,
  2100. SupplierAddress = "-",
  2101. SupplierArea = 1,
  2102. SupplierContact = "-",
  2103. SupplierContactNumber = "-",
  2104. SupplierEmail = "-",
  2105. SupplierName = "-",
  2106. SupplierSocialAccount = "-",
  2107. SupplierTypeId = 0,
  2108. CreateUserId = receiveInfo.CreateUserId,
  2109. Remark = remark
  2110. };
  2111. //1 2590 √
  2112. //2 2737 √ √
  2113. //3 2760 √ √
  2114. //4 2761 √ √
  2115. //5 2788 √ √
  2116. //6 2796 √ √
  2117. //7 2809 √ √
  2118. //8 2833 √ √
  2119. //9 2834 √ √
  2120. //10 2839 √ √
  2121. //11 2846 √ √
  2122. //其他费用
  2123. #region 调用方法
  2124. JsonView groupData = await _otherPaymentRep.OpDecreasePayments(requestData);
  2125. if (groupData.Code != 200)
  2126. {
  2127. view.Msg += groupData.Msg;
  2128. return Ok(view);
  2129. }
  2130. #region 应用推送
  2131. int diId = requestData.DiId, status = requestData.Status;
  2132. int otherId = Convert.ToInt32(groupData.Data.GetType().GetProperty("dataId").GetValue(groupData.Data, null) ?? 0);
  2133. int ccpId = Convert.ToInt32(groupData.Data.GetType().GetProperty("ccpId").GetValue(groupData.Data, null) ?? 0);
  2134. int sign = Convert.ToInt32(groupData.Data.GetType().GetProperty("sign").GetValue(groupData.Data, null) ?? 0);
  2135. //自动审核
  2136. //var autoAdit = await _feeAuditRep.FeeAutomaticAudit(3, diId, otherId);
  2137. await AppNoticeLibrary.SendChatMsg_GroupStatus_ApplyFee(ccpId, sign, QiyeWeChatEnum.GuoJiaoLeaderChat);
  2138. //2024-10-21 新增LZ UID
  2139. var userIds = new List<int>() { 208 };
  2140. //var userIds = new List<int>() { 21 };
  2141. string title = $"系统通知";
  2142. string content = "";
  2143. var ccpInfo = await _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.Id == ccpId).FirstAsync();
  2144. if (status == 1) content = $"[新增-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{(ccpInfo.PayMoney * ccpInfo.DayRate).ToString("#0.00")} CNY;";
  2145. else if (status == 2) content = $"[更新-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{(ccpInfo.PayMoney * ccpInfo.DayRate).ToString("#0.00")} CNY;";
  2146. await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.GroupBusinessOperations, title, content, userIds, diId);
  2147. //await APNsTools.iOS_PushNotifications1("051", $"其他款项费用审核", "", content);
  2148. #endregion
  2149. #endregion
  2150. #endregion
  2151. return Ok(view);
  2152. }
  2153. /// <summary>
  2154. /// 物资进销存
  2155. /// 领用 Del
  2156. /// </summary>
  2157. /// <returns></returns>
  2158. [HttpDelete("{id}")]
  2159. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  2160. public async Task<IActionResult> GoodsReceiveDel(int id)
  2161. {
  2162. var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
  2163. if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
  2164. if (id < 1) return Ok(JsonView(false, MsgTips.Id));
  2165. return Ok(await _goodsRep.GoodsReceiveDel(id, currUserInfo.UserId));
  2166. }
  2167. #endregion
  2168. #region 员工绩效
  2169. /// <summary>
  2170. /// 员工绩效组成结构获取
  2171. /// </summary>
  2172. /// <param name="userid"></param>
  2173. /// <param name="date"></param>
  2174. /// <param name="loginUser"></param>
  2175. /// <returns></returns>
  2176. [HttpGet]
  2177. public IActionResult GetPerformanceList(int userid, string date, int loginUser)
  2178. {
  2179. var jw = JsonView(false);
  2180. if (!DateTime.TryParse(date, out DateTime date_Dt))
  2181. {
  2182. jw.Msg = "日期格式有误!";
  2183. return Ok(jw);
  2184. }
  2185. string sql_CTE = $@"-- 定义递归查询的CTE
  2186. WITH PerAssessmentSettingsCTE AS (
  2187. -- 选择指定ID的记录作为起点
  2188. SELECT
  2189. pac.Id,
  2190. pac.Name,
  2191. pac.AssessmentProportion,
  2192. pac.AssessmentStandard,
  2193. pac.ParentId,
  2194. 1 AS Depth
  2195. FROM
  2196. Per_AssessmentSetting pac
  2197. INNER JOIN
  2198. Per_AssessmentContentSetting pacs
  2199. ON
  2200. pac.id = pacs.assessmentSettingid AND pacs.isdel = 0
  2201. WHERE
  2202. pacs.userid = {userid}
  2203. AND
  2204. pac.isdel = 0
  2205. UNION ALL
  2206. -- 递归部分,选择所有子级记录
  2207. SELECT
  2208. ps.Id,
  2209. ps.Name,
  2210. ps.AssessmentProportion,
  2211. ps.AssessmentStandard,
  2212. ps.ParentId,
  2213. CAST(caste.Depth as int) + 1
  2214. FROM
  2215. Per_AssessmentSetting ps
  2216. INNER JOIN PerAssessmentSettingsCTE caste ON ps.Id = caste.ParentId)
  2217. -- 从CTE中选择最终结果
  2218. SELECT * FROM PerAssessmentSettingsCTE
  2219. OPTION (MAXRECURSION 0); -- 允许无限递归 ";
  2220. var result_CTE = _sqlSugar.Ado.SqlQuery<Per_AssessmentSetting>(sql_CTE);
  2221. var ids = result_CTE.Select(x => x.Id);
  2222. var List = _sqlSugar.Queryable<Per_AssessmentSetting>()
  2223. .LeftJoin<Per_AssessmentContentSetting>((a, b) => a.Id == b.AssessmentSettingId && b.IsDel == 0 && b.UserId == userid)
  2224. .LeftJoin<Per_AssessmentScore>((a, b, c) => b.Id == c.AssessmentContentSettingId && c.IsDel == 0 && c.YearMonth.Year == date_Dt.Year && c.YearMonth.Month == date_Dt.Month)
  2225. .Where((a, b) => a.IsDel == 0 && ids.Contains(a.Id))
  2226. .Select((a, b, c) => new TreeNode
  2227. {
  2228. Id = a.Id,
  2229. ContentId = b.Id,
  2230. Name = a.Name,
  2231. ParentId = a.ParentId,
  2232. AssessmentProportion = a.AssessmentProportion, //占比
  2233. AssessmentStandard = a.AssessmentStandard, //描述
  2234. AssessmentProportionChi = b.AssessmentProportionChi, //占比
  2235. UserId = b.UserId,
  2236. JobId = b.JobId,
  2237. AssessmentSettingId = b.AssessmentSettingId,
  2238. Fixed = b.Fixed,
  2239. TargetValue = b.TargetValue,
  2240. AssessmentProportion_Percentage = a.AssessmentProportion * 100,
  2241. HigherUpAssessment = c.HigherUpAssessment,
  2242. HigherUpConfig = c.HigherUpConfig,
  2243. HigherUpUserId = c.HigherUpUserId,
  2244. Score = c.Score,
  2245. ScoreTotal = c.ScoreTotal,
  2246. SelfAssessment = c.SelfAssessment,
  2247. Status = c.Status,
  2248. YearMonth = c.YearMonth,
  2249. })
  2250. .ToList();
  2251. var rootNodeList = List.Where(x => x.ParentId == 0);
  2252. var rootResult = rootNodeList.Select(x => BuildSubTree(x, List));
  2253. jw.Data = new
  2254. {
  2255. Root = rootResult,
  2256. IsLeader = IsLeader(userid, loginUser)
  2257. };
  2258. jw.Code = 200;
  2259. jw.Msg = "成功";
  2260. return Ok(jw);
  2261. }
  2262. private static TreeNode BuildSubTree(TreeNode parent, List<TreeNode> nodes)
  2263. {
  2264. var children = nodes
  2265. .Where(n => n.ParentId == parent.Id)
  2266. .Select(n => BuildSubTree(n, nodes))
  2267. .ToList();
  2268. parent.Children = children;
  2269. return parent;
  2270. }
  2271. /// <summary>
  2272. /// 绩效项增改
  2273. /// </summary>
  2274. /// <param name="dto"></param>
  2275. /// <returns></returns>
  2276. [HttpPost]
  2277. public async Task<IActionResult> AssessmentSettingOperationAsync(PerAssessmentSettingOperationDto dto)
  2278. {
  2279. var jw = JsonView(false);
  2280. if (!ModelState.IsValid)
  2281. {
  2282. jw.Msg = "参数错误";
  2283. jw.Data = ModelState;
  2284. return Ok(jw);
  2285. }
  2286. try
  2287. {
  2288. if (dto.ParentId != 0)
  2289. {
  2290. var parent = await _sqlSugar.Queryable<Per_AssessmentSetting>().FirstAsync(x => x.IsDel == 0 && x.Id == dto.ParentId);
  2291. if (parent == null)
  2292. {
  2293. jw.Msg = "父级节点不存在";
  2294. return Ok(jw);
  2295. }
  2296. }
  2297. var entity = new Per_AssessmentSetting
  2298. {
  2299. Name = dto.Name,
  2300. AssessmentProportion = dto.AssessmentProportion,
  2301. AssessmentStandard = dto.AssessmentStandard,
  2302. ParentId = dto.ParentId,
  2303. Id = dto.Id,
  2304. Remark = dto.Remark,
  2305. };
  2306. jw.Code = 200;
  2307. if (dto.Id == 0)
  2308. {
  2309. entity.CreateUserId = dto.CreateId;
  2310. entity.CreateTime = DateTime.Now;
  2311. await _sqlSugar.Insertable(entity).ExecuteCommandAsync();
  2312. jw.Msg = "添加成功!";
  2313. }
  2314. else
  2315. {
  2316. await _sqlSugar.Updateable(entity).ExecuteCommandAsync();
  2317. jw.Msg = "修改成功!";
  2318. }
  2319. }
  2320. catch (Exception ex)
  2321. {
  2322. jw.Msg = "Api error " + ex.Message;
  2323. jw.Code = 400;
  2324. }
  2325. return Ok(jw);
  2326. }
  2327. /// <summary>
  2328. /// 绩效内容增改
  2329. /// </summary>
  2330. /// <param name="dto"></param>
  2331. /// <returns></returns>
  2332. [HttpPost]
  2333. public IActionResult AssessmentSettingOperationContentAsync(AssessmentSettingOperationContenDto dto)
  2334. {
  2335. var jw = JsonView(false, "", "");
  2336. var entity = new Per_AssessmentContentSetting
  2337. {
  2338. AssessmentProportionChi = dto.AssessmentProportionChi,
  2339. AssessmentSettingId = dto.AssessmentSettingId,
  2340. CreateTime = DateTime.Now,
  2341. CreateUserId = dto.CreateUserId,
  2342. Fixed = dto.Fixed,
  2343. Id = dto.Id,
  2344. JobId = dto.JobId,
  2345. TargetValue = dto.TargetValue,
  2346. UserId = dto.UserId,
  2347. Remark = dto.Remark,
  2348. };
  2349. var entity_Fk = _sqlSugar.Queryable<Per_AssessmentSetting>().First(x => x.Id == dto.AssessmentSettingId && x.IsDel == 0);
  2350. if (entity_Fk == null)
  2351. {
  2352. jw.Msg = "考核设置不存在";
  2353. return Ok(jw);
  2354. }
  2355. try
  2356. {
  2357. if (dto.Id == 0)
  2358. {
  2359. //add
  2360. var insertCount = _sqlSugar.Insertable(entity).ExecuteCommand();
  2361. jw.Msg = "添加成功!";
  2362. }
  2363. else
  2364. {
  2365. //update
  2366. var updateCount = _sqlSugar.Updateable(entity).ExecuteCommand();
  2367. jw.Msg = "修改成功!";
  2368. }
  2369. jw.Code = 200;
  2370. }
  2371. catch (Exception ex)
  2372. {
  2373. jw.Msg = "Api error " + ex.Message;
  2374. jw.Code = 400;
  2375. }
  2376. return Ok(jw);
  2377. }
  2378. /// <summary>
  2379. /// 绩效项查询
  2380. /// </summary>
  2381. /// <param name="dto"></param>
  2382. /// <returns></returns>
  2383. [HttpPost]
  2384. public async Task<IActionResult> QueryAssessmentSettingListOffsetAsync(QueryAssessmentSettingListOffsetAsyncDto dto)
  2385. {
  2386. var jw = JsonView(false);
  2387. RefAsync<int> total = 0;//REF和OUT不支持异步,想要真的异步这是最优解
  2388. var entities = await _sqlSugar.Queryable<Per_AssessmentSetting>()
  2389. .Where(x => x.IsDel == 0)
  2390. .WhereIF(!string.IsNullOrEmpty(dto.SearchValue), e => e.Name.Contains(dto.SearchValue))
  2391. .ToPageListAsync(dto.pageIndex, dto.pageSize, total);
  2392. var DtoResult = entities.Select(e => new
  2393. {
  2394. e.Id,
  2395. e.Name,
  2396. e.AssessmentProportion,
  2397. e.AssessmentStandard,
  2398. e.ParentId,
  2399. e.Remark
  2400. }).ToList();
  2401. jw.Data = new
  2402. {
  2403. total = total.Value,
  2404. dto.pageIndex,
  2405. dto.pageSize,
  2406. List = DtoResult
  2407. };
  2408. jw.Code = 200;
  2409. jw.Msg = "查询成功!";
  2410. return Ok(jw);
  2411. }
  2412. /// <summary>
  2413. /// 绩效分数保存
  2414. /// </summary>
  2415. /// <param name="dto"></param>
  2416. /// <returns></returns>
  2417. [HttpPost]
  2418. public IActionResult SaveUserAssessmen(SaveUserAssessmenDto dto)
  2419. {
  2420. var jw = JsonView(false, "请传入正确的数据!");
  2421. if (dto.Data.Any())
  2422. {
  2423. if (!DateTime.TryParse(dto.AssessmenData, out DateTime yearMonth_Dt))
  2424. {
  2425. jw.Data = "月份参数有误!";
  2426. return Ok(jw);
  2427. }
  2428. try
  2429. {
  2430. var ids = dto.Data.Select(x => x.AssessmentContentSettingId).ToList();
  2431. var QueryContent_DB = _sqlSugar.Queryable<Per_AssessmentContentSetting>()
  2432. .InnerJoin<Per_AssessmentSetting>((a, b) => b.IsDel == 0 && a.AssessmentSettingId == b.Id)
  2433. .Where((a, b) => a.IsDel == 0 && ids.Contains(a.Id))
  2434. .Select((a, b) => new
  2435. {
  2436. ContentSettingId = a.Id,
  2437. SettingId = b.Id,
  2438. a.TargetValue,
  2439. b.AssessmentStandard,
  2440. MergeStr = $"【项名称:{b.Name}/目标值:{a.TargetValue}/评估标准:{b.AssessmentStandard}】",
  2441. a.AssessmentProportionChi,
  2442. b.Name
  2443. })
  2444. .ToList()
  2445. .ToDictionary(x => x.ContentSettingId);
  2446. //删除上级未确认数据
  2447. var expressionWhere = Expressionable
  2448. .Create<Per_AssessmentScore>()
  2449. .And(x => x.YearMonth.Year == yearMonth_Dt.Year && x.YearMonth.Month == yearMonth_Dt.Month)
  2450. .And(x => ids.Contains(x.AssessmentContentSettingId))
  2451. .And(x => x.HigherUpConfig == 0)
  2452. .ToExpression();
  2453. if (IsLeader(dto.AssessmenUserId, dto.CreateUserId))
  2454. {
  2455. expressionWhere = Expressionable
  2456. .Create<Per_AssessmentScore>()
  2457. .And(x => x.YearMonth.Year == yearMonth_Dt.Year && x.YearMonth.Month == yearMonth_Dt.Month)
  2458. .And(x => ids.Contains(x.AssessmentContentSettingId))
  2459. .ToExpression();
  2460. }
  2461. _sqlSugar.BeginTran();
  2462. _sqlSugar.Updateable<Per_AssessmentScore>()
  2463. .Where(expressionWhere)
  2464. .SetColumns(x => new Per_AssessmentScore { IsDel = 1, DeleteUserId = dto.CreateUserId, DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") })
  2465. .ExecuteCommand();
  2466. var entityList = new List<Per_AssessmentScore>();
  2467. foreach (var x in dto.Data)
  2468. {
  2469. if (x.HigherUpAssessment > 100 || x.SelfAssessment > 100)
  2470. {
  2471. jw.Msg = QueryContent_DB[x.AssessmentContentSettingId].Name + "项分数不能超过100。";
  2472. return Ok(jw);
  2473. }
  2474. Per_AssessmentScore item = new Per_AssessmentScore
  2475. {
  2476. AssessmentContentSettingId = x.AssessmentContentSettingId,
  2477. CreateTime = DateTime.Now,
  2478. CreateUserId = dto.CreateUserId,
  2479. Details = QueryContent_DB[x.AssessmentContentSettingId].MergeStr,
  2480. HigherUpAssessment = x.HigherUpAssessment,
  2481. HigherUpUserId = x.LeadersId,
  2482. HigherUpConfig = x.HigherUpAssessment > 0 ? 1 : 0,
  2483. SelfAssessment = x.SelfAssessment,
  2484. IsDel = 0,
  2485. Status = x.Status,
  2486. YearMonth = yearMonth_Dt,
  2487. Score = x.SelfAssessment * 0.3M + x.HigherUpAssessment * 0.7M,
  2488. ScoreTotal = (x.SelfAssessment * 0.3M + x.HigherUpAssessment * 0.7M) * QueryContent_DB[x.AssessmentContentSettingId].AssessmentProportionChi,
  2489. };
  2490. entityList.Add(item);
  2491. }
  2492. var influenceRow = _sqlSugar.Insertable(entityList).ExecuteCommand();
  2493. _sqlSugar.CommitTran();
  2494. jw.Code = 200;
  2495. jw.Msg = "保存成功!";
  2496. jw.Data = $"{influenceRow}条数据操作成功!";
  2497. }
  2498. catch (Exception ex)
  2499. {
  2500. _sqlSugar.RollbackTran();
  2501. jw.Code = 500;
  2502. jw.Data = $"API ERROR ({ex.Message})";
  2503. }
  2504. }
  2505. return Ok(jw);
  2506. }
  2507. /// <summary>
  2508. /// 绩效项删除
  2509. /// </summary>
  2510. /// <param name="dto"></param>
  2511. /// <returns></returns>
  2512. [HttpPost]
  2513. public IActionResult DeleteAssessmentSetting(DeleteAssessmentSettingDto dto)
  2514. {
  2515. var jw = JsonView(false, "删除失败!");
  2516. if (!dto.IdArr.Any())
  2517. {
  2518. jw.Msg = "id不能为空!";
  2519. return Ok(jw);
  2520. }
  2521. var rowCount = _sqlSugar.Updateable<Per_AssessmentSetting>()
  2522. .Where(x => dto.IdArr.Contains(x.Id) && x.IsDel == 0)
  2523. .SetColumns(x => new Per_AssessmentSetting
  2524. {
  2525. IsDel = 1,
  2526. DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
  2527. DeleteUserId = dto.UserId,
  2528. })
  2529. .ExecuteCommand();
  2530. jw.Code = 200;
  2531. jw.Msg = $"修改成功!,修改数量{rowCount}";
  2532. return Ok(jw);
  2533. }
  2534. /// <summary>
  2535. /// 绩效内容删除
  2536. /// </summary>
  2537. /// <param name="dto"></param>
  2538. /// <returns></returns>
  2539. [HttpPost]
  2540. public IActionResult DeleteAssessmentContentSetting(DeleteAssessmentSettingDto dto)
  2541. {
  2542. var jw = JsonView(false, "删除失败!");
  2543. if (!dto.IdArr.Any())
  2544. {
  2545. jw.Msg = "id不能为空!";
  2546. return Ok(jw);
  2547. }
  2548. var rowCount = _sqlSugar.Updateable<Per_AssessmentContentSetting>()
  2549. .Where(x => dto.IdArr.Contains(x.Id) && x.IsDel == 0)
  2550. .SetColumns(x => new Per_AssessmentContentSetting
  2551. {
  2552. IsDel = 1,
  2553. DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
  2554. DeleteUserId = dto.UserId,
  2555. })
  2556. .ExecuteCommand();
  2557. jw.Code = 200;
  2558. jw.Msg = $"修改成功!,修改数量{rowCount}";
  2559. return Ok(jw);
  2560. }
  2561. private bool IsLeader(int userId, int higherUserId)
  2562. {
  2563. Dictionary<int, List<int>> keyValues = new Dictionary<int, List<int>>()
  2564. {
  2565. { 5 , new List<int>{ 258 , 235, 234, 233, 208 } }
  2566. };
  2567. if (keyValues.ContainsKey(higherUserId))
  2568. {
  2569. return keyValues[higherUserId].Contains(userId);
  2570. }
  2571. return false;
  2572. }
  2573. #endregion
  2574. #region 企微Api测试
  2575. [HttpPost]
  2576. public async Task<IActionResult> GetCheckin_MonthDataAsync(DateTime start, DateTime end)
  2577. {
  2578. var jw = JsonView(false);
  2579. jw.Data = await _qiYeWeChatApiService.GetCheckin_MonthDataAsync1(start, end);
  2580. return Ok(jw);
  2581. }
  2582. [HttpPost]
  2583. public async Task<IActionResult> QueryAssessmentByUser(QueryAssessmentByUser Dto)
  2584. {
  2585. var jw = JsonView(false);
  2586. var user_entity = _sqlSugar.Queryable<Sys_Users>()
  2587. .First(e => e.Id == Dto.UserId && e.IsDel == 0);
  2588. var start_Bool = DateTime.TryParse(Dto.Start, out DateTime start);
  2589. var end_Bool = DateTime.TryParse(Dto.End, out DateTime end);
  2590. if (!start_Bool || !end_Bool)
  2591. {
  2592. jw.Msg = "时间格式不正确!";
  2593. return Ok(jw);
  2594. }
  2595. jw.Msg = "用户企业微信Id未绑定!";
  2596. if (user_entity != null && !string.IsNullOrEmpty(user_entity.QiyeChatUserId))
  2597. {
  2598. var data = await _qiYeWeChatApiService.QueryAssessmentByUser(start, end, new List<string> { user_entity.QiyeChatUserId });
  2599. jw.Data = data;
  2600. jw.Msg = "查询成功!";
  2601. jw.Code = 200;
  2602. }
  2603. return Ok(jw);
  2604. }
  2605. //[HttpPost]
  2606. //public IActionResult TempTest(QueryAssessmentSettingListOffsetAsyncDto Dto)
  2607. //{
  2608. // var jw = JsonView(false);
  2609. // return Ok(jw);
  2610. //}
  2611. #endregion
  2612. #region Ai绩效分析
  2613. [HttpGet]
  2614. public async Task<IActionResult> AiPerformanceAnalysis_JobMarketingAsync
  2615. (int userId, DateTime start, DateTime end, int createUserId)
  2616. {
  2617. var jw = JsonView(false);
  2618. var user_entity = _sqlSugar.Queryable<Sys_Users>()
  2619. .First(e => e.Id == userId && e.IsDel == 0);
  2620. if (user_entity == null)
  2621. {
  2622. jw.Msg = "用户不存在!";
  2623. return Ok(jw);
  2624. }
  2625. List<string> useridlist = new List<string> { user_entity.QiyeChatUserId };
  2626. //获取企微外出打卡信息
  2627. var checkin_data = await _qiYeWeChatApiService.GetCheckinDataAsync(useridlist, 2, start, end);
  2628. if (checkin_data.errcode != 0)
  2629. {
  2630. jw.Msg = "获取企微外出打卡信息失败!" + checkin_data.errmsg;
  2631. return Ok(jw);
  2632. }
  2633. //获取企微外出申请信息
  2634. var approval_data = await _qiYeWeChatApiService.GetApprovalInfoUpdateAsync(start, end, newCursor: "", size: 100, filters: new List<IQiYeWeChatApiService.FilterCondition>(){
  2635. new
  2636. IQiYeWeChatApiService.FilterCondition{
  2637. key = "creator",
  2638. value = user_entity.QiyeChatUserId
  2639. },
  2640. new IQiYeWeChatApiService.FilterCondition{
  2641. key="record_type",
  2642. value="4"
  2643. }
  2644. });
  2645. if (approval_data.errcode != 0)
  2646. {
  2647. jw.Msg = "获取企微外出申请信息失败!" + approval_data.errmsg;
  2648. return Ok(jw);
  2649. }
  2650. List<ApprovalDetailView> detailViews = new List<ApprovalDetailView>();
  2651. foreach (var item in approval_data.sp_no_list)
  2652. {
  2653. var approval_detail = await _qiYeWeChatApiService.GetApprovalDetailAsync(item);
  2654. if (approval_detail.errcode != 0)
  2655. {
  2656. jw.Msg = "获取企微外出申请详情失败!" + approval_detail.errmsg;
  2657. return Ok(jw);
  2658. }
  2659. detailViews.Add(approval_detail);
  2660. }
  2661. string question = $"请根据以下数据分析用户绩效:";
  2662. question += $"外出打卡信息:{JsonConvert.SerializeObject(checkin_data.checkindata)}";
  2663. if (approval_data.sp_no_list.Count > 0)
  2664. {
  2665. question += $"外出申请信息:{JsonConvert.SerializeObject(detailViews)}";
  2666. }
  2667. question += $"请根据我提供的{user_entity.CnName}数据信息(提供的数据已经是一个月的数据),按照一个月拜访20个客户的标准判断是否合格,并给出分析报告。";
  2668. question += @"输出内容格式参考这个我下面提供的模板 “根据您提供的陈小龙2025年9月外出打卡数据,现进行绩效分析如下:\n\n### 一、基础数据统计\n**总打卡次数**:16次 \n**覆盖日期**:9月2日-9月29日(共28天) \n**有效工作日**:22天(扣除周末)\n\n### 二、客户拜访量分析\n1. **实际拜访客户数**:9个\n - 重庆商务职业学院(2次)\n - 重庆市南岸区商务委员会(2次)\n - 重庆市城投金卡信息产业(集团)股份有限公司(2次)\n - 玉马路\n - 重庆市南岸区人民政府外事办公室\n - 重庆经济技术开发区\n - 中共南岸区委党校\n - 重庆市南岸区社会主义学院教学楼\n - 重庆建筑工程职业学院(东站校区)\n - 中德职业教育西部中职示范基地\n - 重庆市璧山区人民政府\n\n2. **与标准对比**:\n - 目标拜访量:20个客户/月\n - 完成率:45%(9/20)\n - **结论:未达到合格标准**\n\n### 三、工作模式分析\n**优势**:\n1. 区域集中度较高:主要活跃在南岸区茶园片区(11次打卡)\n2. 重要客户重复拜访:3个重点客户有2次以上跟进记录\n3. 单日效率突出:9月26日完成4个点位拜访\n\n**待改进点**:\n1. 出勤稳定性不足:28天中仅16天有外出记录\n2. 单日拜访密度低:日均拜访0.57个客户\n3. 时间利用不均衡:多个工作日上午无外出记录\n\n### 四、改进建议\n1. **提升拜访频率**:\n - 建议将日均拜访量提升至1-1.5个客户\n - 合理安排行程,减少单点停留时间\n\n2. **优化区域规划**:\n - 继续保持南岸区的集中开发\n - 沙坪坝区(大学城)客户可集中安排单日拜访\n\n3. **加强过程管理**:\n - 建立每日拜访计划\n - 重要客户保持每月2-3次跟进频率\n\n### 五、综合评级:不合格\n按现行标准(20个客户/月),完成率仅45%。建议结合以下因素综合评估:\n- 客户质量(政府机构/职业院校占比高)\n- 单次拜访实效(需结合业务成果)\n- 区域开发难度\n\n是否需要调整考核标准或提供专项支持,建议直属领导进行面谈沟通。\n\n---\n**数据说明**:本分析仅基于打卡位置去重计算,实际客户数量可能需要结合业务系统数据进一步确认。”";
  2669. var settingTemp = await _sqlSugar.Queryable<Sys_SetData>().FirstAsync(x => x.Id == 1461 && x.IsDel == 0);
  2670. if (settingTemp != null && !string.IsNullOrEmpty(settingTemp.Remark))
  2671. {
  2672. var stringFormatResp = await GeneralMethod.StringFormatAsync(new StringFormatDto
  2673. {
  2674. FormatTemplate = settingTemp.Remark,
  2675. Parameters = new List<string> {
  2676. JsonConvert.SerializeObject(checkin_data.checkindata),
  2677. JsonConvert.SerializeObject(detailViews),
  2678. user_entity.CnName
  2679. }
  2680. });
  2681. if (stringFormatResp.Success)
  2682. {
  2683. question = stringFormatResp.FormattedResult;
  2684. }
  2685. }
  2686. try
  2687. {
  2688. var resp = await _deepSeekService.ChatAsync(question);
  2689. if (!resp.Success)
  2690. {
  2691. jw.Msg = "Ai分析用户绩效失败!" + resp.Message;
  2692. return Ok(jw);
  2693. }
  2694. //获取企微上下班考勤打卡信息
  2695. checkin_data = await _qiYeWeChatApiService.GetCheckinDataAsync(useridlist, 1, start, end);
  2696. if (checkin_data.errcode != 0)
  2697. {
  2698. jw.Msg = "获取企微上下班考勤打卡信息失败!" + checkin_data.errmsg;
  2699. return Ok(jw);
  2700. }
  2701. question = $"{JsonConvert.SerializeObject(checkin_data.checkindata)},请根据我提供的{user_entity.CnName}数据信息(提供的数据已经是一个月的数据),分析该员工日常考勤情况 ,工作日每天需要打卡俩次分别是早上9点和下午18点,"
  2702. + "输出内容标题不要带有表情或者符号。";
  2703. settingTemp = await _sqlSugar.Queryable<Sys_SetData>().FirstAsync(x => x.Id == 1462 && x.IsDel == 0);
  2704. if (settingTemp != null && !string.IsNullOrEmpty(settingTemp.Remark))
  2705. {
  2706. var stringFormatResp = await GeneralMethod.StringFormatAsync(new StringFormatDto
  2707. {
  2708. FormatTemplate = settingTemp.Remark,
  2709. Parameters = new List<string> {
  2710. JsonConvert.SerializeObject(checkin_data.checkindata),
  2711. user_entity.CnName
  2712. }
  2713. });
  2714. if (stringFormatResp.Success)
  2715. {
  2716. question = stringFormatResp.FormattedResult;
  2717. }
  2718. }
  2719. var kaoqinResp = await _deepSeekService.ChatAsync(question);
  2720. if (!resp.Success)
  2721. {
  2722. jw.Msg = "Ai分析用户考勤失败!" + resp.Message;
  2723. return Ok(jw);
  2724. }
  2725. jw.Data = new
  2726. {
  2727. // checkin_data = checkin_data.checkindata,
  2728. // approval_data = approval_data.sp_no_list,
  2729. // detailViews = detailViews,
  2730. Answer = resp.Answer,
  2731. kaoqinAnswer = kaoqinResp.Answer
  2732. };
  2733. //保存至数据库中
  2734. Pm_PerformanceAnalysis insertData = new Pm_PerformanceAnalysis
  2735. {
  2736. CreateTime = DateTime.Now,
  2737. CreateUserId = createUserId,
  2738. IsDel = 0,
  2739. Year = start.Year,
  2740. Month = start.Month,
  2741. JsonResult = JsonConvert.SerializeObject(jw.Data),
  2742. UserId = userId,
  2743. };
  2744. await _sqlSugar.Insertable(insertData).ExecuteCommandAsync();
  2745. }
  2746. catch (Exception ex)
  2747. {
  2748. jw.Msg = "Ai分析用户绩效失败!" + ex.Message;
  2749. return Ok(jw);
  2750. }
  2751. jw.Code = 200;
  2752. jw.Msg = "查询成功!";
  2753. return Ok(jw);
  2754. }
  2755. class wordTable
  2756. {
  2757. public int 序号 { get; set; }
  2758. public string 团组名 { get; set; }
  2759. public decimal 营业颔 { get; set; }
  2760. public string 出访日期 { get; set; }
  2761. public int 人数 { get; set; }
  2762. public string 收款日期 { get; set; }
  2763. };
  2764. [HttpPost]
  2765. public async Task<IActionResult> AiPerformanceAnalysis_JobMarketingFileDownAsync(int year, int month, int userId)
  2766. {
  2767. var jw = JsonView(false);
  2768. var user_entity = _sqlSugar.Queryable<Sys_Users>()
  2769. .First(e => e.Id == userId && e.IsDel == 0);
  2770. if (user_entity == null)
  2771. {
  2772. jw.Msg = "用户不存在!";
  2773. return Ok(jw);
  2774. }
  2775. var data = new Pm_PerformanceAnalysis();
  2776. if (year < 1 && month < 1)
  2777. {
  2778. data = await _sqlSugar.Queryable<Pm_PerformanceAnalysis>()
  2779. .Where(x => x.UserId == userId && x.IsDel == 0)
  2780. .OrderByDescending(x => x.CreateTime)
  2781. .FirstAsync();
  2782. }
  2783. else
  2784. {
  2785. data = await _sqlSugar.Queryable<Pm_PerformanceAnalysis>()
  2786. .Where(x => x.UserId == userId && x.Year == year && x.Month == month && x.IsDel == 0)
  2787. .FirstAsync();
  2788. }
  2789. if (data == null)
  2790. {
  2791. jw.Msg = "数据不存在!";
  2792. return Ok(jw);
  2793. }
  2794. var jsonResult = JObject.Parse(data.JsonResult);
  2795. var answer = jsonResult["Answer"]?.toString();
  2796. var kaoqinAnswer = jsonResult["kaoqinAnswer"]?.toString();
  2797. var tableapi = await this.AiPerformanceAnalysis_GroupStatisticsAsync(
  2798. userId,
  2799. new DateTime(data.Year, data.Month, 1),
  2800. new DateTime(data.Year, data.Month, 1).AddMonths(1)
  2801. );
  2802. var jwValue = (((tableapi as OkObjectResult).Value) as OASystem.Domain.ViewModels.JsonView);
  2803. if (jwValue.Code != 200)
  2804. {
  2805. jw.Msg = "获取团组统计数据失败!" + jwValue.Msg;
  2806. return Ok(jw);
  2807. }
  2808. var tableList = jwValue.Data as List<AiPerformanceAnalysis_GroupStatisticsView>;
  2809. if (tableList == null)
  2810. {
  2811. jw.Msg = "获取团组统计数据失败!";
  2812. return Ok(jw);
  2813. }
  2814. var tableListValue = tableList.Select(x => new wordTable
  2815. {
  2816. 序号 = x.RowNumber,
  2817. 团组名 = x.TeamName,
  2818. 营业颔 = x.GroupSales,
  2819. 出访日期 = x.VisitDate.ToString("yyyy-MM-dd"),
  2820. 人数 = x.VisitPNumber,
  2821. 收款日期 = x.CollectionDays.ToString("yyyy-MM-dd")
  2822. }).ToList();
  2823. var url = this.MarkdownToWord(new
  2824. List<WordContentItem>{
  2825. new
  2826. WordContentItem{
  2827. Type = WordContentType.Markdown,
  2828. MarkdownContent = answer
  2829. },
  2830. WordContentItem.FromObjectList(tableListValue, "团组统计")
  2831. ,
  2832. new
  2833. WordContentItem{
  2834. Type = WordContentType.Markdown,
  2835. MarkdownContent = kaoqinAnswer
  2836. }
  2837. }, $"{user_entity.CnName}_{data.Year}年{data.Month.ToString("00")}月绩效分析");
  2838. return Ok(new
  2839. {
  2840. url
  2841. });
  2842. }
  2843. /// <summary>
  2844. /// Word文档内容项类型
  2845. /// </summary>
  2846. public enum WordContentType
  2847. {
  2848. Markdown, // Markdown内容
  2849. Table // 表格内容
  2850. }
  2851. /// <summary>
  2852. /// Word文档内容项
  2853. /// </summary>
  2854. public class WordContentItem
  2855. {
  2856. /// <summary>
  2857. /// 内容类型
  2858. /// </summary>
  2859. public WordContentType Type { get; set; }
  2860. /// <summary>
  2861. /// Markdown内容(当Type为Markdown时使用)
  2862. /// </summary>
  2863. public string MarkdownContent { get; set; }
  2864. /// <summary>
  2865. /// 表格数据(当Type为Table时使用)- 第一行为表头
  2866. /// </summary>
  2867. public List<List<string>> TableData { get; set; }
  2868. /// <summary>
  2869. /// 表格标题(可选)
  2870. /// </summary>
  2871. public string TableTitle { get; set; }
  2872. /// <summary>
  2873. /// 从DataTable创建表格数据(便捷方法)
  2874. /// </summary>
  2875. /// <param name="dataTable">数据表</param>
  2876. /// <param name="tableTitle">表格标题(可选)</param>
  2877. /// <param name="includeHeader">是否包含表头(默认true)</param>
  2878. /// <returns>WordContentItem实例</returns>
  2879. public static WordContentItem FromDataTable(DataTable dataTable, string? tableTitle = null, bool includeHeader = true)
  2880. {
  2881. if (dataTable == null || dataTable.Rows.Count == 0)
  2882. {
  2883. return new WordContentItem
  2884. {
  2885. Type = WordContentType.Table,
  2886. TableTitle = tableTitle,
  2887. TableData = new List<List<string>>()
  2888. };
  2889. }
  2890. var tableData = new List<List<string>>();
  2891. // 添加表头
  2892. if (includeHeader)
  2893. {
  2894. var headerRow = new List<string>();
  2895. foreach (DataColumn column in dataTable.Columns)
  2896. {
  2897. headerRow.Add(column.ColumnName);
  2898. }
  2899. tableData.Add(headerRow);
  2900. }
  2901. // 添加数据行
  2902. foreach (DataRow row in dataTable.Rows)
  2903. {
  2904. var dataRow = new List<string>();
  2905. foreach (DataColumn column in dataTable.Columns)
  2906. {
  2907. dataRow.Add(row[column]?.ToString() ?? "");
  2908. }
  2909. tableData.Add(dataRow);
  2910. }
  2911. return new WordContentItem
  2912. {
  2913. Type = WordContentType.Table,
  2914. TableTitle = tableTitle,
  2915. TableData = tableData
  2916. };
  2917. }
  2918. /// <summary>
  2919. /// 从对象列表创建表格数据(便捷方法)
  2920. /// </summary>
  2921. /// <typeparam name="T">对象类型</typeparam>
  2922. /// <param name="items">对象列表</param>
  2923. /// <param name="tableTitle">表格标题(可选)</param>
  2924. /// <param name="columnMappings">列映射(属性名 -> 显示名称),如果为null则使用属性名</param>
  2925. /// <returns>WordContentItem实例</returns>
  2926. public static WordContentItem FromObjectList<T>(List<T> items, string? tableTitle = null, Dictionary<string, string>? columnMappings = null)
  2927. {
  2928. if (items == null || items.Count == 0)
  2929. {
  2930. return new WordContentItem
  2931. {
  2932. Type = WordContentType.Table,
  2933. TableTitle = tableTitle,
  2934. TableData = new List<List<string>>()
  2935. };
  2936. }
  2937. var tableData = new List<List<string>>();
  2938. var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
  2939. // 添加表头
  2940. var headerRow = new List<string>();
  2941. foreach (var prop in properties)
  2942. {
  2943. string headerName = columnMappings != null && columnMappings.ContainsKey(prop.Name)
  2944. ? columnMappings[prop.Name]
  2945. : prop.Name;
  2946. headerRow.Add(headerName);
  2947. }
  2948. tableData.Add(headerRow);
  2949. // 添加数据行
  2950. foreach (var item in items)
  2951. {
  2952. var dataRow = new List<string>();
  2953. foreach (var prop in properties)
  2954. {
  2955. var value = prop.GetValue(item);
  2956. dataRow.Add(value?.ToString() ?? "");
  2957. }
  2958. tableData.Add(dataRow);
  2959. }
  2960. return new WordContentItem
  2961. {
  2962. Type = WordContentType.Table,
  2963. TableTitle = tableTitle,
  2964. TableData = tableData
  2965. };
  2966. }
  2967. }
  2968. /// <summary>
  2969. /// 将多个Markdown内容和表格合并转换为Word文档
  2970. /// </summary>
  2971. /// <param name="contentItems">内容项列表(可以是Markdown或表格)</param>
  2972. /// <param name="fileName">文件名(不含扩展名)</param>
  2973. /// <returns>返回文件访问URL</returns>
  2974. private string MarkdownToWord(List<WordContentItem> contentItems, string fileName)
  2975. {
  2976. if (contentItems == null || contentItems.Count == 0)
  2977. {
  2978. throw new ArgumentException("内容项不能为空", nameof(contentItems));
  2979. }
  2980. // 创建新的Word文档
  2981. Aspose.Words.Document doc = new Aspose.Words.Document();
  2982. Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(doc);
  2983. // 设置默认字体
  2984. builder.Font.Name = "微软雅黑";
  2985. builder.Font.Size = 10.5;
  2986. // Markdown转换管道
  2987. var pipeline = new Markdig.MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
  2988. // 处理每个内容项
  2989. for (int i = 0; i < contentItems.Count; i++)
  2990. {
  2991. var item = contentItems[i];
  2992. // 如果是第一个内容项,先清理文档开头的空段落
  2993. if (i == 0)
  2994. {
  2995. // 清理文档开头的所有空段落
  2996. var firstBody = doc.FirstSection.Body;
  2997. while (firstBody.Paragraphs.Count > 0)
  2998. {
  2999. var firstPara = firstBody.Paragraphs[0];
  3000. if (string.IsNullOrWhiteSpace(firstPara.GetText().Trim()))
  3001. {
  3002. firstPara.Remove();
  3003. }
  3004. else
  3005. {
  3006. break;
  3007. }
  3008. }
  3009. }
  3010. else
  3011. {
  3012. // 如果不是第一个内容项,确保前一个段落没有过大的间距
  3013. builder.MoveToDocumentEnd();
  3014. var lastParagraph = doc.LastSection.Body.LastParagraph;
  3015. if (lastParagraph != null)
  3016. {
  3017. // 减少前一个段落的间距
  3018. lastParagraph.ParagraphFormat.SpaceAfter = 0;
  3019. lastParagraph.ParagraphFormat.SpaceBefore = 0;
  3020. }
  3021. // 不插入额外的段落分隔,直接追加内容
  3022. }
  3023. if (item.Type == WordContentType.Markdown)
  3024. {
  3025. // 处理Markdown内容
  3026. if (!string.IsNullOrWhiteSpace(item.MarkdownContent))
  3027. {
  3028. // 将Markdown转换为HTML
  3029. string htmlBody = Markdig.Markdown.ToHtml(item.MarkdownContent, pipeline);
  3030. // 包装成完整的HTML片段,减少body的margin和padding
  3031. string htmlContent = $@"<!DOCTYPE html>
  3032. <html>
  3033. <head>
  3034. <meta charset=""UTF-8"">
  3035. <meta http-equiv=""Content-Type"" content=""text/html; charset=UTF-8"">
  3036. <style>
  3037. body {{ font-family: '微软雅黑', 'Microsoft YaHei', SimSun, sans-serif; font-size: 10.5pt; line-height: 1.5; margin: 0; padding: 0; }}
  3038. h1, h2, h3, h4, h5, h6 {{ font-family: '微软雅黑', 'Microsoft YaHei', SimHei, sans-serif; margin-top: 12pt; margin-bottom: 6pt; }}
  3039. h1 {{ margin-top: 0; }}
  3040. p {{ margin: 0; padding: 0; }}
  3041. table {{ border-collapse: collapse; width: 100%; margin: 10px 0; }}
  3042. table th, table td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
  3043. table th {{ background-color: #f2f2f2; font-weight: bold; }}
  3044. code {{ font-family: 'Consolas', 'Courier New', monospace; }}
  3045. pre {{ background-color: #f5f5f5; padding: 10px; border-radius: 4px; margin: 6pt 0; }}
  3046. ul, ol {{ margin: 6pt 0; padding-left: 20pt; }}
  3047. li {{ margin: 3pt 0; }}
  3048. </style>
  3049. </head>
  3050. <body>
  3051. {htmlBody}
  3052. </body>
  3053. </html>";
  3054. // 使用LoadOptions指定UTF-8编码
  3055. var loadOptions = new Aspose.Words.LoadOptions
  3056. {
  3057. LoadFormat = Aspose.Words.LoadFormat.Html,
  3058. Encoding = System.Text.Encoding.UTF8
  3059. };
  3060. // 从HTML创建临时文档
  3061. byte[] htmlBytes = System.Text.Encoding.UTF8.GetBytes(htmlContent);
  3062. using (MemoryStream htmlStream = new MemoryStream(htmlBytes))
  3063. {
  3064. Aspose.Words.Document tempDoc = new Aspose.Words.Document(htmlStream, loadOptions);
  3065. if (i == 0)
  3066. {
  3067. // 第一个内容项:先清理所有空段落
  3068. var firstBody = doc.FirstSection.Body;
  3069. // 删除所有空段落
  3070. while (firstBody.Paragraphs.Count > 0)
  3071. {
  3072. var firstPara = firstBody.Paragraphs[0];
  3073. if (string.IsNullOrWhiteSpace(firstPara.GetText().Trim()))
  3074. {
  3075. firstPara.Remove();
  3076. }
  3077. else
  3078. {
  3079. break;
  3080. }
  3081. }
  3082. // 如果文档完全为空,直接替换整个文档内容
  3083. if (firstBody.Paragraphs.Count == 0)
  3084. {
  3085. // 清空原文档的所有内容
  3086. doc.FirstSection.Body.RemoveAllChildren();
  3087. // 将临时文档的所有内容节点复制到主文档
  3088. foreach (Aspose.Words.Node node in tempDoc.FirstSection.Body.ChildNodes.ToArray())
  3089. {
  3090. var importedNode = doc.ImportNode(node, true);
  3091. doc.FirstSection.Body.AppendChild(importedNode);
  3092. }
  3093. }
  3094. else
  3095. {
  3096. // 文档有内容,在第一个段落之前插入
  3097. var firstPara = firstBody.Paragraphs[0];
  3098. builder.MoveTo(firstPara);
  3099. builder.InsertDocument(tempDoc, Aspose.Words.ImportFormatMode.KeepSourceFormatting);
  3100. }
  3101. // 插入后再次清理开头的空段落,并统一格式
  3102. firstBody = doc.FirstSection.Body;
  3103. while (firstBody.Paragraphs.Count > 0)
  3104. {
  3105. var firstPara = firstBody.Paragraphs[0];
  3106. if (string.IsNullOrWhiteSpace(firstPara.GetText().Trim()))
  3107. {
  3108. firstPara.Remove();
  3109. }
  3110. else
  3111. {
  3112. // 找到第一个有内容的段落,确保它没有前间距
  3113. firstPara.ParagraphFormat.SpaceBefore = 0;
  3114. if (firstPara.ParagraphFormat.SpaceAfter > 6)
  3115. {
  3116. firstPara.ParagraphFormat.SpaceAfter = 6;
  3117. }
  3118. // 统一字体格式
  3119. foreach (Aspose.Words.Run run in firstPara.Runs)
  3120. {
  3121. if (string.IsNullOrEmpty(run.Font.Name) ||
  3122. (!run.Font.Name.Contains("微软") && !run.Font.Name.Contains("Microsoft") &&
  3123. !run.Font.Name.Contains("Sim") && !run.Font.Name.Contains("宋体")))
  3124. {
  3125. run.Font.Name = "微软雅黑";
  3126. }
  3127. if (firstPara.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading1 &&
  3128. firstPara.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading2 &&
  3129. firstPara.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading3 &&
  3130. firstPara.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading4 &&
  3131. (run.Font.Size == 0 || (run.Font.Size != 12 && run.Font.Size != 14 && run.Font.Size != 16 && run.Font.Size != 18 && run.Font.Size != 20 && run.Font.Size != 24)))
  3132. {
  3133. run.Font.Size = 10.5;
  3134. }
  3135. }
  3136. break;
  3137. }
  3138. }
  3139. // 统一处理第一个内容项的所有段落格式
  3140. foreach (Aspose.Words.Paragraph para in firstBody.Paragraphs)
  3141. {
  3142. if (string.IsNullOrWhiteSpace(para.GetText().Trim()))
  3143. {
  3144. continue;
  3145. }
  3146. // 统一段落格式
  3147. para.ParagraphFormat.SpaceBefore = 0;
  3148. if (para.ParagraphFormat.SpaceAfter > 6)
  3149. {
  3150. para.ParagraphFormat.SpaceAfter = 6;
  3151. }
  3152. // 统一字体格式 - 与非第一个内容项的处理逻辑完全一致
  3153. foreach (Aspose.Words.Run run in para.Runs)
  3154. {
  3155. // 统一字体名称 - 强制设置为微软雅黑
  3156. if (string.IsNullOrEmpty(run.Font.Name) ||
  3157. (!run.Font.Name.Contains("微软") && !run.Font.Name.Contains("Microsoft") &&
  3158. !run.Font.Name.Contains("Sim") && !run.Font.Name.Contains("宋体")))
  3159. {
  3160. run.Font.Name = "微软雅黑";
  3161. }
  3162. // 统一字体大小 - 与非第一个内容项的逻辑完全一致
  3163. bool isHeading = para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading1 ||
  3164. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading2 ||
  3165. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading3 ||
  3166. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading4;
  3167. if (!isHeading)
  3168. {
  3169. // 非标题:强制统一设置为10.5pt,确保与非第一个内容项一致
  3170. run.Font.Size = 10.5;
  3171. }
  3172. // 标题保持原有大小,但字体名称已在上面的逻辑中统一
  3173. }
  3174. }
  3175. }
  3176. else
  3177. {
  3178. // 非第一个内容项:记录追加前的段落数量
  3179. int paraCountBefore = doc.FirstSection.Body.Paragraphs.Count;
  3180. // 追加到文档末尾
  3181. doc.AppendDocument(tempDoc, Aspose.Words.ImportFormatMode.KeepSourceFormatting);
  3182. // 追加后立即清理格式,确保与第一个内容项格式一致
  3183. var appendedBody = doc.FirstSection.Body;
  3184. var allParagraphs = appendedBody.Paragraphs;
  3185. // 处理所有追加的段落(从paraCountBefore开始)
  3186. for (int paraIdx = paraCountBefore; paraIdx < allParagraphs.Count; paraIdx++)
  3187. {
  3188. var para = allParagraphs[paraIdx];
  3189. // 删除空段落
  3190. if (string.IsNullOrWhiteSpace(para.GetText().Trim()))
  3191. {
  3192. para.Remove();
  3193. paraIdx--; // 调整索引
  3194. continue;
  3195. }
  3196. // 统一段落格式:移除前间距,限制后间距
  3197. para.ParagraphFormat.SpaceBefore = 0;
  3198. if (para.ParagraphFormat.SpaceAfter > 6)
  3199. {
  3200. para.ParagraphFormat.SpaceAfter = 6;
  3201. }
  3202. // 统一字体格式 - 与第一个内容项的处理逻辑完全一致
  3203. foreach (Aspose.Words.Run run in para.Runs)
  3204. {
  3205. // 统一字体名称 - 强制设置为微软雅黑
  3206. if (string.IsNullOrEmpty(run.Font.Name) ||
  3207. (!run.Font.Name.Contains("微软") && !run.Font.Name.Contains("Microsoft") &&
  3208. !run.Font.Name.Contains("Sim") && !run.Font.Name.Contains("宋体")))
  3209. {
  3210. run.Font.Name = "微软雅黑";
  3211. }
  3212. // 统一字体大小 - 与第一个内容项的逻辑完全一致
  3213. bool isHeading = para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading1 ||
  3214. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading2 ||
  3215. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading3 ||
  3216. para.ParagraphFormat.StyleIdentifier == Aspose.Words.StyleIdentifier.Heading4;
  3217. if (!isHeading)
  3218. {
  3219. // 非标题:强制统一设置为10.5pt,确保与第一个内容项一致
  3220. run.Font.Size = 10.5;
  3221. }
  3222. // 标题保持原有大小,但字体名称已在上面的逻辑中统一
  3223. }
  3224. }
  3225. // 确保追加内容前的最后一个段落没有过大的后间距
  3226. if (paraCountBefore > 0 && paraCountBefore <= allParagraphs.Count)
  3227. {
  3228. var lastParaBefore = allParagraphs[paraCountBefore - 1];
  3229. if (lastParaBefore != null)
  3230. {
  3231. lastParaBefore.ParagraphFormat.SpaceAfter = 0;
  3232. }
  3233. }
  3234. }
  3235. }
  3236. // 移动builder到文档末尾
  3237. builder.MoveToDocumentEnd();
  3238. }
  3239. }
  3240. else if (item.Type == WordContentType.Table)
  3241. {
  3242. // 处理表格内容
  3243. if (item.TableData != null && item.TableData.Count > 0)
  3244. {
  3245. // 确保builder在正确位置
  3246. if (i == 0)
  3247. {
  3248. // 第一个内容项,确保在文档开头
  3249. builder.MoveToDocumentStart();
  3250. // 清理开头的空段落
  3251. var tableBody = doc.FirstSection.Body;
  3252. while (tableBody.Paragraphs.Count > 0)
  3253. {
  3254. var firstPara = tableBody.Paragraphs[0];
  3255. if (string.IsNullOrWhiteSpace(firstPara.GetText().Trim()))
  3256. {
  3257. firstPara.Remove();
  3258. }
  3259. else
  3260. {
  3261. break;
  3262. }
  3263. }
  3264. builder.MoveToDocumentStart();
  3265. }
  3266. else
  3267. {
  3268. builder.MoveToDocumentEnd();
  3269. }
  3270. // 添加表格标题(如果有)
  3271. if (!string.IsNullOrWhiteSpace(item.TableTitle))
  3272. {
  3273. builder.InsertBreak(Aspose.Words.BreakType.ParagraphBreak);
  3274. builder.InsertBreak(Aspose.Words.BreakType.ParagraphBreak);
  3275. builder.InsertBreak(Aspose.Words.BreakType.ParagraphBreak);
  3276. builder.ParagraphFormat.SpaceAfter = 6;
  3277. builder.ParagraphFormat.SpaceBefore = 0; // 表格标题前不添加间距
  3278. builder.Font.Size = 12;
  3279. builder.Font.Bold = true;
  3280. builder.Font.Name = "微软雅黑";
  3281. builder.Writeln(item.TableTitle);
  3282. builder.Font.Bold = false;
  3283. builder.Font.Size = 10.5;
  3284. builder.ParagraphFormat.SpaceAfter = 3; // 标题和表格之间的小间距
  3285. }
  3286. // 计算列数(取第一行的列数)
  3287. int columnCount = item.TableData[0]?.Count ?? 0;
  3288. if (columnCount == 0)
  3289. {
  3290. continue; // 跳过空表格
  3291. }
  3292. // 创建表格
  3293. Aspose.Words.Tables.Table table = builder.StartTable();
  3294. // 设置列宽(平均分配)- 在添加行之前设置
  3295. for (int colIndex = 0; colIndex < columnCount; colIndex++)
  3296. {
  3297. builder.CellFormat.PreferredWidth = Aspose.Words.Tables.PreferredWidth.FromPercent(100.0 / columnCount);
  3298. }
  3299. // 先添加表头(第一行),这样表格就不是空的了
  3300. if (item.TableData.Count > 0)
  3301. {
  3302. var headerRow = item.TableData[0];
  3303. foreach (var headerCell in headerRow)
  3304. {
  3305. builder.InsertCell();
  3306. builder.CellFormat.VerticalAlignment = Aspose.Words.Tables.CellVerticalAlignment.Center;
  3307. builder.CellFormat.Shading.BackgroundPatternColor = System.Drawing.Color.FromArgb(240, 240, 240);
  3308. builder.ParagraphFormat.Alignment = Aspose.Words.ParagraphAlignment.Center;
  3309. builder.Font.Bold = true;
  3310. builder.Font.Size = 10.5;
  3311. builder.Font.Name = "微软雅黑";
  3312. builder.Font.Color = System.Drawing.Color.Black;
  3313. builder.Write(headerCell ?? "");
  3314. builder.Font.Bold = false;
  3315. }
  3316. builder.EndRow();
  3317. }
  3318. // 现在表格有行了,可以设置表格样式
  3319. table.StyleIdentifier = Aspose.Words.StyleIdentifier.LightGridAccent1;
  3320. table.AllowAutoFit = true;
  3321. table.PreferredWidth = Aspose.Words.Tables.PreferredWidth.FromPercent(100);
  3322. table.Alignment = Aspose.Words.Tables.TableAlignment.Center;
  3323. // 添加数据行
  3324. for (int rowIndex = 1; rowIndex < item.TableData.Count; rowIndex++)
  3325. {
  3326. var row = item.TableData[rowIndex];
  3327. // 确保列数一致
  3328. while (row.Count < columnCount)
  3329. {
  3330. row.Add("");
  3331. }
  3332. foreach (var cell in row.Take(columnCount))
  3333. {
  3334. builder.InsertCell();
  3335. builder.CellFormat.VerticalAlignment = Aspose.Words.Tables.CellVerticalAlignment.Center;
  3336. builder.CellFormat.Shading.BackgroundPatternColor = System.Drawing.Color.White;
  3337. builder.ParagraphFormat.Alignment = Aspose.Words.ParagraphAlignment.Left;
  3338. builder.Font.Size = 10.5;
  3339. builder.Font.Name = "微软雅黑";
  3340. builder.Write(cell ?? "");
  3341. }
  3342. builder.EndRow();
  3343. }
  3344. builder.EndTable();
  3345. // 设置较小的段落间距
  3346. builder.ParagraphFormat.SpaceAfter = 6;
  3347. }
  3348. }
  3349. }
  3350. // 清理文档开头的空段落,避免第一段内容前出现空白页
  3351. var body = doc.FirstSection.Body;
  3352. var paragraphs = body.Paragraphs;
  3353. while (paragraphs.Count > 0)
  3354. {
  3355. var firstPara = paragraphs[0];
  3356. var paraText = firstPara.GetText().Trim();
  3357. // 如果第一个段落是空的或只包含空白字符,删除它
  3358. if (string.IsNullOrWhiteSpace(paraText))
  3359. {
  3360. firstPara.Remove();
  3361. }
  3362. else
  3363. {
  3364. // 找到第一个有内容的段落,确保它没有前间距
  3365. firstPara.ParagraphFormat.SpaceBefore = 0;
  3366. break;
  3367. }
  3368. }
  3369. // 遍历所有段落,确保字体设置正确,并统一段落间距
  3370. foreach (Aspose.Words.Paragraph paragraph in doc.GetChildNodes(Aspose.Words.NodeType.Paragraph, true))
  3371. {
  3372. // 统一段落间距,避免内容项之间出现大段空白
  3373. if (paragraph.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading1 &&
  3374. paragraph.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading2 &&
  3375. paragraph.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading3 &&
  3376. paragraph.ParagraphFormat.StyleIdentifier != Aspose.Words.StyleIdentifier.Heading4)
  3377. {
  3378. // 普通段落保持较小的间距
  3379. if (paragraph.ParagraphFormat.SpaceAfter > 6)
  3380. {
  3381. paragraph.ParagraphFormat.SpaceAfter = 6;
  3382. }
  3383. // 移除段落前的间距,避免内容项之间出现空白
  3384. if (paragraph.ParagraphFormat.SpaceBefore > 0)
  3385. {
  3386. paragraph.ParagraphFormat.SpaceBefore = 0;
  3387. }
  3388. }
  3389. foreach (Aspose.Words.Run run in paragraph.Runs)
  3390. {
  3391. // 如果字体不是中文字体,设置为微软雅黑
  3392. if (string.IsNullOrEmpty(run.Font.Name) ||
  3393. (!run.Font.Name.Contains("微软") && !run.Font.Name.Contains("Microsoft") &&
  3394. !run.Font.Name.Contains("Sim") && !run.Font.Name.Contains("宋体")))
  3395. {
  3396. run.Font.Name = "微软雅黑";
  3397. }
  3398. }
  3399. }
  3400. // 保存文件
  3401. string saveFolder = $"{AppSettingsHelper.Get("WordBasePath")}PerformanceAnalysis";
  3402. if (!Directory.Exists(saveFolder))
  3403. {
  3404. Directory.CreateDirectory(saveFolder);
  3405. }
  3406. string outputFile = $"{fileName}_{DateTime.Now:yyyyMMddHHmmss}.pdf";
  3407. string filePath = Path.Combine(saveFolder, outputFile);
  3408. doc.Save(filePath, Aspose.Words.SaveFormat.Pdf);
  3409. // 返回访问URL
  3410. return $"{AppSettingsHelper.Get("WordBaseUrl")}Office/Word/PerformanceAnalysis/{outputFile}";
  3411. }
  3412. [HttpGet]
  3413. public async Task<IActionResult> AiPerformanceAnalysis_QueryAsync(int year, int month, int userId)
  3414. {
  3415. if (userId < 1)
  3416. {
  3417. return Ok(JsonView(false, "请传入有效的userId参数!"));
  3418. }
  3419. var data = new Pm_PerformanceAnalysis();
  3420. if (year < 1 && month < 1)
  3421. {
  3422. data = await _sqlSugar.Queryable<Pm_PerformanceAnalysis>()
  3423. .Where(x => x.UserId == userId && x.IsDel == 0)
  3424. .OrderByDescending(x => x.CreateTime)
  3425. .FirstAsync();
  3426. }
  3427. else
  3428. {
  3429. data = await _sqlSugar.Queryable<Pm_PerformanceAnalysis>()
  3430. .Where(x => x.UserId == userId && x.Year == year && x.Month == month && x.IsDel == 0)
  3431. .OrderByDescending(x => x.CreateTime)
  3432. .FirstAsync();
  3433. }
  3434. var result = JObject.Parse(data.JsonResult);
  3435. return Ok(JsonView(true, "操作成功!", new
  3436. {
  3437. data.JsonResult,
  3438. data.Year,
  3439. data.Month,
  3440. data.Id,
  3441. data.CreateTime,
  3442. data = result
  3443. }));
  3444. }
  3445. /// <summary>
  3446. /// Ai绩效分析
  3447. /// 列表查询基础数据
  3448. /// </summary>
  3449. /// <returns></returns>
  3450. [HttpGet]
  3451. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  3452. public async Task<IActionResult> AiPerformanceAnalysis_InitAsync()
  3453. {
  3454. var companyDatas = await _sqlSugar.Queryable<Sys_Company>().Where(x => x.IsDel == 0).Select(x => new { x.Id, x.CompanyName }).ToListAsync();
  3455. var jobPostDatas = await _sqlSugar.Queryable<Sys_JobPost>().Where(x => x.IsDel == 0).Select(x => new { x.Id, x.CompanyId, x.JobName }).ToListAsync();
  3456. var userDatas = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0).Select(x => new { x.Id, x.CompanyId, x.JobPostId, x.CnName }).ToListAsync();
  3457. companyDatas.Insert(0, new { Id = 0, CompanyName = "全部" });
  3458. jobPostDatas.Insert(0, new { Id = 0, CompanyId = 0, JobName = "全部" });
  3459. userDatas.Insert(0, new { Id = 0, CompanyId = 0, JobPostId = 0, CnName = "全部" });
  3460. return Ok(JsonView(true, "操作成功!", new
  3461. {
  3462. companyDatas,
  3463. jobPostDatas,
  3464. userDatas
  3465. }));
  3466. }
  3467. /// <summary>
  3468. /// Ai绩效分析
  3469. /// 用户列表
  3470. /// </summary>
  3471. /// <returns></returns>
  3472. [HttpPost]
  3473. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  3474. public async Task<IActionResult> AiPerformanceAnalysis_UserListAsync(AiPerformanceAnalysis_UserListDto dto)
  3475. {
  3476. if (dto.PageIndex < 1)
  3477. {
  3478. dto.PageIndex = 1;
  3479. }
  3480. if (dto.PageSize < 1 || dto.PageSize > 100)
  3481. {
  3482. dto.PageSize = 10;
  3483. }
  3484. RefAsync<int> total = 0;
  3485. var notidsJson = _sqlSugar.Queryable<Sys_SetData>().First(x => x.Id == 1463 && x.IsDel == 0)?.Remark;
  3486. var notids = new List<int>();
  3487. if (!string.IsNullOrWhiteSpace(notidsJson))
  3488. {
  3489. try
  3490. {
  3491. notids = JsonConvert.DeserializeObject<List<int>>(notidsJson) ?? new List<int>();
  3492. }
  3493. catch
  3494. { }
  3495. }
  3496. var query = _sqlSugar.Queryable<Sys_Users>()
  3497. .LeftJoin<Sys_Company>((u, c) => u.CompanyId == c.Id)
  3498. .LeftJoin<Sys_Department>((u, c, d) => u.DepId == d.Id)
  3499. .LeftJoin<Sys_JobPost>((u, c, d, jp) => u.JobPostId == jp.Id)
  3500. .Where((u, c, d, jp) => u.IsDel == 0 && !notids.Contains(u.Id))
  3501. .WhereIF(!string.IsNullOrEmpty(dto.ScreeningCriteria?.Trim()), (u, c, d, jp) =>
  3502. u.CnName.Contains(dto.ScreeningCriteria.Trim()) ||
  3503. c.CompanyName.Contains(dto.ScreeningCriteria.Trim()) ||
  3504. d.DepName.Contains(dto.ScreeningCriteria.Trim()) ||
  3505. jp.JobName.Contains(dto.ScreeningCriteria.Trim()) ||
  3506. SqlFunc.ToString(u.Id).Contains(dto.ScreeningCriteria.Trim()))
  3507. .OrderBy(u => u.CompanyId)
  3508. .OrderBy(u => u.DepId)
  3509. .OrderBy(u => u.JobPostId)
  3510. .OrderBy(u => u.Id);
  3511. var view = await query.Select((u, c, d, jp) => new AiPerformanceAnalysis_UserView()
  3512. {
  3513. RowNumber = SqlFunc.RowNumber("u.CompanyId ASC, u.JobPostId ASC, u.Id ASC"),
  3514. Id = u.Id,
  3515. UserName = u.CnName,
  3516. Sex = u.Sex == 0 ? "男" : u.Sex == 1 ? "女" : "未设置",
  3517. EDate = u.Edate.ToString("yyyy-MM-dd"),
  3518. CompanyId = u.CompanyId,
  3519. CompanyName = c.CompanyName,
  3520. DepId = u.DepId,
  3521. DepName = d.DepName,
  3522. JobPostId = u.JobPostId,
  3523. JobName = jp.JobName,
  3524. WorkYears = SqlFunc.DateDiff(DateType.Year, u.Edate, DateTime.Now)
  3525. })
  3526. .ToPageListAsync(dto.PageIndex, dto.PageSize, total);
  3527. return Ok(JsonView(true, "操作成功!", view, total));
  3528. }
  3529. /// <summary>
  3530. /// Ai绩效分析
  3531. /// 团组统计
  3532. /// </summary>
  3533. /// <param name="userId">用户ID</param>
  3534. /// <param name="start">开始日期(eg:2025-01-01)</param>
  3535. /// <param name="end">结束日期(eg:2025-12-31)</param>
  3536. /// <returns></returns>
  3537. [HttpGet]
  3538. [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
  3539. public async Task<IActionResult> AiPerformanceAnalysis_GroupStatisticsAsync(int userId, DateTime start, DateTime end)
  3540. {
  3541. #region 参数验证
  3542. if (userId < 1)
  3543. {
  3544. return Ok(JsonView(false, "请传入有效UserId。"));
  3545. }
  3546. if (start > end)
  3547. {
  3548. return Ok(JsonView(false, "开始日期不能晚于结束日期。"));
  3549. }
  3550. #endregion
  3551. var parameters = new
  3552. {
  3553. UserId = userId,
  3554. StartDate = start.Date,
  3555. EndDate = end.Date.AddDays(1).AddSeconds(-1) // 包含结束日期的最后一秒
  3556. };
  3557. string sql = @"
  3558. SELECT
  3559. ROW_NUMBER() OVER (ORDER BY MonthNumber, CollectionDays) AS RowNumber,
  3560. Id,
  3561. TeamName,
  3562. ClientUnit,
  3563. ClientName,
  3564. VisitDate,
  3565. VisitPNumber,
  3566. JietuanOperator,
  3567. VisitEndDate,
  3568. MonthNumber,
  3569. GroupSales,
  3570. GroupPickupUser,
  3571. CollectionDays
  3572. FROM
  3573. (
  3574. SELECT
  3575. di.Id,
  3576. di.TeamName,
  3577. di.ClientUnit,
  3578. di.ClientName,
  3579. di.VisitDate,
  3580. di.VisitPNumber,
  3581. di.JietuanOperator,
  3582. di.VisitEndDate,
  3583. DATEPART(MONTH, di.VisitEndDate) AS MonthNumber,
  3584. (
  3585. SELECT CAST(COALESCE(SUM(ItemSumPrice * Rate), 0) AS DECIMAL(12, 2))
  3586. FROM Fin_ForeignReceivables
  3587. WHERE IsDel = 0
  3588. AND di.Id = Diid
  3589. AND AddingWay IN (0, 1, 2)
  3590. ) AS GroupSales,
  3591. u.CnName AS GroupPickupUser,
  3592. DATEADD(DAY, 7, di.VisitEndDate) AS CollectionDays
  3593. FROM Grp_DelegationInfo di WITH (NOLOCK)
  3594. LEFT JOIN Sys_Users u ON di.JietuanOperator = u.Id
  3595. WHERE di.Isdel = 0
  3596. AND di.IsBid = 0
  3597. AND di.JietuanOperator = @UserId
  3598. AND di.TeamName NOT LIKE '%投标%'
  3599. AND di.VisitDate BETWEEN @StartDate AND @EndDate
  3600. AND EXISTS (
  3601. SELECT 1
  3602. FROM Fin_ForeignReceivables fr
  3603. WHERE fr.IsDel = 0
  3604. AND fr.Diid = di.Id
  3605. AND fr.AddingWay IN (0, 1, 2)
  3606. )
  3607. ) Temp
  3608. ORDER BY MonthNumber, CollectionDays";
  3609. var groupData = await _sqlSugar.SqlQueryable<AiPerformanceAnalysis_GroupStatisticsView>(sql)
  3610. .AddParameters(parameters)
  3611. .ToListAsync();
  3612. return Ok(JsonView(true, "操作成功!", groupData, groupData?.Count ?? 0));
  3613. }
  3614. private class AiPerformanceAnalysis_GroupStatisticsView : MarketingSalesGroupList
  3615. {
  3616. /// <summary>
  3617. ///月份
  3618. /// </summary>
  3619. public int MonthNumber { get; set; }
  3620. }
  3621. /// <summary>
  3622. /// AI绩效分析用户列表视图模型
  3623. /// </summary>
  3624. private class AiPerformanceAnalysis_UserView
  3625. {
  3626. public int RowNumber { get; set; }
  3627. public int Id { get; set; }
  3628. public string UserName { get; set; }
  3629. public string Sex { get; set; }
  3630. public string EDate { get; set; }
  3631. public int CompanyId { get; set; }
  3632. public string CompanyName { get; set; }
  3633. public int DepId { get; set; }
  3634. public string DepName { get; set; }
  3635. public int JobPostId { get; set; }
  3636. public string JobName { get; set; }
  3637. public int WorkYears { get; set; }
  3638. }
  3639. #endregion
  3640. }
  3641. }